package com.bonus.material.approval.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.bonus.common.biz.enums.ApproveModeEnum;
import com.bonus.common.biz.enums.ApprovalResultEnum;
import com.bonus.common.biz.enums.ApprovalStatusEnum;
import com.bonus.common.biz.enums.ApproverTypeEnum;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.material.approval.domain.ApprovalInstance;
import com.bonus.material.approval.domain.ApprovalNode;
import com.bonus.material.approval.domain.ApprovalProcess;
import com.bonus.material.approval.domain.ApprovalRecord;
import com.bonus.material.approval.mapper.ApprovalInstanceMapper;
import com.bonus.material.approval.mapper.ApprovalNodeMapper;
import com.bonus.material.approval.mapper.ApprovalProcessMapper;
import com.bonus.material.approval.mapper.ApprovalRecordMapper;
import com.bonus.material.approval.service.IApprovalEngineService;
import com.bonus.material.approval.strategy.IApprovalCallback;
import com.bonus.system.api.domain.SysRole;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 审批引擎服务实现
 * 
 * @author syruan
 */
@Service
public class ApprovalEngineServiceImpl implements IApprovalEngineService {

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

    @Resource
    private ApprovalProcessMapper processMapper;

    @Resource
    private ApprovalNodeMapper nodeMapper;

    @Resource
    private ApprovalInstanceMapper instanceMapper;

    @Resource
    private ApprovalRecordMapper recordMapper;

    /**
     * 审批回调处理器Map（业务类型 -> 回调处理器）
     */
    @Resource
    private Map<String, IApprovalCallback> callbackMap;

