package cn.iocoder.yudao.module.bpm.service.oa;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.workorder.*;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderAssignRuleDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkOrderTrackDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAWorkOrderAssignRuleMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAWorkOrderMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAWorkOrderTrackMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_WORK_TASK_NOT_EXISTS;

/**
 * BPM OA 工单 Service 实现类
 *
 * @author 系统
 */
@Service
@Validated
public class BpmOAWorkOrderServiceImpl extends BpmOABaseService implements BpmOAWorkOrderService {

    /**
     * 工单对应的流程定义 KEY
     */
    public static final String PROCESS_KEY = "work_order";

    @Resource
    private BpmOAWorkOrderMapper workOrderMapper;

    @Resource
    private BpmOAWorkOrderAssignRuleMapper assignRuleMapper;

    @Resource
    private BpmOAWorkOrderTrackMapper trackMapper;

    @Resource
    private BpmProcessInstanceApi processInstanceApi;

    @Resource
    private AdminUserApi userApi;

    @Resource
    private DeptApi deptApi;

    @Resource
    private DictDataApi dictDataApi;

    private static final String WORK_ORDER_TYPE = "work_order_type";
    private static final String WORK_ORDER_LEVEL = "work_order_level";
    private static final String WORK_ORDER_STATUS = "work_order_status";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createWorkOrder(Long userId, BpmOAWorkOrderCreateReqVO createReqVO) {
        // 获取当前登录用户信息
        AdminUserRespDTO userRespDTO = userApi.getUser(userId).getCheckedData();

        List<UploadUserFile> list = createReqVO.getFileItems();
        // 创建工单DO
        BpmOAWorkOrderDO workOrder = BpmOAWorkOrderDO.builder()
                .title(createReqVO.getTitle())
                .type(createReqVO.getType())
                .level(createReqVO.getLevel())
                .content(createReqVO.getContent())
                .expectedTime(createReqVO.getExpectedTime())
                .fileItems(new ArrayList<>(list))
                .fromUserId(userId)
                .fromDeptId(userRespDTO.getDeptId())
                .status(2) // 默认状态：处理中
                .result(BpmProcessInstanceResultEnum.PROCESS.getResult())
                .build();
        // 自动分配责任人（根据规则）
        autoAssignWorkOrder(workOrder);
        workOrderMapper.insert(workOrder);

        // 发起 BPM 流程
        Map<String, Object> processInstanceVariables = new HashMap<>();
        String processInstanceId = processInstanceApi.createProcessInstance(userId,
                new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
                        .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(workOrder.getId()))).getCheckedData();

        // 更新工单的流程实例ID
        workOrderMapper.updateById(new BpmOAWorkOrderDO().setId(workOrder.getId()).setProcessInstanceId(processInstanceId));

        // 创建初始跟踪记录
        createTrackRecord(workOrder.getId(), userId, userRespDTO.getNickname(), "创建工单", null);

        List<UploadUserFile> fileItems = createReqVO.getFileItems();
        //这里的逻辑，如果fileItems不为空，且有数据，那么说明是上传了附件的，则需要更工作流文件表对应的实例Id
        if (fileItems != null && !fileItems.isEmpty()) {
            uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
        }

