package com.ygtx.gxt.task;

import com.ygtx.common.core.domain.entity.SysUser;
import com.ygtx.common.core.domain.model.LoginUser;
import com.ygtx.common.utils.DateUtils;
import com.ygtx.common.utils.SecurityUtils;
import com.ygtx.framework.web.service.SysPermissionService;
import com.ygtx.gxt.domain.*;
import com.ygtx.gxt.mapper.GxtRepairOrderMapper;
import com.ygtx.gxt.mapper.GxtWorkOrderMapper;
import com.ygtx.gxt.service.IGxtOrderScoreService;
import com.ygtx.gxt.service.IGxtRepairOrderFlowService;
import com.ygtx.gxt.service.IGxtRepairOrderService;
import com.ygtx.gxt.service.IGxtWorkOrderFlowService;
import com.ygtx.gxt.service.IGxtWorkOrderService;
import com.ygtx.system.mapper.SysUserMapper;
import com.ygtx.system.service.ISysConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * 工单自动归档任务
 * 每天凌晨2点执行，对自评状态超过3天的维修工单和维保工单进行自动归档
 *
 * @author ouyj
 * @date 2026-01-07
 */
@EnableScheduling
@Component("orderScoreAutoArchiveTask")
public class OrderScoreAutoArchiveTask {

    private static final Logger log = LoggerFactory.getLogger(OrderScoreAutoArchiveTask.class);

    @Autowired
    private IGxtRepairOrderService repairOrderService;

    @Autowired
    private IGxtRepairOrderFlowService repairOrderFlowService;

    @Autowired
    private IGxtWorkOrderService workOrderService;

    @Autowired
    private IGxtWorkOrderFlowService workOrderFlowService;

    @Autowired
    private IGxtOrderScoreService orderScoreService;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private ISysConfigService configService;
    


    /**
     * 每天凌晨2点执行定时任务
     * 查找自评状态超过3天但未处理的维修工单和维保工单，并进行工分自动归档
     */
    //@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行一次
    public void autoArchiveOrders() {
        log.info("开始执行工单工分自动归档任务");
        
        // 设置系统用户上下文
        setSystemUserContext();
        
        try {
            // 处理维修工单的自动归档
            processRepairOrders();

            // 处理维保工单的自动归档
            processWorkOrders();

        } catch (Exception e) {
            log.error("执行工单工分自动归档任务时发生异常", e);
        }
    }

    /**
     * 处理维修工单工分的自动归档
     */
    private void processRepairOrders() {
        try {
            // 构造查询条件：待自评状态的维修工单
            GxtRepairOrder queryOrder = new GxtRepairOrder();
            queryOrder.setWorkOrderStatus("completed");
            queryOrder.setScoringStatus("to_self"); // 待自评状态
            List<GxtRepairOrder> orders = repairOrderService.selectGxtRepairOrderList(queryOrder);

            int archiveCount = 0;
            for (GxtRepairOrder order : orders) {
                // 检查是否满足自动归档条件（自评状态超过3天）
                if (shouldAutoArchiveRepairOrder(order)) {
                    // 执行自动归档操作
                    autoArchiveRepairOrder(order);
                    archiveCount++;
                }
            }

            log.info("维修工单工分自动归档任务执行完成，共处理 {} 个工单", archiveCount);
        } catch (Exception e) {
            log.error("处理维修工单工分自动归档时发生异常", e);
        }
    }

    /**
     * 处理维保工单工分的自动归档
     */
    private void processWorkOrders() {
        try {
            // 构造查询条件：待自评状态的维保工单
            GxtWorkOrder queryOrder = new GxtWorkOrder();
            queryOrder.setWorkOrderStatus("completed");
            queryOrder.setScoringStatus("to_self"); // 待自评状态
            List<GxtWorkOrder> orders = workOrderService.selectGxtWorkOrderList(queryOrder);

            int archiveCount = 0;
            for (GxtWorkOrder order : orders) {
                // 检查是否满足自动归档条件（自评状态超过3天）
                if (shouldAutoArchiveWorkOrder(order)) {
                    // 执行自动归档操作
                    autoArchiveWorkOrder(order);
                    archiveCount++;
                }
            }

            log.info("维保工单工分自动归档任务执行完成，共处理 {} 个工单", archiveCount);
        } catch (Exception e) {
            log.error("处理维保工单工分自动归档时发生异常", e);
        }
    }

