package org.jeecg.modules.plan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.AllArgsConstructor;
import org.jeecg.modules.device.entity.BuDevice;
import org.jeecg.modules.device.mapper.BuDeviceMapper;
import org.jeecg.modules.plan.entity.PlanV;
import org.jeecg.modules.plan.mapper.PlanVMapper;
import org.jeecg.modules.plan.modal.PlanBo;
import org.jeecg.modules.plan.service.IPlanVService;
import org.jeecg.modules.regular.entity.Regular;
import org.jeecg.modules.regular.mapper.RegularMapper;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;

import static java.time.LocalDate.now;

/**
 * @Description: 计划临时表(用于计划预测)
 * @Author: jeecg-boot
 * @Date:   2025-06-10
 * @Version: V1.0
 */
@AllArgsConstructor
@Service
public class PlanVServiceImpl extends ServiceImpl<PlanVMapper, PlanV> implements IPlanVService {

    private BuDeviceMapper deviceMapper;
    private RegularMapper regularMapper;

    /**
     * 计划生成方法
     *
     * @param bo 计划生成要求
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean generatePlan(PlanBo bo) throws Exception {
        // 需要生成计划的设备
        List<BuDevice> deviceList = deviceMapper.selectList(null);

        // 处理每一个设备
        for(BuDevice device : deviceList) {
            // 查询设备的需要生成计划的规程
            List<Regular> deviceRegularList = regularMapper.selectList(new LambdaQueryWrapper<Regular>()
                    .eq(Regular::getDeviceTypeId, device.getDeviceTypeId())
                    .eq(bo.getRapairRange() != null, Regular::getRapairRange, bo.getRapairRange())
                    .orderByDesc(Regular::getRapairRange));

            Set<LocalDate> planRegulars = new HashSet<>();
            for(Regular regularVo : deviceRegularList) {
                // 在计划预测部分，如果指定日期之后存在数据，则清空原有数据
                LambdaQueryWrapper<PlanV> queryWrapper = new LambdaQueryWrapper<PlanV>()
                        .eq(PlanV::getDeviceId, device.getId())
                        .eq(PlanV::getRapairRange, regularVo.getRapairRange())
                        .ge(bo.getCalMonthStart() != null, PlanV::getCalDay, bo.getCalMonthStart())
                        .orderByAsc(bo.getCalDay() != null, PlanV::getCalDay)
                        .orderByDesc(bo.getCalDay() == null, PlanV::getCalDay);
                baseMapper.delete(queryWrapper);

                // 批量创建新计划
                List<PlanV> devicePlanList = new ArrayList<>();
                // 检修计划年次序
                int nextOrder = 0;
                // 初始检修作业日期
                LocalDate planDate = now();
                // 根据[结束日期]按时间顺序生成检修计划
                while (!planDate.isAfter(LocalDate.parse(bo.getCalMonthEnd().substring(0,10)))) {
                    nextOrder = nextOrder % 12 + 1;
                    // 如果日期已存在则跳过
                    if (planRegulars.add(planDate)) {
                        // 添加成功说明当天没有安排更高的检修计划，生成新的计划
                        LocalDate workDate = planDate;
                        int workDays = 0;//以安排计划的天数(在单个检修任务中计算)
                        while (workDays < regularVo.getDuration()) {
                            // 跳过周末
                            if (workDate.getDayOfWeek().getValue() <= 5) {
                                PlanV plan = new PlanV(device.getId(), regularVo.getRapairRange(),
                                        workDate,// 检修作业日期
                                        workDate.getDayOfWeek().getValue(),// 获取数字形式(1-7，周一是1，周日是7)
                                        nextOrder);
                                devicePlanList.add(plan);
                                workDays++;// 如果成功创建检修计划对象则已安排的计划天数加一
                            }
                            // 无论当天是否安排计划，日期加一天
                            workDate = workDate.plusDays(1);
                        }
                    }
                    // 无论是否安排计划，跳转到下一个检修作业日期
                    planDate = planDate.plusDays(regularVo.getMaintenanceCycle());
                }

                // 批量插入
                if (!devicePlanList.isEmpty()) {
                    saveBatch(devicePlanList);
                }
            }
        }
        return true;
    }

}