    @Override
    public boolean needApproval(String businessType) {
        ApprovalProcess process = processMapper.selectProcessByBusinessType(businessType);
        return process != null && "1".equals(process.getStatus());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApprovalInstance createApprovalInstance(String businessType, String businessId, String businessData) {
        // 调用新的方法，orgId 为 null（使用默认流程）
        Long orgId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        return createApprovalInstance(businessType, businessId, businessData, orgId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApprovalInstance createApprovalInstance(String businessType, String businessId, String businessData, Long orgId) {
        // 1. 查询审批流程配置
        ApprovalProcess process;
        if (orgId != null) {
            // 按组织机构查询
            process = processMapper.selectProcessByBusinessTypeAndOrgId(businessType, orgId);
            if (process == null) {
                // 按业务类型查询（兼容旧逻辑）
                process = processMapper.selectProcessByBusinessType(businessType);
            }
        } else {
            // 按业务类型查询（兼容旧逻辑）
            process = processMapper.selectProcessByBusinessType(businessType);
        }

        if (process == null) {
            throw new ServiceException("未找到业务类型[" + businessType + "]的审批流程配置");
        }
        if (!"1".equals(process.getStatus())) {
            throw new ServiceException("审批流程已停用");
        }

        // 2. 查询第一个审批节点
        ApprovalNode firstNode = nodeMapper.selectNodeByOrder(process.getId(), 1);
        if (firstNode == null) {
            throw new ServiceException("审批流程未配置审批节点");
        }

        // 3. 创建审批实例
        ApprovalInstance instance = new ApprovalInstance();
        instance.setInstanceCode(generateInstanceCode());
        instance.setProcessId(process.getId());
        instance.setBusinessType(businessType);
        instance.setBusinessId(businessId);
        instance.setBusinessData(businessData);
        instance.setCurrentNodeId(firstNode.getId());
        instance.setCurrentNodeOrder(1);
        instance.setStatus(ApprovalStatusEnum.PENDING.getCode());
        instance.setApplyUserId(SecurityUtils.getUserId());
        instance.setApplyUserName(SecurityUtils.getUsername());
        instance.setApplyTime(new Date());

        instanceMapper.insertInstance(instance);

        log.info("创建审批实例成功，实例编号：{}，业务类型：{}，业务ID：{}", instance.getInstanceCode(), businessType, businessId);

        // 4. 检查第一个节点是否自动通过
        if ("1".equals(firstNode.getAutoPass())) {
            log.info("第一个节点[{}]设置为自动通过，开始自动审批", firstNode.getNodeName());

            // 创建自动审批记录
            ApprovalRecord autoRecord = getAutoRecord(instance, firstNode);
            recordMapper.insertRecord(autoRecord);

            log.info("第一个节点[{}]自动审批完成，继续流转", firstNode.getNodeName());

            // 处理通过逻辑（会自动流转到下一个节点）
            handlePass(instance, firstNode);
        }

        return instance;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult doApprove(Long instanceId, String approveResult, String approveOpinion) {
        // 1. 校验参数
        if (!ApprovalResultEnum.PASS.getCode().equals(approveResult) 
                && !ApprovalResultEnum.REJECT.getCode().equals(approveResult)) {
            return AjaxResult.error("审批结果参数错误");
        }

        // 2. 查询审批实例
        ApprovalInstance instance = instanceMapper.selectInstanceById(instanceId);
        if (instance == null) {
            return AjaxResult.error("审批实例不存在");
        }

        // 3. 校验实例状态
        if (!ApprovalStatusEnum.PENDING.getCode().equals(instance.getStatus())
                && !ApprovalStatusEnum.IN_PROGRESS.getCode().equals(instance.getStatus())) {
            return AjaxResult.error("该审批已完成，无法再次审批");
        }

        // 4. 查询当前节点
        ApprovalNode currentNode = nodeMapper.selectNodeById(instance.getCurrentNodeId());
        if (currentNode == null) {
            return AjaxResult.error("审批节点不存在");
        }

        // 5. 校验审批人权限
        Long userId = SecurityUtils.getUserId();
        if (!checkApproverPermission(currentNode, userId)) {
            return AjaxResult.error("您没有权限审批该节点");
        }

        // 6. 检查是否已审批过
        ApprovalRecord existRecord = recordMapper.selectRecordByApprover(instanceId, currentNode.getId(), userId);
        if (existRecord != null) {
            return AjaxResult.error("您已审批过该节点，无法重复审批");
        }

        // 7. 记录审批操作
        ApprovalRecord record = new ApprovalRecord();
        record.setInstanceId(instanceId);
        record.setNodeId(currentNode.getId());
        record.setNodeName(currentNode.getNodeName());
        record.setNodeOrder(currentNode.getNodeOrder());
        record.setApproverId(userId);
        record.setApproverName(SecurityUtils.getUsername());
        record.setApproveResult(approveResult);
        record.setApproveOpinion(approveOpinion);
        record.setApproveTime(new Date());
        recordMapper.insertRecord(record);

        // 8. 处理审批结果
        return handleApprovalResult(instance, currentNode, approveResult);
    }

    @Override
    public ApprovalInstance getApprovalDetail(Long instanceId) {
        ApprovalInstance instance = instanceMapper.selectInstanceById(instanceId);
        if (instance != null) {
            // 查询审批记录
            List<ApprovalRecord> recordList = recordMapper.selectRecordListByInstanceId(instanceId);
            instance.setRecordList(recordList);
        }
        return instance;
    }

    /**
     * 处理审批结果
     */
    private AjaxResult handleApprovalResult(ApprovalInstance instance, ApprovalNode currentNode, String approveResult) {
        // 驳回处理
        if (ApprovalResultEnum.REJECT.getCode().equals(approveResult)) {
            return handleReject(instance);
        }

        // 通过处理 - 判断是否需要等待其他审批人（会签模式）
        if (ApproveModeEnum.AND_SIGN.getCode().equals(currentNode.getApproveMode())) {
            // 会签模式：需要所有审批人都通过
            int passedCount = recordMapper.countPassedByNode(instance.getId(), currentNode.getId());
            int totalApprovers = getTotalApprovers(currentNode);

            if (passedCount < totalApprovers) {
                // 还有其他审批人未审批，更新实例状态为审批中
                instanceMapper.updateInstanceStatus(instance.getId(), ApprovalStatusEnum.IN_PROGRESS.getCode());
                log.info("会签节点[{}]审批通过，等待其他审批人，当前进度：{}/{}",
                        currentNode.getNodeName(), passedCount, totalApprovers);
                return AjaxResult.success("审批成功，等待其他审批人");
            }
        }

        // 或签模式 或 会签已全部通过：流转到下一节点
        return handlePass(instance, currentNode);
    }

    /**
     * 处理驳回
     */
    private AjaxResult handleReject(ApprovalInstance instance) {
        // 更新实例状态为已驳回
        instanceMapper.updateInstanceStatus(instance.getId(), ApprovalStatusEnum.REJECTED.getCode());

        log.info("审批实例[{}]被驳回", instance.getInstanceCode());

        // 执行驳回回调
        executeCallback(instance, ApprovalStatusEnum.REJECTED.getCode());

        return AjaxResult.success("审批驳回成功");
    }

    /**
     * 处理通过
     */
    private AjaxResult handlePass(ApprovalInstance instance, ApprovalNode currentNode) {
        // 查询下一个节点
        ApprovalNode nextNode = nodeMapper.selectNodeByOrder(instance.getProcessId(), currentNode.getNodeOrder() + 1);

        if (nextNode == null) {
            // 没有下一个节点，审批流程结束
            instanceMapper.updateInstanceStatus(instance.getId(), ApprovalStatusEnum.APPROVED.getCode());
            log.info("审批实例[{}]审批通过", instance.getInstanceCode());

            // 执行通过回调
            executeCallback(instance, ApprovalStatusEnum.APPROVED.getCode());
            return AjaxResult.success("审批通过，流程结束");
        } else {
            // 流转到下一个节点
            instanceMapper.updateCurrentNode(instance.getId(), nextNode.getId(), nextNode.getNodeOrder());
            instanceMapper.updateInstanceStatus(instance.getId(), ApprovalStatusEnum.IN_PROGRESS.getCode());

            log.info("审批实例[{}]流转到下一节点[{}]", instance.getInstanceCode(), nextNode.getNodeName());
            // 检查下一个节点是否自动通过
            log.info("节点[{}]的autoPass值为：[{}]", nextNode.getNodeName(), nextNode.getAutoPass());

            if ("1".equals(nextNode.getAutoPass())) {
                log.info("节点[{}]设置为自动通过，开始自动审批", nextNode.getNodeName());

                // 创建自动审批记录
                ApprovalRecord autoRecord = getAutoRecord(instance, nextNode);
                recordMapper.insertRecord(autoRecord);

                log.info("节点[{}]自动审批完成，继续流转", nextNode.getNodeName());

                // 递归处理下一个节点
                return handlePass(instance, nextNode);
            }

            return AjaxResult.success("审批通过，已流转到下一节点：" + nextNode.getNodeName());
        }
    }

    /**
     * 创建自动审批记录
     */
    private static ApprovalRecord getAutoRecord(ApprovalInstance instance, ApprovalNode nextNode) {
        ApprovalRecord autoRecord = new ApprovalRecord();
        autoRecord.setInstanceId(instance.getId());
        autoRecord.setNodeId(nextNode.getId());
        autoRecord.setNodeName(nextNode.getNodeName());
        autoRecord.setNodeOrder(nextNode.getNodeOrder());
        autoRecord.setApproverId(0L);  // 系统自动审批
        autoRecord.setApproverName("系统自动审批");
        autoRecord.setApproveResult(ApprovalResultEnum.PASS.getCode());
        autoRecord.setApproveOpinion("自动通过");
        autoRecord.setApproveTime(new Date());
        return autoRecord;
    }

    /**
     * 校验审批人权限
     */
    private boolean checkApproverPermission(ApprovalNode node, Long userId) {
        if (StrUtil.isBlank(node.getApproverIds())) {
            return false;
        }

        String[] approverIds = node.getApproverIds().split(",");

        if (ApproverTypeEnum.USER.getCode().equals(node.getApproverType())) {
            // 用户类型：直接匹配用户ID
            return Arrays.asList(approverIds).contains(String.valueOf(userId));
        } else if (ApproverTypeEnum.ROLE.getCode().equals(node.getApproverType())) {
            // 角色类型：匹配用户的角色
            List<Long> userRoleIds = SecurityUtils.getLoginUser().getSysUser().getRoles()
                    .stream()
                    .map(SysRole::getRoleId)
                    .collect(Collectors.toList());

            for (String roleId : approverIds) {
                if (userRoleIds.contains(Long.valueOf(roleId))) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 获取节点审批人总数
     */
    private int getTotalApprovers(ApprovalNode node) {
        if (StrUtil.isBlank(node.getApproverIds())) {
            return 0;
        }
        return node.getApproverIds().split(",").length;
    }

    /**
     * 执行审批回调
     * 注意：如果回调执行失败，会抛出异常，触发事务回滚
     */
    private void executeCallback(ApprovalInstance instance, String status) {
        try {
            IApprovalCallback callback = callbackMap.get(instance.getBusinessType());
            if (callback != null) {
                if (ApprovalStatusEnum.APPROVED.getCode().equals(status)) {
                    callback.onApproved(instance);
                } else if (ApprovalStatusEnum.REJECTED.getCode().equals(status)) {
                    callback.onRejected(instance);
                }
            }
        } catch (Exception e) {
            log.error("执行审批回调失败，实例编号：{}，业务类型：{}", instance.getInstanceCode(), instance.getBusinessType(), e);
            // 重新抛出异常，触发事务回滚
            throw new RuntimeException("审批回调执行失败：" + e.getMessage(), e);
        }
    }

    /**
     * 生成审批实例编号
     */
    private String generateInstanceCode() {
        return "AP" + System.currentTimeMillis() + (int)(Math.random() * 1000);
    }
}