    /**
     * 判断维修工单是否满足工分自动归档条件
     * 条件：自评状态时间已超过配置的天数，默认1天
     *
     * @param order 维修工单
     * @return 是否满足工分自动归档条件
     */
    private boolean shouldAutoArchiveRepairOrder(GxtRepairOrder order) {
        /*if("completed".equals(order.getWorkOrderStatus()) || "archived".equals(order.getWorkOrderStatus())){

        }*/
        Date completeTime = null;
        
        // 通过查询工单流转记录获取自评状态时间
        GxtRepairOrderFlow flowQuery = new GxtRepairOrderFlow();
        flowQuery.setOrderId(order.getId());
        flowQuery.setActionType("complete"); // 结单操作类型
        List<GxtRepairOrderFlow> flows = repairOrderFlowService.selectGxtRepairOrderFlowList(flowQuery);

        if (!flows.isEmpty()) {
            // 获取最后一次自评的时间
            completeTime = flows.get(flows.size() - 1).getActionTime();
        }

        if (completeTime == null) {
            return false;
        }

        // 从配置中获取自评状态超时天数，如果配置为空则默认3天
        String daysStr = configService.selectConfigByKey("gxt.orderScore.autoArchiveDays");
        int archiveDays = 3; // 默认3天
        if (daysStr != null && !daysStr.trim().isEmpty()) {
            try {
                archiveDays = Integer.parseInt(daysStr.trim());
            } catch (NumberFormatException e) {
                log.warn("配置的自动归档天数不是有效数字，使用默认值3天: {}", daysStr);
            }
        }

        // 检查自评时间是否已超过配置的天数
        Date now = DateUtils.getNowDate();
        Date archiveTimeThreshold = DateUtils.addDays(completeTime, archiveDays);

        return now.after(archiveTimeThreshold);
    }

    /**
     * 判断维保工单是否满足工分自动归档条件
     * 条件：自评状态时间已超过配置的天数，默认1天
     *
     * @param order 维保工单
     * @return 是否满足工分自动归档条件
     */
    private boolean shouldAutoArchiveWorkOrder(GxtWorkOrder order) {
        Date completeTime = null;
        
        // 通过查询工单流转记录获取自评状态时间
        GxtWorkOrderFlow flowQuery = new GxtWorkOrderFlow();
        flowQuery.setOrderId(order.getId());
        flowQuery.setActionType("complete"); // 结单操作类型
        List<GxtWorkOrderFlow> flows = workOrderFlowService.selectGxtWorkOrderFlowList(flowQuery);

        if (!flows.isEmpty()) {
            // 获取最后一次自评的时间
            completeTime = flows.get(flows.size() - 1).getActionTime();
        }

        if (completeTime == null) {
            return false;
        }

        // 从配置中获取自评状态超时天数，如果配置为空则默认3天
        String daysStr = configService.selectConfigByKey("gxt.orderScore.autoArchiveDays");
        int archiveDays = 3; // 默认3天
        if (daysStr != null && !daysStr.trim().isEmpty()) {
            try {
                archiveDays = Integer.parseInt(daysStr.trim());
            } catch (NumberFormatException e) {
                log.warn("配置的自动归档天数不是有效数字，使用默认值3天: {}", daysStr);
            }
        }

        // 检查自评时间是否已超过配置的天数
        Date now = DateUtils.getNowDate();
        Date archiveTimeThreshold = DateUtils.addDays(completeTime, archiveDays);

        return now.after(archiveTimeThreshold);
    }

    /**
     * 对维修工单进行自动归档操作
     *
     * @param order 需要归档的工单
     */
    private void autoArchiveRepairOrder(GxtRepairOrder order) {
        try {
            // 更新工单状态为已归档
            if(order.getRestartTime() != null){
                order.setScoringStatus("archived");
                order.setWorkOrderStatus("archived");
            }else{
                order.setScoringStatus("to_archive");
            }
            order.setUpdateTime(new Date());
            order.setUpdateBy(SecurityUtils.getLoginUser().getUser().getUserName());

            int result = repairOrderService.updateGxtRepairOrderForScore(order);
            
            if (result > 0) {
                log.info("工单 {} 已成功自动归档", order.getWorkOrderProjectNo());

                if("archived".equals(order.getWorkOrderStatus())){
                    // 添加归档流程记录
                    addArchiveFlowRecordForRepairOrder(order);
                }
            } else {
                log.warn("工单 {} 自动归档失败", order.getWorkOrderProjectNo());
            }
        } catch (Exception e) {
            log.error("自动归档工单 {} 时发生异常", order.getWorkOrderProjectNo(), e);
        }
    }

