package com.aucma.dms.service.impl;


import com.aucma.common.core.domain.model.LoginUser;
import com.aucma.common.utils.DateUtils;
import com.aucma.common.utils.SecurityUtils;
import com.aucma.common.utils.StringUtils;
import com.aucma.common.utils.uuid.Seq;
import com.aucma.dms.domain.DmsPlanMaint;
import com.aucma.dms.domain.DmsPlanMaintDetail;
import com.aucma.dms.mapper.DmsPlanMaintMapper;
import com.aucma.dms.service.IDmsBillsMaintInstanceService;
import com.aucma.dms.service.IDmsPlanMaintService;
import com.aucma.quartz.util.CronUtils;
import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 保养计划信息Service业务层处理
 *
 * @author xins
 * @date 2024-01-08
 */
@Service
public class DmsPlanMaintServiceImpl implements IDmsPlanMaintService {
    
    private static final Logger log = LoggerFactory.getLogger(DmsPlanMaintServiceImpl.class);
    
    @Autowired
    private DmsPlanMaintMapper dmsPlanMaintMapper;

    @Autowired
    private IDmsBillsMaintInstanceService dmsBillsMaintInstanceService;

/*    @Autowired
    private RemoteJobService remoteJobService;*/

    /**
     * 查询保养计划信息
     *
     * @param planMaintId 保养计划信息主键
     * @return 保养计划信息
     */
    @Override
    public DmsPlanMaint selectDmsPlanMaintByPlanMaintId(Long planMaintId) {
        DmsPlanMaint dmsPlanMaint = dmsPlanMaintMapper.selectPlanMaintJoinJobByPlanMaintId(planMaintId);

        Long timeLimit = dmsPlanMaint.getTimeLimit();
        if (timeLimit != null) {
            Long days = timeLimit / (24 * 60 * 60l);
            Long hours = timeLimit % (24 * 60 * 60l);
//            System.out.println(days);
//            System.out.println(hours);
            dmsPlanMaint.setTimeLimitDays(days);
            dmsPlanMaint.setTimeLimitHours(hours / (60 * 60l));
        }
        return dmsPlanMaint;
    }

    /**
     * 查询保养计划信息列表
     *
     * @param dmsPlanMaint 保养计划信息
     * @return 保养计划信息
     */
    @Override
    public List<DmsPlanMaint> selectDmsPlanMaintList(DmsPlanMaint dmsPlanMaint) {

        List<DmsPlanMaint> dmsPlanMaints = dmsPlanMaintMapper.selectDmsPlanMaintList(dmsPlanMaint);
        for (DmsPlanMaint d : dmsPlanMaints) {
            Long timeLimit = d.getTimeLimit();
            d.setTimeLimitDays(timeLimit / (24 * 60 * 60L));
            d.setTimeLimitHours((timeLimit % (24 * 60 * 60L)) / (60 * 60l));
        }

        return dmsPlanMaints;
    }