        return workOrder.getId();
    }

    @Override
    public void updateWorkOrderResult(Long id, Integer result) {
        validateWorkOrderExists(id);
        // BPM流程完成时，将工单状态设置为已完成
        int status = result.equals(BpmProcessInstanceResultEnum.APPROVE.getResult()) ? 3 : 4; // 3-已完成，4-已取消
        LocalDateTime completedTime = result.equals(BpmProcessInstanceResultEnum.APPROVE.getResult()) ? LocalDateTime.now() : null;

        workOrderMapper.updateById(new BpmOAWorkOrderDO()
                .setId(id)
                .setResult(result)
                .setStatus(status)
                .setCompletedTime(completedTime));
    }

    @Override
    public void assignWorkOrder(Long id, Long assigneeUserId, Long assigneeDeptId) {
        validateWorkOrderExists(id);
        workOrderMapper.updateById(new BpmOAWorkOrderDO()
                .setId(id)
                .setAssigneeUserId(assigneeUserId)
                .setAssigneeDeptId(assigneeDeptId)
                .setStatus(2)); // 2-处理中

        // 创建分配跟踪记录
        AdminUserRespDTO assigneeUser = userApi.getUser(assigneeUserId).getCheckedData();
        createTrackRecord(id, assigneeUserId, assigneeUser.getNickname(), "工单已分配给：" + assigneeUser.getNickname(), null);
    }

    @Override
    public void addTrackInfo(Long userId, BpmOAWorkOrderTrackReqVO trackReqVO) {
        AdminUserRespDTO userRespDTO = userApi.getUser(userId).getCheckedData();
        createTrackRecord(trackReqVO.getWorkOrderId(), userId, userRespDTO.getNickname()
                , trackReqVO.getContent(), null);
    }

    @Override
    public void updateWorkOrder(BpmOAWorkOrderUpdateReqVO updateReqVO) {
        validateWorkOrderExists(updateReqVO.getId());
        BpmOAWorkOrderDO updateData = BpmOAWorkOrderDO.builder()
                .id(updateReqVO.getId())
                .status(updateReqVO.getStatus())
                .result(updateReqVO.getResult())
                .expectedTime(updateReqVO.getExpectedTime())
                .completedTime(updateReqVO.getCompletedTime())
                .resultDescription(updateReqVO.getResultDescription())
                .build();
        workOrderMapper.updateById(updateData);
    }

    @Override
    public BpmOAWorkOrderDO getWorkOrder(Long id) {
        return workOrderMapper.selectById(id);
    }

    @Override
    public BpmOAWorkOrderRespVO getWorkOrderDetail(Long id) {
        BpmOAWorkOrderDO workOrder = validateWorkOrderExists(id);

        // 转换为VO
        BpmOAWorkOrderRespVO respVO = convertToRespVO(workOrder);

        // 获取跟踪记录
        List<BpmOAWorkOrderTrackDO> trackList = trackMapper.selectByWorkOrderId(id);
        List<BpmOAWorkOrderTrackInfo> trackInfoList = trackList.stream()
                .map(this::convertToTrackInfo)
                .collect(Collectors.toList());
        respVO.setTrackInfo(trackInfoList);

        return respVO;
    }

    @Override
    public BpmOAWorkOrderDO getWorkOrderByProcessInstanceId(String processInstanceId) {
        return workOrderMapper.selectOne(BpmOAWorkOrderDO::getProcessInstanceId, processInstanceId);
    }

    @Override
    public PageResult<BpmOAWorkOrderRespVO> getWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
        IPage<BpmOAWorkOrderRespVO> pageResult = workOrderMapper.selectWorkOrderPage(MyBatisUtils.buildPage(pageVO), pageVO.setLoginUserId(loginUserId));
        // 使用XML查询，直接返回带关联信息的VO数据
        return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
    }

    @Override
    public PageResult<BpmOAWorkOrderRespVO> getMyWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
        List<DictDataRespDTO> workOrderTypeDictList = dictDataApi.getDictDataList(WORK_ORDER_TYPE).getCheckedData();
        Map<String, String> workOrderTypeDictMap = workOrderTypeDictList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel));
        List<DictDataRespDTO> workOrderLevelDictList = dictDataApi.getDictDataList(WORK_ORDER_LEVEL).getCheckedData();
        Map<String, String> workOrderLevelDictMap = workOrderLevelDictList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel));
        List<DictDataRespDTO> workOrderStatusDictList = dictDataApi.getDictDataList(WORK_ORDER_STATUS).getCheckedData();
        Map<String, String> workOrderStatusDictMap = workOrderStatusDictList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel));
        PageResult<BpmOAWorkOrderRespVO> bpmOAWorkOrderRespVOPageResult = workOrderMapper.selectMyWorkOrderPage(MyBatisUtils.buildPage(pageVO), pageVO.setLoginUserId(loginUserId));
        for (BpmOAWorkOrderRespVO bpmOAWorkOrderRespVO : bpmOAWorkOrderRespVOPageResult.getList()) {
            bpmOAWorkOrderRespVO.setTypeName(workOrderTypeDictMap.get(bpmOAWorkOrderRespVO.getType()));
            bpmOAWorkOrderRespVO.setLevelName(workOrderLevelDictMap.get(String.valueOf(bpmOAWorkOrderRespVO.getLevel())));
            bpmOAWorkOrderRespVO.setStatusName(workOrderStatusDictMap.get(String.valueOf(bpmOAWorkOrderRespVO.getStatus())));
        }
        // 使用XML查询，直接返回带关联信息的VO数据
        return bpmOAWorkOrderRespVOPageResult;
    }

    @Override
    public PageResult<BpmOAWorkOrderRespVO> getAssignedWorkOrderPage(Long loginUserId, BpmOAWorkOrderPageReqVO pageVO) {
        List<DictDataRespDTO> workOrderTypeDictList = dictDataApi.getDictDataList(WORK_ORDER_TYPE).getCheckedData();
        Map<String, String> workOrderTypeDictMap = workOrderTypeDictList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel));
        List<DictDataRespDTO> workOrderLevelDictList = dictDataApi.getDictDataList(WORK_ORDER_LEVEL).getCheckedData();
        Map<String, String> workOrderLevelDictMap = workOrderLevelDictList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel));
        List<DictDataRespDTO> workOrderStatusDictList = dictDataApi.getDictDataList(WORK_ORDER_STATUS).getCheckedData();
        Map<String, String> workOrderStatusDictMap = workOrderStatusDictList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel));
        IPage<BpmOAWorkOrderRespVO> pageResult = workOrderMapper.selectAssignedWorkOrderPage(MyBatisUtils.buildPage(pageVO), pageVO.setLoginUserId(loginUserId));
        PageResult<BpmOAWorkOrderRespVO> bpmOAWorkOrderRespVOPageResult =
                pageResult != null ? new PageResult<>(pageResult.getRecords(), pageResult.getTotal()) : new PageResult<>();
        for (BpmOAWorkOrderRespVO bpmOAWorkOrderRespVO : bpmOAWorkOrderRespVOPageResult.getList()) {
            bpmOAWorkOrderRespVO.setTypeName(workOrderTypeDictMap.get(bpmOAWorkOrderRespVO.getType()));
            bpmOAWorkOrderRespVO.setLevelName(workOrderLevelDictMap.get(String.valueOf(bpmOAWorkOrderRespVO.getLevel())));
            bpmOAWorkOrderRespVO.setStatusName(workOrderStatusDictMap.get(String.valueOf(bpmOAWorkOrderRespVO.getStatus())));
        }
        // 使用XML查询，直接返回带关联信息的VO数据
        return bpmOAWorkOrderRespVOPageResult;
    }

    @Override
    public Long getMyAssignedWorkOrderCount(Long userId) {
        return workOrderMapper.selectMyAssignedCount(userId);
    }

    @Override
    public PageResult<BpmOAWorkOrderTrackInfo> getTrackPage(BpmOAWorkOrderTrackReqDTO dto) {
        PageResult<BpmOAWorkOrderTrackDO> pageResult = trackMapper.selectPage(new PageParam().setPageSize(dto.getPageSize()).setPageNo(dto.getPageNo()),
                new LambdaQueryWrapper<BpmOAWorkOrderTrackDO>()
                        .eq(dto.getWorkOrderId() != null, BpmOAWorkOrderTrackDO::getWorkOrderId, dto.getWorkOrderId()));
        return new PageResult<>(pageResult.getList().stream().map(this::convertToTrackInfo).collect(Collectors.toList()), pageResult.getTotal());
    }

    /**
     * 创建跟踪记录
     */
    private void createTrackRecord(Long workOrderId, Long operatorId, String operatorName, String content, String attachments) {
        BpmOAWorkOrderTrackDO track = BpmOAWorkOrderTrackDO.builder()
                .workOrderId(workOrderId)
                .operatorId(operatorId)
                .operatorName(operatorName)
                .content(content)
                .attachments(attachments)
                .build();
        trackMapper.insert(track);
    }

    /**
     * 自动分配工单责任人
     */
    private void autoAssignWorkOrder(BpmOAWorkOrderDO workOrder) {
        // 根据工单类型查询分配规则
        List<BpmOAWorkOrderAssignRuleDO> rules = assignRuleMapper.selectRulesByType(workOrder.getType());

        if (!rules.isEmpty()) {
            // 选择第一个匹配的规则（按优先级排序）
            BpmOAWorkOrderAssignRuleDO rule = rules.get(0);
            workOrder.setAssigneeUserId(rule.getAssigneeUserId());
            workOrder.setAssigneeDeptId(rule.getDeptId());
            workOrder.setStatus(2); // 2-处理中
        }
        // 如果没有匹配的规则，保持待分配状态
    }

    /**
     * 校验工单是否存在
     */
    private BpmOAWorkOrderDO validateWorkOrderExists(Long id) {
        BpmOAWorkOrderDO workOrder = workOrderMapper.selectById(id);
        if (workOrder == null) {
            throw exception(OA_WORK_TASK_NOT_EXISTS); // 暂时复用现有错误码
        }
        return workOrder;
    }

    /**
     * 上传BPM文件流程实例ID
     * 重写父类方法，使用父类的实现
     */
    @Override
    public void uploadBpmFileProcessInstanceId(String processInstanceId, List<UploadUserFile> fileItems) {
        super.uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
    }

    /**
     * 转换DO为RespVO
     */
    private BpmOAWorkOrderRespVO convertToRespVO(BpmOAWorkOrderDO workOrder) {
        if (workOrder == null) {
            return null;
        }

        BpmOAWorkOrderRespVO respVO = new BpmOAWorkOrderRespVO();
        respVO.setId(workOrder.getId());
        respVO.setTitle(workOrder.getTitle());
        respVO.setType(workOrder.getType());
        respVO.setLevel(workOrder.getLevel());
        respVO.setContent(workOrder.getContent());
        respVO.setFromUserId(workOrder.getFromUserId());
        respVO.setFromDeptId(workOrder.getFromDeptId());
        respVO.setAssigneeUserId(workOrder.getAssigneeUserId());
        respVO.setAssigneeDeptId(workOrder.getAssigneeDeptId());
        respVO.setStatus(workOrder.getStatus());
        respVO.setExpectedTime(workOrder.getExpectedTime());
        respVO.setCompletedTime(workOrder.getCompletedTime());
        respVO.setResultDescription(workOrder.getResultDescription());
        respVO.setResult(workOrder.getResult());
        respVO.setProcessInstanceId(workOrder.getProcessInstanceId());
        respVO.setCreateTime(workOrder.getCreateTime());
        respVO.setUpdateTime(workOrder.getUpdateTime());
        respVO.setFileItems(workOrder.getFileItems());
        // 设置类型名称
        respVO.setTypeName(getWorkOrderTypeName(workOrder.getType()));

        // 设置优先级名称
        respVO.setLevelName(getWorkOrderLevelName(workOrder.getLevel()));

        // 设置状态名称
        respVO.setStatusName(getWorkOrderStatusName(workOrder.getStatus()));

        // 获取用户和部门名称
        if (workOrder.getFromUserId() != null) {
            AdminUserRespDTO fromUser = userApi.getUser(workOrder.getFromUserId()).getCheckedData();
            respVO.setFromUserName(fromUser.getNickname());
        }

        if (workOrder.getAssigneeUserId() != null) {
            AdminUserRespDTO assigneeUser = userApi.getUser(workOrder.getAssigneeUserId()).getCheckedData();
            respVO.setAssigneeUserName(assigneeUser.getNickname());
        }

        if (workOrder.getFromDeptId() != null) {
            DeptRespDTO fromDept = deptApi.getDept(workOrder.getFromDeptId()).getCheckedData();
            respVO.setFromDeptName(fromDept.getName());
        }

        if (workOrder.getAssigneeDeptId() != null) {
            DeptRespDTO assigneeDept = deptApi.getDept(workOrder.getAssigneeDeptId()).getCheckedData();
            respVO.setAssigneeDeptName(assigneeDept.getName());
        }

        return respVO;
    }

    /**
     * 转换跟踪记录DO为TrackInfo
     */
    private BpmOAWorkOrderTrackInfo convertToTrackInfo(BpmOAWorkOrderTrackDO trackDO) {
        if (trackDO == null) {
            return null;
        }

        BpmOAWorkOrderTrackInfo trackInfo = new BpmOAWorkOrderTrackInfo();
        trackInfo.setTrackId(String.valueOf(trackDO.getId()));
        trackInfo.setOperatorId(trackDO.getOperatorId());
        trackInfo.setOperatorName(trackDO.getOperatorName());
        trackInfo.setContent(trackDO.getContent());
        trackInfo.setTrackTime(trackDO.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        return trackInfo;
    }

    /**
     * 转换分页结果
     */
    private PageResult<BpmOAWorkOrderRespVO> convertToPageResult(PageResult<BpmOAWorkOrderDO> pageResult) {
        if (pageResult == null || pageResult.getList() == null) {
            return new PageResult<>();
        }

        List<BpmOAWorkOrderRespVO> respList = pageResult.getList().stream()
                .map(this::convertToRespVO)
                .collect(Collectors.toList());

        return new PageResult<>(respList, pageResult.getTotal());
    }

    /**
     * 获取工单类型名称
     */
    private String getWorkOrderTypeName(String type) {
        if (type == null) {
            return "";
        }
        try {
            DictDataRespDTO dictData = dictDataApi.getDictData("work_order_type", type).getCheckedData();
            return dictData != null ? dictData.getLabel() : type;
        } catch (Exception e) {
            // 如果字典查询失败，返回原值
            return type;
        }
    }

    /**
     * 获取工单优先级名称
     */
    private String getWorkOrderLevelName(Integer level) {
        if (level == null) {
            return "";
        }
        try {
            DictDataRespDTO dictData = dictDataApi.getDictData("work_order_level", String.valueOf(level)).getCheckedData();
            return dictData != null ? dictData.getLabel() : String.valueOf(level);
        } catch (Exception e) {
            // 如果字典查询失败，返回原值
            return String.valueOf(level);
        }
    }

    /**
     * 获取工单状态名称
     */
    private String getWorkOrderStatusName(Integer status) {
        if (status == null) {
            return "";
        }
        try {
            DictDataRespDTO dictData = dictDataApi.getDictData("work_order_status", String.valueOf(status)).getCheckedData();
            return dictData != null ? dictData.getLabel() : String.valueOf(status);
        } catch (Exception e) {
            // 如果字典查询失败，返回原值
            return String.valueOf(status);
        }
    }

}
