package org.jeecg.modules.quartz.job;


import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.app.service.IAppIsinService;
import org.jeecg.modules.quartz.utils.HolidayUtil;
import org.jeecg.modules.system.app.dto.TeachingDayDTO;
import org.jeecg.modules.system.app.entity.*;
import org.jeecg.modules.system.app.mapper.AppDeviceMapper;
import org.jeecg.modules.system.app.mapper.AppGmtInfoMapper;
import org.jeecg.modules.system.app.service.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.alibaba.dashscope.utils.JsonUtils.gson;
import static org.jeecg.modules.hikiot.HikiotTool.deleteExpiredVisitors;
import static org.jeecg.modules.hikiot.HikiotTool.queryOpenDoorRecord;

/**
 * @author wzq
 * @date 2025/7/15 10:28
 * @description
 */
@Slf4j
@AllArgsConstructor
@Component
public class OrTeachingJobService {

    private final IAppSitePriceRulesService appSitePriceRulesService;

    private final IAppTeachingTimeService appTeachingTimeService;

    private final IAppSitePlaceService appSitePlaceService;

    private final IAppSiteService appSiteService;

    private final IAppOrderProInfoService appOrderProInfoService;

    private final IAppOrderService appOrderService;

    private final IAppIsinService appIsinService;

    @Resource
    private AppDeviceMapper appDeviceMapper;

    @Resource
    private AppGmtInfoMapper appGmtInfoMapper;