    /**
     * 新增保养计划信息
     *
     * @param dmsPlanMaint 保养计划信息
     * @return 结果
     */
    @Transactional
    @Override
    public int insertDmsPlanMaint(DmsPlanMaint dmsPlanMaint) {
        String day = "*";
        String month = "*";
        String week = "*";
        String year = "*";
        String cron = "";
        if (dmsPlanMaint.getDay()!=null){
            day = dmsPlanMaint.getDay().toString();
        }
        if (dmsPlanMaint.getMonth()!=null){
            month = dmsPlanMaint.getMonth().toString();
        }
        if (dmsPlanMaint.getWeek()!=null){
            Long weekDay = dmsPlanMaint.getWeek() + 1;
            week = weekDay.toString();
        }
        if (dmsPlanMaint.getYear()!=null){
            year = dmsPlanMaint.getYear().toString();
        }
        if (dmsPlanMaint.getMaintLevel().equals(1l)){
            cron = "0 0 "+dmsPlanMaint.getHour()+" "+day+" "+month+" ?";
        }
        if (dmsPlanMaint.getMaintLevel().equals(2l)){
            cron = "0 0 "+dmsPlanMaint.getHour()+" ?"+" "+month+" "+week;
        }
        if (dmsPlanMaint.getMaintLevel().equals(3l)){
            cron = "0 0 "+dmsPlanMaint.getHour()+" "+day+" "+ month+" ? "+year;
        }
        String planMaintCode = Seq.getId(Seq.planMaintSeqType, Seq.planMaintCode);
//        String cron = "* * "+dmsPlanMaint.getHour()+" ? * "+week;
/*        SysJob job = new SysJob();
        job.setJobName("保养计划编号" + planMaintCode + "工单任务");
        job.setJobGroup("DEFAULT");
        job.setInvokeTarget("ryTask.getDmsBillsMaint(\"" + planMaintCode + "\")");
        job.setCronExpression(cron);
        job.setMisfirePolicy("1");
        job.setConcurrent("1");
        job.setStatus("1");
        R<Integer> jobIdR = remoteJobService.add(SecurityConstants.INNER, job);*/

        String time = cron;
        //通过cron表达式获取下一次执行时间
        Date nextExecution = CronUtils.getNextExecution(time);
        dmsPlanMaint.setMaintTime(nextExecution);
        dmsPlanMaint.setCronExpression(cron);
//        dmsPlanMaint.setJobId(jobIdR.getData().longValue());
        dmsPlanMaint.setPlanMaintCode(planMaintCode);
        Long timeLimitDays = dmsPlanMaint.getTimeLimitDays()==null?0L:dmsPlanMaint.getTimeLimitDays();
        Long timeLimitHours = dmsPlanMaint.getTimeLimitHours() == null?0L:dmsPlanMaint.getTimeLimitHours();
        dmsPlanMaint.setTimeLimit((timeLimitDays * 24 * 60 * 60)
                + (timeLimitHours * 60 * 60));
        // 设置默认值：IS_FLAG 为 null 时默认为 0
        if (dmsPlanMaint.getIsFlag() == null) {
            dmsPlanMaint.setIsFlag(0L);
        }
        dmsPlanMaint.setCreateBy(SecurityUtils.getLoginUser()==null ? SecurityUtils.getUserId() :SecurityUtils.getLoginUser().getUser().getUserId());
        dmsPlanMaint.setCreateTime(DateUtils.getNowDate());
        int rows = dmsPlanMaintMapper.insertDmsPlanMaint(dmsPlanMaint);

        return rows;
    }

    /**
     * 修改保养计划信息
     *
     * @param dmsPlanMaint 保养计划信息
     * @return 结果
     */
    @Transactional
    @Override
    public int updateDmsPlanMaint(DmsPlanMaint dmsPlanMaint) {
        Long jobId = dmsPlanMaint.getJobId();
        String cronExpression = dmsPlanMaint.getCronExpression();
/*        if(StringUtils.isNotEmpty(cronExpression)){
            if (jobId == null) {
                String planMaintCode = dmsPlanMaint.getPlanMaintCode();
                SysJob job = new SysJob();
                job.setJobName("保养计划编号" + planMaintCode + "工单任务");
                job.setJobGroup("DEFAULT");
                job.setInvokeTarget("ryTask.getDmsBillsMaint(\"" + planMaintCode + "\")");
                job.setCronExpression(dmsPlanMaint.getCronExpression());
                job.setMisfirePolicy("1");
                job.setConcurrent("1");
                job.setStatus("1");
                R<Integer> jobIdR = remoteJobService.add(SecurityConstants.INNER, job);
                dmsPlanMaint.setJobId(jobIdR.getData().longValue());
            } else {
*//*                SysJob sysJob = remoteJobService.getJobInfo(jobId, SecurityConstants.INNER);
                if (sysJob != null) {
                    sysJob.setCronExpression(dmsPlanMaint.getCronExpression());
                    remoteJobService.update(SecurityConstants.INNER, sysJob);
                }*//*
            }
        }*/

        // 根据保养级别和周期字段重新构建cron表达式
        String day = "*";
        String month = "*";
        String week = "*";
        String year = "*";
        String cron = "";
        if (dmsPlanMaint.getDay()!=null){
            day = dmsPlanMaint.getDay().toString();
        }
        if (dmsPlanMaint.getMonth()!=null){
            month = dmsPlanMaint.getMonth().toString();
        }
        if (dmsPlanMaint.getWeek()!=null){
            Long weekDay = dmsPlanMaint.getWeek() + 1;
            week = weekDay.toString();
        }
        if (dmsPlanMaint.getYear()!=null){
            year = dmsPlanMaint.getYear().toString();
        }
        if (dmsPlanMaint.getMaintLevel().equals(1l)){
            cron = "0 0 "+dmsPlanMaint.getHour()+" "+day+" "+month+" ?";
        }
        if (dmsPlanMaint.getMaintLevel().equals(2l)){
            cron = "0 0 "+dmsPlanMaint.getHour()+" ?"+" "+month+" "+week;
        }
        if (dmsPlanMaint.getMaintLevel().equals(3l)){
            cron = "0 0 "+dmsPlanMaint.getHour()+" "+day+" "+ month+" ? "+year;
        }

        String time = cron;
        //通过cron表达式获取下一次执行时间
        Date nextExecution = CronUtils.getNextExecution(time);
        dmsPlanMaint.setMaintTime(nextExecution);
        dmsPlanMaint.setCronExpression(cron);
        Long timeLimitDays = dmsPlanMaint.getTimeLimitDays()==null?0L:dmsPlanMaint.getTimeLimitDays();
        Long timeLimitHours = dmsPlanMaint.getTimeLimitHours() == null?0L:dmsPlanMaint.getTimeLimitHours();
        dmsPlanMaint.setTimeLimit((timeLimitDays * 24 * 60 * 60)
                + (timeLimitHours * 60 * 60));
        dmsPlanMaint.setUpdateBy(SecurityUtils.getLoginUser()==null ? SecurityUtils.getUserId() :SecurityUtils.getLoginUser().getUser().getUserId());
        dmsPlanMaint.setUpdateTime(DateUtils.getNowDate());
        return dmsPlanMaintMapper.updateDmsPlanMaint(dmsPlanMaint);
    }

