package com.testor.module.safeCheck.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.testor.biz.sys.dict.data.model.domain.SysDictData;
import com.testor.biz.sys.dict.data.service.SysDictDataService;
import com.testor.common.util.cron.FrequencyDTO;
import com.testor.common.util.cron.FrequencyUtil;
import com.testor.module.safeCheck.dao.TSafeCheckPlanDao;
import com.testor.module.safeCheck.model.domain.*;
import com.testor.module.safeCheck.model.dto.TSafeCheckPlanParam;
import com.testor.module.safeCheck.service.*;
import com.testor.module.sys.model.domian.NewSysOrg;
import com.testor.module.sys.service.NewSysOrgService;
import com.tongtech.tfw.backend.common.biz.constants.BizConstants;
import com.tongtech.tfw.backend.common.context.ContextUtils;
import com.tongtech.tfw.backend.common.models.exceptions.ServiceException;
import com.tongtech.tfw.backend.common.models.response.ResponseInfo;
import com.tongtech.tfw.backend.common.models.sys.UserInfo;
import com.tongtech.tfw.backend.core.helper.IdHelper;
import com.tongtech.tfw.backend.core.helper.ObjectHelper;
import com.tongtech.tfw.backend.core.helper.StringHelper;
import lombok.SneakyThrows;
import net.sf.cglib.core.Local;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Service;
import com.tongtech.tfw.backend.common.models.supers.SuperServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 安全检查计划Service业务层处理
 * 
 * @author testor-framework
 * @date 2024-09-03 08:04:18
 */
@Service
public class TSafeCheckPlanServiceImpl extends SuperServiceImpl<TSafeCheckPlanDao, TSafeCheckPlan> implements TSafeCheckPlanService
{
    private TSafeCheckPlanDao tSafeCheckPlanDao;

    @Autowired
    private TSafeCheckOrgService tSafeCheckOrgService;

    @Autowired
    private TSafeCheckPersonService tSafeCheckPersonService;

    @Autowired
    private FrequencyUtil frequencyUtil;

    @Autowired
    private NewSysOrgService sysOrgService;

    @Autowired
    private SysDictDataService sysDictDataService;

    @Autowired
    private TSafeCheckPersonArrangeService tSafeCheckPersonArrangeService;

    @Autowired
    private TSafeCheckTaskService tSafeCheckTaskService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(TSafeCheckPlan data) {

        boolean b = this.save(data);
        if (b) {
            saveCheckOrgAndPerson(data);
            return true;
        }
        return false;
    }

    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(TSafeCheckPlan data) {
        boolean checkStatusDidntStart = checkStatusDidntStart(data.getId());
        //状态不为未开始
        if (!checkStatusDidntStart){
            throw new ServiceException(ResponseInfo.builder().code(400).msg("进行中、已结束状态的排查计划不支持该操作").build());
        }
        boolean b = this.updateById(data);
        if (b){
            delCheckOrgAndPerson(data.getId());
            if (data.getStatus().equals(BizConstants.STATUS_ENABLE)) {
                saveCheckOrgAndPerson(data);
            }
        }
        return b;
    }

    @Override
    public boolean copyPlan(TSafeCheckPlan updateRequest) {
        String planId = updateRequest.getId();
        TSafeCheckPlan byId = this.getById(planId);
        byId.setName(byId.getName()+"-复制信息");
        byId.setId(IdHelper.getId32bit());
        //重置时间
        byId.setStartDate(null);
        byId.setEndDate(null);
        boolean save = this.save(byId);
        if (save) {
            //复制机构信息
            List<TSafeCheckOrg> listByPlanId = tSafeCheckOrgService.getListByPlanId(planId);
            listByPlanId = listByPlanId.stream().peek(tSafeCheckPerson -> {
                tSafeCheckPerson.setId(IdHelper.getId32bit());
                tSafeCheckPerson.setPlanId(byId.getId());
            }).collect(Collectors.toList());
            tSafeCheckOrgService.saveBatch(listByPlanId);
            //复制人员计划信息
            List<TSafeCheckPerson> listByPlanId1 = tSafeCheckPersonService.getListByPlanId(planId);
            listByPlanId1 = listByPlanId1.stream().peek(tSafeCheckPerson -> {
                String uuid = IdHelper.getId32bit();
                //复制人员计划具体人员
                List<TSafeCheckPersonArrange> listByCheckPersonId = tSafeCheckPersonArrangeService.getListByCheckPersonId(tSafeCheckPerson.getId());
                listByCheckPersonId = listByCheckPersonId.stream().peek(tSafeCheckPersonArrange -> {
                   tSafeCheckPersonArrange.setId(IdHelper.getId32bit());
                   tSafeCheckPersonArrange.setPlanId(byId.getId());
                   tSafeCheckPersonArrange.setCheckPersonId(uuid);
                }).collect(Collectors.toList());
                tSafeCheckPerson.setId(uuid);
                tSafeCheckPerson.setPlanId(byId.getId());
                tSafeCheckPersonArrangeService.saveBatch(listByCheckPersonId);
            }).collect(Collectors.toList());
            tSafeCheckPersonService.saveBatch(listByPlanId1);
            return true;
        }
        return false;
    }