    @Scheduled(cron = "0 0 0 1 12 *")
//    @Scheduled(cron = "0 01 11 * * ?")
    @Transactional(rollbackFor = Exception.class)
    public void execute() throws ParseException {
        log.info("开始执行定时任务");
        int year = DateUtils.getYear();
//        int year = 2025;
        Map<String, List<String>> HolidayMap = HolidayUtil.getYearHoliday(String.valueOf(year+1));
        // 设置开始日期和结束日期
        Date beginDate = DateUtils.str2Date((year + 1) + "-01-01 00:00:00", new SimpleDateFormat("yyyy-MM-dd"));
        Date endDate = DateUtils.str2Date((year + 2) + "-01-01 00:00:00", new SimpleDateFormat("yyyy-MM-dd"));
        // 获取开始日期和结束日期之间的所有日期
        List<Date> dateList = HolidayUtil.getDaysBetweenDates(beginDate, endDate);
        //部门、场地、教学日（teaching）、
        //1、查询所有的学校
        LambdaQueryWrapper<AppSite> wrapper = Wrappers.<AppSite>lambdaQuery().eq(AppSite::getType, 0).eq(AppSite::getStatus, 0);
        List<AppSite> appSiteList = appSiteService.list(wrapper);
        List<AppSitePriceRules> appSitePriceRulesList = new ArrayList<>();
        if(!appSiteList.isEmpty()){
            //教学日列表
            List<AppTeachingTime> appteachingList = new ArrayList<>();
            //2、遍历查询所有的学校
            for (AppSite site : appSiteList) {
                //根据学校查询场地
                AppSitePlace appSitePlace = appSitePlaceService.getOne(Wrappers.<AppSitePlace>lambdaQuery().eq(AppSitePlace::getOrgCode, site.getOrgCode()));
                // 遍历生成一对多教学时段
                for (Date localDate : dateList) {
                    AppTeachingTime appTeachingTime = new AppTeachingTime();
                    appTeachingTime
                            .setTenantId(site.getTenantId())
                            //localDate 转 Date
                            .setDay(localDate)
                            .setOrgCode(site.getOrgCode());
                    //格式‘yyyy-MM-dd’
                    String yearHoliday = null;
                    try {
                        List<String> holiday = HolidayMap.get("holiday");
                        List<String> extraWorkDay = HolidayMap.get("extraWorkDay");
                        yearHoliday = HolidayUtil.isWorkingDay(DateUtils.formatDate(localDate, "yyyy-MM-dd"),holiday,extraWorkDay);
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
                    if("0".equals(yearHoliday)){
                        log.info("是教学日");
                        appTeachingTime.setIsTeaching(0);
                    }else{
                        log.info("非教学日");
                        appTeachingTime.setIsTeaching(1);
                    }
                    //添加到集合中
                    appteachingList.add(appTeachingTime);
                    //如果开放时段列表不为空(教学日/非教学日)，根据开放时段批量存储，开放时段记录
                    if (StringUtils.isNotEmpty(site.getTeachingDay()) && appTeachingTime.getIsTeaching() == 0){
                        JSONObject jsonObject = JSONObject.parseObject(site.getTeachingDay());
                        List<TeachingDayDTO> data = jsonObject.getJSONArray("data").toJavaList(TeachingDayDTO.class);
                        data.forEach(item -> {
                            String startTime = item.getStartTime();
                            String endTime = item.getEndTime();
                            Integer ticketNum = Integer.valueOf(item.getTicketNum());
                            AppSitePriceRules appSitePriceRules = new AppSitePriceRules();
                            appSitePriceRules
                                    .setOrgCode(site.getOrgCode())
                                    .setTenantId(site.getTenantId())
                                    .setSitePlaceId(appSitePlace.getId())
                                    .setType(0)
                                    .setTicketNum(ticketNum)
                                    .setDateOfSale(localDate)
                                    .setStartTime(DateUtils.str2Date(startTime, new SimpleDateFormat("HH:mm")))
                                    .setEndTime(DateUtils.str2Date(endTime, new SimpleDateFormat("HH:mm")))
                                    .setDayOfWeek(HolidayUtil.getWeekOfDate(localDate))
                                    .setTicketNum(Integer.valueOf(item.getTicketNum()))
                                    .setIsTeaching(appTeachingTime.getIsTeaching())
                                    .setCategoryId(site.getCategoryId())
                                    .setCreateBy("admin")
                                    .setStatus(CommonConstant.STATUS_NORMAL)
                                    .setDelFlag(CommonConstant.STATUS_NORMAL)
                            ;
                            appSitePriceRulesList.add(appSitePriceRules);
                        });
                    }
                    if (ObjectUtils.isNotEmpty(site.getNoTeachingDay())&& appTeachingTime.getIsTeaching() == 1){
                        List<TeachingDayDTO> data = JSONObject.parseObject(site.getNoTeachingDay()).getJSONArray("data").toJavaList(TeachingDayDTO.class);
                        data.forEach(item -> {
                            String startTime = item.getStartTime();
                            String endTime = item.getEndTime();
                            Integer ticketNum = Integer.valueOf(item.getTicketNum());
                            AppSitePriceRules appSitePriceRules = new AppSitePriceRules();
                            appSitePriceRules
                                    .setOrgCode(site.getOrgCode())
                                    .setTenantId(site.getTenantId())
                                    .setSitePlaceId(appSitePlace.getId())
                                    .setType(0)
                                    .setTicketNum(ticketNum)
                                    .setDateOfSale(localDate)
                                    .setStartTime(DateUtils.str2Date(startTime, new SimpleDateFormat("HH:mm")))
                                    .setEndTime(DateUtils.str2Date(endTime, new SimpleDateFormat("HH:mm")))
                                    .setDayOfWeek(HolidayUtil.getWeekOfDate(localDate))
                                    .setTicketNum(Integer.valueOf(item.getTicketNum()))
                                    .setIsTeaching(appTeachingTime.getIsTeaching())
                                    .setCategoryId(site.getCategoryId())
                                    .setCreateBy("admin")
                                    .setStatus(CommonConstant.STATUS_NORMAL)
                                    .setDelFlag(CommonConstant.STATUS_NORMAL)
                            ;
                            appSitePriceRulesList.add(appSitePriceRules);
                        });
                    }
                }
            }
            //存放集合
            appTeachingTimeService.saveBatch(appteachingList);
            //存放开放时段列表
            appSitePriceRulesService.saveBatch(appSitePriceRulesList);
        }
    }

    /**
     * @Author SheepHy
     * @Description 删除过期用户
     * @Date 17:43 2025/9/1
     * @Param
     * @return
     **/
    @Scheduled(cron = "0 0 1 * * ?")
    public void deleteExpiredVisitorsExecute(){
        try {
            // 获取所有设备列表
            List<AppDevice> deviceList = appDeviceMapper.selectList(null);
            if (deviceList == null || deviceList.isEmpty()) {
                log.warn("未找到需要处理的设备");
                return;
            }

            // 定义休眠时间（毫秒）
            final long SLEEP_TIME = 3000; // 5秒，可根据实际情况调整

            // 遍历设备处理
            for (AppDevice device : deviceList) {
                try {
                    String deviceSerial = device.getDeviceSerial();
                    log.info("开始处理设备：{}", deviceSerial);

                    // 执行删除操作
                    String result = deleteExpiredVisitors(deviceSerial);
                    log.info("设备 {} 处理完成，结果：{}", deviceSerial, result);

                    // 最后一次处理后不休眠
                    if (!device.equals(deviceList.get(deviceList.size() - 1))) {
                        log.info("休眠 {} 毫秒...", SLEEP_TIME);
                        Thread.sleep(SLEEP_TIME);
                    }
                } catch (InterruptedException e) {
                    // 恢复中断状态
                    Thread.currentThread().interrupt();
                    log.error("设备 {} 处理过程中发生中断异常", device.getDeviceSerial(), e);
                    break; // 中断后停止处理
                } catch (Exception e) {
                    log.error("设备 {} 处理失败", device.getDeviceSerial(), e);
                    // 记录失败设备信息
                    continue; // 继续处理其他设备
                }
            }
        } catch (Exception e) {
            log.error("获取设备列表失败", e);
        }
    }

    /**
     * @Author SheepHy
     * @Description 同步开关门记录
     * @Date 17:44 2025/9/1
     * @Param
     * @return
     **/
    //todo
    @Scheduled(fixedDelay = 600000)
//    @Scheduled(cron = "0 0 23 * * ?")
    public void synchronousDoorOpeningAndClosingRecords(){
        try {
            List<DoorRecordDTO> allRecords = fetchAllDoorRecords();
            for (DoorRecordDTO data : allRecords) {
                if(null == appGmtInfoMapper.selectOne(Wrappers.<AppGmtInfo>lambdaQuery().eq(AppGmtInfo::getOriginId, data.getOriginId()).last("LIMIT 1"))){
                    AppDevice appDevice = appDeviceMapper.selectOne(Wrappers.<AppDevice>lambdaQuery().eq(AppDevice::getDeviceSerial, data.getDeviceSerial().split("-")[0]));
                    if(null == appDevice){
                        log.error("未找到设备：{}", data.getDeviceSerial());
                        continue;
                    }
                    String siteId = appDevice.getSiteId();
                    appGmtInfoMapper.insert(new AppGmtInfo()
                            .setFamilyId(data.getEmployeeNo())
                            .setSiteId(siteId)
                            .setAuthResultMsg(data.getAuthResultMsg())
                            .setGmtCreate(DateUtils.str2Date(data.getGmtCreate(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")))
                            .setPicUrl(data.getPicUrl())
                            .setSecMsgCode(data.getSecMsgCode())
                            .setOriginId(data.getOriginId())
                            .setDeviceSerial(data.getDeviceSerial().split("-")[0])
                            .setCreateTime(new Date())
                            .setUpdateTime(new Date())
                            .setDeviceSerialNo(data.getDeviceSerial()));
                    //查询相关日期学校子订单
                    // 定义格式化模板
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

                    // 格式化输出
                    Date date = DateUtils.str2Date(data.getGmtCreate(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
                    String formattedDate = sdf.format(date);

                    List<AppOrderProInfo> orderProInfoList = appOrderProInfoService.list(Wrappers.lambdaQuery(AppOrderProInfo.class)
                            .eq(AppOrderProInfo::getUseDateStr, formattedDate)
                            .eq(AppOrderProInfo::getFamilyUserId, data.getEmployeeNo())
                            .eq(AppOrderProInfo::getSiteId, siteId)
                            .eq(AppOrderProInfo::getType, CommonConstant.ORDER_PRO_INFO_TYPE_0)
                    );
                    //修改订单状态
                    for (AppOrderProInfo appOrderProInfo : orderProInfoList) {
                        if (appOrderProInfo.getOrderStatus() == 1){
                            appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_2);
                            appOrderProInfoService.updateById(appOrderProInfo);
                            //修改券使用记录状态
                            appIsinService.update(Wrappers.lambdaUpdate(AppIsin.class).eq(AppIsin::getOrderProInfoId, appOrderProInfo.getId())
                                    .set(AppIsin::getIsinStatus, CommonConstant.ISIN_STATUS_1)
                                    .set(AppIsin::getUseImage,data.getPicUrl())
                                    .set(AppIsin::getUseTime,DateUtils.str2Date(data.getGmtCreate(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")))
                            );
                            //修改订单状态
                            String orderId = appOrderProInfo.getOrderId();
                            List<AppOrderProInfo> proInfos = appOrderProInfoService.list(Wrappers.lambdaQuery(AppOrderProInfo.class).eq(AppOrderProInfo::getOrderId, orderId));
                            if(proInfos.size() == proInfos.stream().filter(ap -> ap.getOrderStatus() > 1).count()){
                                AppOrder appOrder = appOrderService.getById(orderId);
                                appOrder.setOrderStatus(CommonConstant.ORDER_STATUS_2);
                                appOrderService.updateById(appOrder);
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            log.error("处理门禁记录失败", e);
        }
    }

    /**
     * 分页获取所有门禁记录
     */
    private List<DoorRecordDTO> fetchAllDoorRecords() {
        List<DoorRecordDTO> allRecords = new ArrayList<>();
        int pageNum = 1;
        int pageSize = 100;
        AppGmtInfo appGmtInfo = appGmtInfoMapper.selectOne(Wrappers.<AppGmtInfo>lambdaQuery()
                .orderByDesc(AppGmtInfo::getGmtCreate)
                .last("limit 1"));
        try {
            while (true) {
                JSONObject response;
                if(null != appGmtInfo && null != appGmtInfo.getGmtCreate()){
                    response = gson.fromJson(queryOpenDoorRecord(pageNum, pageSize, appGmtInfo.getGmtCreate()), JSONObject.class);
                }else {
                    response = gson.fromJson(queryOpenDoorRecord(pageNum, pageSize,null), JSONObject.class);
                }

                // 验证响应有效性
                if (!isValidResponse(response)) {
                    log.warn("无效的响应数据，停止获取");
                    break;
                }
                // 提取当前页数据
                JSONArray dataList = response.getJSONArray("data");
                List<DoorRecordDTO> currentRecords = JSON.parseArray(
                        dataList.toJSONString(),
                        DoorRecordDTO.class
                );
                allRecords.addAll(currentRecords);

                // 分页判断
                int totalCount = response.getIntValue("count");
                if (pageNum * pageSize >= totalCount) {
                    break;
                }
                pageNum++;
            }

        } catch (Exception e) {
            log.error("分页获取门禁记录失败", e);
        }

        return allRecords;
    }

    /**
     * 验证响应是否有效
     */
    private boolean isValidResponse(JSONObject response) {
        if (response == null) return false;
        if (response.getIntValue("code") != 0) return false;
        return response.containsKey("data");
    }

    /**
     * DTO类 - 原始门禁记录
     */
    @Data
    private static class DoorRecordDTO {
        private String employeeNo;
        private String authResultMsg;
        private String gmtCreate;
        private String picUrl;
        private String secMsgCode;
        private String originId;
        private String deviceSerial;
    }

}