    /**
     * 批量删除保养计划信息
     *
     * @param planMaintIds 需要删除的保养计划信息主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteDmsPlanMaintByPlanMaintIds(Long[] planMaintIds) {
        int planMaintLength = planMaintIds.length;
        Long[] jobIds = new Long[planMaintLength];
        for (int i = 0; i < planMaintIds.length; i++) {
            Long planMaintId = planMaintIds[i];
            DmsPlanMaint dmsPlanMaint = dmsPlanMaintMapper.selectDmsPlanMaintByPlanMaintId(planMaintId);
            jobIds[i] = dmsPlanMaint.getJobId();
        }

//        remoteJobService.remove(SecurityConstants.INNER, jobIds);

        return dmsPlanMaintMapper.deleteDmsPlanMaintByPlanMaintIds(planMaintIds);
    }

    /**
     * 删除保养计划信息信息
     *
     * @param planMaintId 保养计划信息主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteDmsPlanMaintByPlanMaintId(Long planMaintId) {
        dmsPlanMaintMapper.deleteDmsPlanMaintDetailByPlanMaintId(planMaintId);
        return dmsPlanMaintMapper.deleteDmsPlanMaintByPlanMaintId(planMaintId);
    }

    /**
     * 新增保养计划明细信息
     *
     * @param dmsPlanMaint 保养计划信息对象
     */
    public void insertDmsPlanMaintDetail(DmsPlanMaint dmsPlanMaint) {
        List<DmsPlanMaintDetail> dmsPlanMaintDetailList = dmsPlanMaint.getDmsPlanMaintDetailList();
        Long planMaintId = dmsPlanMaint.getPlanMaintId();

        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNotNull(dmsPlanMaintDetailList)) {
            List<DmsPlanMaintDetail> list = new ArrayList<DmsPlanMaintDetail>();
            for (DmsPlanMaintDetail dmsPlanMaintDetail : dmsPlanMaintDetailList) {
                dmsPlanMaintDetail.setIsFlag(1l);
                dmsPlanMaintDetail.setCreateBy(loginUser.getUserId());
                dmsPlanMaintDetail.setPlanMaintId(planMaintId);
                list.add(dmsPlanMaintDetail);
            }
            if (list.size() > 0) {
                dmsPlanMaintMapper.batchDmsPlanMaintDetail(list);
            }
        }
    }


    /**
     * 查询保养计划信息 Join detail
     *
     * @param planMaintCode 保养计划信息Code
     * @return 保养计划信息
     */
    @Override
    public DmsPlanMaint selectDmsPlanMaintJoinByPlanMaintCode(String planMaintCode) {
        DmsPlanMaint dmsPlanMaint = dmsPlanMaintMapper.selectDmsPlanMaintJoinByPlanMaintCode(planMaintCode);

        Long timeLimit = dmsPlanMaint.getTimeLimit();
        if (timeLimit != null) {
            Long days = timeLimit / (24 * 60 * 60l);
            Long hours = timeLimit % (24 * 60 * 60l);
//            System.out.println(days);
//            System.out.println(hours);
            dmsPlanMaint.setTimeLimitDays(days);
            dmsPlanMaint.setTimeLimitHours(hours / (60 * 60l));
        }
        return dmsPlanMaint;
    }

    /**
     * 定时任务：每天凌晨1点一次性生成当天整天的保养工单
     * 使用Mapper替代JdbcTemplate，生成已完成状态工单，工单中所有设备默认保养完成
     * 若有异常可在网页端维护工单明细中的设备状态
     * cron表达式：秒 分 时 日 月 周
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void generateDailyMaintWorkOrders() {
        log.info("========== 开始执行保养工单生成任务 ==========");
        int count = 0;
        int skipCount = 0;
        try {
            // 通过Mapper查询“今天整天内应生成”的保养计划。
            // 这里依赖SQL使用“小于次日0点”的上界，避免把次日00:00计划提前捞出来。
            List<DmsPlanMaint> plans = dmsPlanMaintMapper.selectPendingMaintPlans();

            for (DmsPlanMaint plan : plans) {
                try {
                    Long planMaintId = plan.getPlanMaintId();
                    String planMaintCode = plan.getPlanMaintCode();

                    if (planMaintCode == null || planMaintCode.isEmpty()) {
                        log.warn("保养计划ID[{}]编号为空，跳过", planMaintId);
                        skipCount++;
                        continue;
                    }

                    // 通过Service创建已完成状态的保养工单（含明细，工单中所有设备默认保养完成，异常可在网页端维护）
                    int insertRows = dmsBillsMaintInstanceService.insertCompletedMaintInstance(planMaintCode);
                    if (insertRows > 0) {
                        count++;
                        log.info("已为保养计划[{}]生成已完成工单", planMaintCode);
                        // 基于“当前计划时间”推进下次执行时间，
                        // 避免凌晨1点批量生成当天工单后，又把计划推进回当天稍晚时间，导致次日被重复捞取。
                        updateMaintPlanNextTime(plan);
                    } else {
                        skipCount++;
                        log.debug("保养计划[{}]未生成工单（可能已存在或数据不完整），跳过", planMaintCode);
                    }

                } catch (Exception e) {
                    log.error("为保养计划生成工单失败 | planMaintId={}, planMaintCode={}, cronExpression={}, maintTime={}, maintLevel={}, maintGroup={}, 异常信息: {}",
                            plan.getPlanMaintId(), plan.getPlanMaintCode(), plan.getCronExpression(),
                            plan.getMaintTime(), plan.getMaintLevel(), plan.getMaintGroup(),
                            e.getMessage(), e);
                }
            }
        } catch (Exception e) {
            log.error("查询待执行保养计划列表失败(selectPendingMaintPlans), 异常信息: {}", e.getMessage(), e);
        }
        log.info("========== 保养工单生成任务完成，生成数量: {}，跳过数量: {} ==========", count, skipCount);
    }

    /**
     * 更新保养计划的下次执行时间
     * 优先使用cron表达式计算，无cron则默认+1天
     */
    private void updateMaintPlanNextTime(DmsPlanMaint plan) {
        try {
            Date nextTime = null;
            String cronExpression = plan.getCronExpression();
            if (cronExpression != null && !cronExpression.isEmpty()) {
                // 这里必须基于计划当前 maintTime 推进，而不能基于“当前系统时间”直接算下一次，
                // 否则当天未来时点的计划会被错误推进到“今天稍后”，第二天凌晨仍会再次命中。
                nextTime = calculateNextMaintTime(cronExpression, plan.getMaintTime());
            }
            if (nextTime == null) {
                log.warn("保养计划下次执行时间计算为null, 使用默认+1天 | planMaintId={}, planMaintCode={}, cronExpression={}",
                        plan.getPlanMaintId(), plan.getPlanMaintCode(), cronExpression);
                nextTime = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000L);
            }
            dmsPlanMaintMapper.updatePlanNextTime(plan.getPlanMaintId(), nextTime);
            log.debug("更新保养计划下次执行时间 | planMaintCode={}, nextTime={}", plan.getPlanMaintCode(), nextTime);
        } catch (Exception e) {
            log.error("更新保养计划下次执行时间失败 | planMaintId={}, planMaintCode={}, cronExpression={}, 异常信息: {}",
                    plan.getPlanMaintId(), plan.getPlanMaintCode(), plan.getCronExpression(),
                    e.getMessage(), e);
        }
    }

    /**
     * 计算保养计划下次执行时间:
     * 1) 基于计划当前 maintTime 推进；
     * 2) 若算出的时间仍不晚于当前时间，则继续推进，直到晚于当前时间。
     */
    private Date calculateNextMaintTime(String cronExpression, Date currentMaintTime) {
        try {
            CronExpression cron = new CronExpression(cronExpression);
            Date now = new Date();
            Date cursor = currentMaintTime != null ? currentMaintTime : now;
            Date next = cron.getNextValidTimeAfter(cursor);
            while (next != null && !next.after(now)) {
                next = cron.getNextValidTimeAfter(next);
            }
            return next;
        } catch (ParseException e) {
            log.error("cron表达式非法，无法计算下次执行时间 | cronExpression={}, 异常信息: {}", cronExpression, e.getMessage(), e);
            return null;
        }
    }
}