    @Override
    public List<TSafeCheckPlan> findList(TSafeCheckPlanParam param) {
        QueryWrapper<TSafeCheckPlan> queryWrapper=this.createQuery(param);
        return this.list(queryWrapper);
    }

    @Override
    public List<TSafeCheckPlan> findOngoingList() {
        TSafeCheckPlanParam queryParam = new TSafeCheckPlanParam();
        queryParam.setPlanStatus("1");
        QueryWrapper<TSafeCheckPlan> queryWrapper= new QueryWrapper<>();
        queryWrapper.eq(TSafeCheckPlan.STATUS, BizConstants.STATUS_ENABLE);
        //如果计划状态不为空
        if(StringHelper.isNotEmpty(queryParam.getPlanStatus())){
            Date now = new Date();
            //未开始
            if (queryParam.getPlanStatus().equals("0")){
                queryWrapper.ge(TSafeCheckPlan.START_DATE, now);
                //进行中
            }else if (queryParam.getPlanStatus().equals("1")){
                queryWrapper.le(TSafeCheckPlan.START_DATE, now)
                        .ge(TSafeCheckPlan.END_DATE, now);
                //已结束
            }else if (queryParam.getPlanStatus().equals("2")){
                queryWrapper.le(TSafeCheckPlan.END_DATE, now);
            }
        }
        return this.list(queryWrapper);
    }

    @Override
    public Page<TSafeCheckPlan> pageList(TSafeCheckPlanParam param) {
        Long page=
                StringHelper.isEmpty(param.getPage())?BizConstants.PAGE:Long.valueOf(param.getPage());
        Long limit=
                StringHelper.isEmpty(param.getLimit())?BizConstants.LIMIT:Long.valueOf(param.getLimit());
        Page<TSafeCheckPlan> resultPage=new Page<>(page,limit);
        // TODO 根据需求修改查询条件及查询参数
        QueryWrapper<TSafeCheckPlan> queryWrapper=this.createQuery(param);
        Page<TSafeCheckPlan> pageList = this.page(resultPage, queryWrapper);
        List<TSafeCheckPlan> records = pageList.getRecords();
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        for (TSafeCheckPlan record : records) {
            NewSysOrg byId = sysOrgService.getById(record.getOrgId());
            if (byId != null) {
                record.setOrgName(byId.getOrgName());
            }
            //设置检查类型
            List<TSafeCheckPerson> tSafeCheckPersonList = tSafeCheckPersonService.list(new LambdaQueryWrapper<TSafeCheckPerson>().select(TSafeCheckPerson::getCheckType).eq(TSafeCheckPerson::getPlanId, record.getId()).groupBy(TSafeCheckPerson::getCheckType));
            List<String> checkTypes = new ArrayList<>();
            for (TSafeCheckPerson tSafeCheckPerson : tSafeCheckPersonList) {
                SysDictData sysDictData = sysDictDataService.getById(tSafeCheckPerson.getCheckType());
                checkTypes.add(sysDictData.getDictValue());
            }
            record.setCheckType(String.join(", ", checkTypes));
            // 获取计划的开始日期和结束日期
            LocalDateTime startDate = com.testor.common.util.DateUtil.dateToLocalDateTime(  record.getStartDate());
            LocalDateTime endDate =com.testor.common.util.DateUtil.dateToLocalDateTime( record.getEndDate());
            // 计算计划状态
            if (startDate == null || endDate == null) {
                // 处理缺失的日期情况
                setPlanStatus(record, TSafeCheckPlan.PlanStatus.NOT_STARTED);
            } else if (now.isBefore(startDate)) {
                // 当前时间在开始时间之前
                setPlanStatus(record, TSafeCheckPlan.PlanStatus.NOT_STARTED);
            } else if (now.isAfter(endDate)) {
                // 当前时间在结束时间之后
                setPlanStatus(record, TSafeCheckPlan.PlanStatus.COMPLETED);
            } else {
                // 当前时间在开始时间和结束时间之间
                setPlanStatus(record, TSafeCheckPlan.PlanStatus.IN_PROGRESS);
            }
        }
        return pageList;
    }

    private void setPlanStatus(TSafeCheckPlan record, TSafeCheckPlan.PlanStatus status) {
        record.setPlanStatus(status.getCode());
        record.setPlanStatusName(status.getName());
    }