    /**
     * 对维保工单进行自动归档操作
     *
     * @param order 需要归档的工单
     */
    private void autoArchiveWorkOrder(GxtWorkOrder order) {
        try {
            // 更新工单状态为已归档
            if(order.getRestartTime() != null){
                order.setScoringStatus("archived");
                order.setWorkOrderStatus("archived");
            }else{
                order.setScoringStatus("to_archive");
            }
            order.setUpdateTime(new Date());
            order.setUpdateBy(SecurityUtils.getLoginUser().getUser().getUserName());

            int result = workOrderService.updateGxtWorkOrderForScore(order);
            
            if (result > 0) {
                log.info("工单 {} 已成功自动归档", order.getWorkOrderProjectNo());

                if("archived".equals(order.getWorkOrderStatus())){
                    // 添加归档流程记录
                    addArchiveFlowRecordForWorkOrder(order);
                }
            } else {
                log.warn("工单 {} 自动归档失败", order.getWorkOrderProjectNo());
            }
        } catch (Exception e) {
            log.error("自动归档工单 {} 时发生异常", order.getWorkOrderProjectNo(), e);
        }
    }

    /**
     * 为维修工单添加归档流程记录
     *
     * @param order 已归档的工单
     */
    private void addArchiveFlowRecordForRepairOrder(GxtRepairOrder order) {
        try {
            GxtRepairOrderFlow flow = new GxtRepairOrderFlow();
            flow.setOrderId(order.getId());
            flow.setOrderCode(order.getWorkOrderProjectNo());
            flow.setActionType("archive");
            flow.setFromStatus("to_archive");
            flow.setToStatus("archived");
            flow.setOperatorId(1L); // 系统自动操作，使用系统用户ID
            flow.setOperatorName("系统自动");
            flow.setActionTime(DateUtils.getNowDate());
            flow.setActionRemark("系统自动归档");
            
            repairOrderFlowService.insertGxtRepairOrderFlow(flow);
            log.info("工单 {} 的归档流程记录已添加", order.getWorkOrderProjectNo());
        } catch (Exception e) {
            log.error("为维修工单 {} 添加归档流程记录时发生异常", order.getWorkOrderProjectNo(), e);
        }
    }

    /**
     * 为维保工单添加归档流程记录
     *
     * @param order 已归档的工单
     */
    private void addArchiveFlowRecordForWorkOrder(GxtWorkOrder order) {
        try {
            GxtWorkOrderFlow flow = new GxtWorkOrderFlow();
            flow.setOrderId(order.getId());
            flow.setOrderCode(order.getWorkOrderProjectNo());
            flow.setActionType("archive");
            flow.setFromStatus("to_archive");
            flow.setToStatus("archived");
            flow.setOperatorId(1L); // 系统自动操作，使用系统用户ID
            flow.setOperatorName("系统自动");
            flow.setActionTime(DateUtils.getNowDate());
            flow.setActionRemark("系统自动归档");
            
            workOrderFlowService.insertGxtWorkOrderFlow(flow);
            log.info("工单 {} 的归档流程记录已添加", order.getWorkOrderProjectNo());
        } catch (Exception e) {
            log.error("为维保工单 {} 添加归档流程记录时发生异常", order.getWorkOrderProjectNo(), e);
        }
    }

    /**
     * 设置系统用户上下文，用于自动操作
     */
    private void setSystemUserContext() {
        try {
            // 获取admin用户信息
            SysUser userAdmin = userMapper.selectUserByUserName("admin");
            if (userAdmin != null) {
                Set<String> permissions = permissionService.getMenuPermission(userAdmin);
                LoginUser loginUser = new LoginUser(userAdmin, permissions);

                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        loginUser,
                        null,
                        loginUser.getAuthorities()
                );

                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception e) {
            log.error("设置系统用户上下文失败", e);
        }
    }
}