    /**
     * 删除被检查机构和检查人员
     * @param planId
     */
    @Override
    public void delCheckOrgAndPerson(String planId){
        tSafeCheckOrgService.remove(new LambdaQueryWrapper<TSafeCheckOrg>().eq(TSafeCheckOrg::getPlanId, planId));
        tSafeCheckPersonService.remove(new LambdaQueryWrapper<TSafeCheckPerson>().eq(TSafeCheckPerson::getPlanId, planId));
        tSafeCheckPersonArrangeService.remove(new LambdaQueryWrapper<TSafeCheckPersonArrange>().eq(TSafeCheckPersonArrange::getPlanId, planId));
    }

    /**
     * 存入被检查机构和检查人员
     * @param data
     */
    public void saveCheckOrgAndPerson(TSafeCheckPlan data){
       List<TSafeCheckOrg> tSafeCheckOrgs = data.getTSafeCheckOrgs();
       if (tSafeCheckOrgs != null && tSafeCheckOrgs.size() > 0){
          tSafeCheckOrgs = tSafeCheckOrgs.stream().peek(tSafeCheckOrg -> tSafeCheckOrg.setPlanId(data.getId())).collect(Collectors.toList());
       }
       tSafeCheckOrgService.saveBatch(tSafeCheckOrgs);
       List<TSafeCheckPerson> tSafeCheckPersonList = data.getTSafeCheckPersonList();
       if (tSafeCheckPersonList != null && tSafeCheckPersonList.size() > 0){
           tSafeCheckPersonList = tSafeCheckPersonList.stream().peek(tSafeCheckPerson -> tSafeCheckPerson.setPlanId(data.getId())).collect(Collectors.toList());
           buildCheckPerson(tSafeCheckPersonList,data);
       }
    }

    /**
     * 封装任务执行时间
     * @param tSafeCheckPersonList
     */
    public void buildCheckPerson(List<TSafeCheckPerson> tSafeCheckPersonList,TSafeCheckPlan data){
        LocalDateTime now = LocalDateTime.now();
        Integer generated = 0;
        if (tSafeCheckPersonList != null && tSafeCheckPersonList.size() > 0){
            // 生成cron表达式
            for (TSafeCheckPerson checkPeople : tSafeCheckPersonList) {
                FrequencyDTO frequencyDTO = new FrequencyDTO();
                frequencyDTO.setFrequencyKey(checkPeople.getFrequency());
                frequencyDTO.setTime(checkPeople.getStartTime());
                frequencyDTO.setDate(checkPeople.getStartDate());
                frequencyDTO.setDayNum(checkPeople.getStartDayNum());
                frequencyDTO.setMonthNum((checkPeople.getStartMonthNum()));
                //   frequencyDTO.setAdvanceHour(-advanceHour);
                String startCronStr = FrequencyUtil.generateCronBy(frequencyDTO);

                FrequencyDTO endFrequencyDTO = new FrequencyDTO();
                endFrequencyDTO.setFrequencyKey(checkPeople.getFrequency());
                endFrequencyDTO.setTime(checkPeople.getEndTime());
                endFrequencyDTO.setDate(checkPeople.getEndDate());
                endFrequencyDTO.setDayNum(checkPeople.getEndDayNum());
                endFrequencyDTO.setMonthNum((checkPeople.getEndMonthNum()));
                //     endFrequencyDTO.setAdvanceHour(-advanceHour);
                String endCronStr = FrequencyUtil.generateCronBy(endFrequencyDTO);

                checkPeople.setStartCronExpression(startCronStr);
                checkPeople.setEndCronExpression(endCronStr);
                tSafeCheckPersonService.save(checkPeople);

                //插入具体人员信息
                List<TSafeCheckPersonArrange> tSafeCheckPersonArranges = checkPeople.getTSafeCheckPersonArranges();
                tSafeCheckPersonArranges = tSafeCheckPersonArranges.stream().peek(tSafeCheckPersonArrange -> {
                    tSafeCheckPersonArrange.setCheckPersonId(checkPeople.getId());
                    tSafeCheckPersonArrange.setPlanId(checkPeople.getPlanId());
                }).collect(Collectors.toList());
                tSafeCheckPersonArrangeService.saveBatch(tSafeCheckPersonArranges);
                LocalDateTime planStartDate = com.testor.common.util.DateUtil.dateToLocalDateTime(data.getStartDate());
                //如果计划任务开始日期是当天
                if (planStartDate.toLocalDate().isEqual(now.toLocalDate())){
                    TSafeCheckPlan tSafeCheckPlan = tSafeCheckTaskService.buildStartAndEndTime(checkPeople, now);
                    LocalDateTime startDate = com.testor.common.util.DateUtil.dateToLocalDateTime(tSafeCheckPlan.getStartDate());
                    //如果生成的任务开始时间是今天
                    if(startDate.toLocalDate().isEqual(now.toLocalDate())) {
                        generated ++;
                    }
                }
            }
        }
        //生成任务
        if (generated > 0){
            tSafeCheckTaskService.createCheckTaskExecutor();
        }
    }

    /**
     * 校验计划是否未开始
     * @param planId
     * @return
     */
    public boolean checkStatusDidntStart(String planId){
        TSafeCheckPlan one = this.getOne(new LambdaQueryWrapper<TSafeCheckPlan>().eq(TSafeCheckPlan::getId, planId).gt(TSafeCheckPlan::getStartDate, new Date()));
        if (one != null){
            return true;
        }
        return false;
    }


    /**
     * 列表查询条件及查询参数
     */
    private QueryWrapper<TSafeCheckPlan> createQuery(TSafeCheckPlanParam queryParam){
        QueryWrapper<TSafeCheckPlan> queryWrapper=new QueryWrapper<>();
        if(StringHelper.isNotEmpty(queryParam.getOrgId())){
            String orgId = queryParam.getOrgId();
            List<String> orgIds = Arrays.asList(orgId.split(","));
            queryWrapper.in(TSafeCheckPlan.ORG_ID,orgIds);
        }else {
            UserInfo loginUser = ContextUtils.getLoginUser();
            if(loginUser != null) {
                List<String> childOrgIdByParentId = sysOrgService.getIdsChildrenById(loginUser.getOrgId());
                queryWrapper.in(TSafeCheckPlan.ORG_ID, childOrgIdByParentId);
            }
        }
        //如果计划状态不为空
        if(StringHelper.isNotEmpty(queryParam.getPlanStatus())){
            Date now = new Date();
            //未开始
            if (queryParam.getPlanStatus().equals("0")){
                queryWrapper.ge(TSafeCheckPlan.START_DATE, now);
                //进行中
            }else if (queryParam.getPlanStatus().equals("1")){
                queryWrapper.le(TSafeCheckPlan.START_DATE, now)
                        .ge(TSafeCheckPlan.END_DATE, now);
                //已结束
            }else if (queryParam.getPlanStatus().equals("2")){
                queryWrapper.le(TSafeCheckPlan.END_DATE, now);
            }
        }
        if(StringHelper.isNotEmpty(queryParam.getCheckType())){
            List<Object> ids = tSafeCheckPersonService.listObjs(new LambdaQueryWrapper<TSafeCheckPerson>().select(TSafeCheckPerson::getPlanId)
                    .eq(TSafeCheckPerson::getCheckType, queryParam.getCheckType()).groupBy(TSafeCheckPerson::getPlanId));
            if (ids != null && ids.size() > 0){
                queryWrapper.in(TSafeCheckPlan.ID,ids);
            }
            //没有查询空
            else {
                queryWrapper.eq(TSafeCheckPerson.ID,-1);
            }
        }
        if(StringHelper.isNotEmpty(queryParam.getName())){
            queryWrapper.like(TSafeCheckPlan.NAME,queryParam.getName());
        }
        if(ObjectHelper.isNotEmpty(queryParam.getStartDate())){
            queryWrapper.ge(TSafeCheckPlan.START_DATE,queryParam.getStartDate());
        }
        if(ObjectHelper.isNotEmpty(queryParam.getEndDate())){
            queryWrapper.le(TSafeCheckPlan.START_DATE,queryParam.getEndDate());
        }
        if(StringHelper.isNotEmpty(queryParam.getInWeekend())){
            queryWrapper.eq(TSafeCheckPlan.IN_WEEKEND,queryParam.getInWeekend());
        }
        if(StringHelper.isNotEmpty(queryParam.getInHoliday())){
            queryWrapper.eq(TSafeCheckPlan.IN_HOLIDAY,queryParam.getInHoliday());
        }
        if(ObjectHelper.isNotEmpty(queryParam.getAdvanceHour())){
            queryWrapper.eq(TSafeCheckPlan.ADVANCE_HOUR,queryParam.getAdvanceHour());
        }
        if (StringHelper.isNotEmpty(queryParam.getStatus())) {
            queryWrapper.eq(TSafeCheckPlan.STATUS, queryParam.getStatus());
        } else {
            queryWrapper.ne(TSafeCheckPlan.STATUS, BizConstants.STATUS_DELETE);
        }
        if (StringHelper.isNotEmpty(queryParam.getOrderBy())){
            if(StringHelper.isNotEmpty(queryParam.getOrderType())
                    &&BizConstants.ASC.equals(queryParam.getOrderType())){
                queryWrapper.orderByAsc(queryParam.getOrderBy());
            }else{
                queryWrapper.orderByDesc(queryParam.getOrderBy());
            }
        }else{
            queryWrapper.orderByDesc(TSafeCheckPlan.UPDATE_DATE);
        }
        return queryWrapper;
    }
}
