package com.zt.plat.module.qms.resource.material.listener;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.security.core.LoginUser;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.framework.web.core.util.WebFrameworkUtils;
import com.zt.plat.module.bpm.api.task.BpmProcessInstanceApi;
import com.zt.plat.module.bpm.api.task.BpmTaskApi;
import com.zt.plat.module.bpm.api.task.dto.*;
import com.zt.plat.module.qms.business.bus.controller.vo.SampleProjectResultDetailReqVO;
import com.zt.plat.module.qms.business.bus.controller.vo.SampleProjectResultDetailRespVO;
import com.zt.plat.module.qms.business.bus.controller.vo.SampleProjectResultPageReqVO;
import com.zt.plat.module.qms.business.bus.controller.vo.SampleProjectResultRespVO;
import com.zt.plat.module.qms.business.bus.service.SampleResultQueryService;
import com.zt.plat.module.qms.enums.QmsCommonConstant;
import com.zt.plat.module.qms.mq.SampleEntrustRegistrationAssayCompleteMessage;
import com.zt.plat.module.qms.resource.material.constant.MaterialConstants;
import com.zt.plat.module.qms.resource.material.controller.vo.assist.MaterialAssayResult;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialCorrelationAssayDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDetailDO;
import com.zt.plat.module.qms.resource.material.service.MaterialCorrelationAssayService;
import com.zt.plat.module.qms.resource.material.service.MaterialLifecycleDetailService;
import com.zt.plat.module.qms.resource.material.service.MaterialLifecycleService;
import com.zt.plat.module.qms.resource.material.utils.BpmnXmlUtil;
import com.zt.plat.module.system.api.user.AdminUserApi;
import com.zt.plat.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Component
// @RequiredArgsConstructor
@RocketMQMessageListener(
        topic = MaterialConstants.MQ_TOPIC_MATERIAL_ACCEPT_ASSAY_COMPLETE,
        consumerGroup = MaterialConstants.MQ_TOPIC_MATERIAL_ACCEPT_ASSAY_COMPLETE + "_CONSUMER"
)
public class MaterialAssayResultListener implements RocketMQListener<SampleEntrustRegistrationAssayCompleteMessage> {

    @Autowired
    private BpmTaskApi bpmTaskApi;

    @Autowired
    private BpmProcessInstanceApi bpmProcessInstanceApi;
    @Autowired
    private AdminUserApi adminUserApi;
    @Autowired
    private MaterialCorrelationAssayService materialCorrelationAssayService;
    @Autowired
    private MaterialLifecycleDetailService materialLifecycleDetailService;
    @Autowired
    private MaterialLifecycleService materialLifecycleService;
    @Autowired
    private SampleResultQueryService sampleResultQueryService;


    @Override
    public void onMessage(SampleEntrustRegistrationAssayCompleteMessage message) {
        log.info("物料验收检验委托完成[消息内容({})]", message);
        if (message == null || message.getBusinessSampleEntrustRegistrationId() == null) return;
        Long entrustId = message.getBusinessSampleEntrustRegistrationId();
        MaterialCorrelationAssayDO assay = materialCorrelationAssayService.getByEntrustId(message.getBusinessSampleEntrustRegistrationId());
        log.info("检验信息:{}", assay);
        if (assay == null) return;
        // 检化验结果
        PageResult<SampleProjectResultRespVO> assayResultPage = sampleResultQueryService.sampleProjectResultQuery(
                new SampleProjectResultPageReqVO().setBusinessSampleEntrustRegistrationId(entrustId));
        List<SampleProjectResultRespVO> asyResults = assayResultPage.getList();
        log.info("检验结果:{}", asyResults);
        if (CollUtil.isEmpty(asyResults)) return;
        // 结果
        SampleProjectResultRespVO oriAsyResult = asyResults.get(0);
        MaterialAssayResult assayResult = BeanUtils.toBean(oriAsyResult, MaterialAssayResult.class);
        // 结果明细
        SampleProjectResultDetailReqVO detailReqVO = new SampleProjectResultDetailReqVO()
                .setBusinessSubParentSampleId(oriAsyResult.getBusinessSubParentSampleId())
                .setConfigAssayMethodProjectId(oriAsyResult.getConfigAssayMethodProjectId());
        List<SampleProjectResultDetailRespVO> asyResultDetail = sampleResultQueryService.sampleProjectResultDetailQuery(detailReqVO);
        log.info("检验结果明细:{}", asyResultDetail);
        assayResult.setDetailList(asyResultDetail);
        assay.setResult(JSONUtil.toJsonStr(assayResult));
        assay.setAssayStatus(QmsCommonConstant.COMPLETED);
        materialCorrelationAssayService.updateById(assay);
        List<MaterialLifecycleDetailDO> detailsByAsyId = materialLifecycleDetailService.getDetailListByAsyId(assay.getId());
        if (CollUtil.isEmpty(detailsByAsyId)) return;
        MaterialLifecycleDO lifecycle = materialLifecycleService.getMaterialLifecycle(detailsByAsyId.get(0).getLifecycleId());
        if (lifecycle == null) return;
        // 检查检化验结果有没有全部出来
        List<MaterialLifecycleDetailDO> detailsByLfcId = materialLifecycleDetailService.getDetailListByLfcId(lifecycle.getId());
        List<Long> asyIds = detailsByLfcId.stream().map(MaterialLifecycleDetailDO::getAssayId)
                .filter(Objects::nonNull).toList();
        List<MaterialCorrelationAssayDO> assays = materialCorrelationAssayService.getListByIds(asyIds);
        if (CollUtil.isEmpty(assays)) return;
        for (MaterialCorrelationAssayDO asy : assays) {
            if (!QmsCommonConstant.COMPLETED.equals(asy.getAssayStatus())) return;
        }
        // 获取到流程id
        String flowId = lifecycle.getFlowInstanceId();
        this.approveTask(flowId);
    }

    public void approveTask(String flowId) {
        // 获取当前节点
        CommonResult<List<BpmTaskRespDTO>> taskListRes = bpmTaskApi.getTaskListByProcessInstanceId(flowId);
        List<BpmTaskRespDTO> taskList = taskListRes.getData();
        if (CollUtil.isEmpty(taskList)) return;
        // List<BpmTaskRespDTO> curTasks = taskList.stream().filter(task -> task.getStatus() != null && task.getStatus() == 1).toList();
        BpmTaskRespDTO curTask = taskList.get(taskList.size() - 1);
        log.info("当前任务：{}", curTask);
        // 检查是否为等待检化验结果节点
        CommonResult<BpmProcessInstanceBpmnModelViewRespDTO> bpmnModelView = bpmProcessInstanceApi.getProcessInstanceBpmnModelView(flowId);
        BpmProcessInstanceBpmnModelViewRespDTO modelView = bpmnModelView.getData();
        if (modelView == null || modelView.getBpmnXml() == null) {
            log.error("流程【{}】BPMN模型为空", flowId);
            return;
        }
        log.debug("流程【{}】BPMN XML: {}", flowId, modelView.getBpmnXml());
        // 解析 BPMN XML，提取节点扩展字段
        Map<String, Map<String, String>> nodeFieldExtensions = BpmnXmlUtil.parseBpmnFieldExtensions(modelView.getBpmnXml());
        log.debug("流程【{}】节点扩展字段：{}", flowId, nodeFieldExtensions);
        // 获取当前节点的扩展字段
        String currentTaskKey = curTask.getTaskDefinitionKey();
        Map<String, String> currentFields = nodeFieldExtensions.get(currentTaskKey);
        log.info("流程【{}】当前节点 {} 的扩展字段：{}", flowId, currentTaskKey, currentFields);
        // 判断当前节点是否为检化验等待节点
        boolean isCurrentNodeWaitAssay = currentFields != null && "1".equals(currentFields.get(MaterialConstants.WAIT_ASSAY_NODE_MARK));
        if (!isCurrentNodeWaitAssay) {
            log.error("流程【{}】当前节点 {} 不是等待检化验结果节点，可能存在未知异常", flowId, currentTaskKey);
            return;
        }
        // 提交当前节点
        log.info("流程【{}】的检化验已全部完成，等待检验结果节点自动执行", flowId);
        // 保存当前登录用户
        LoginUser originalLoginUser = SecurityFrameworkUtils.getLoginUser();
        log.debug("已保存登录用户上下文: user={}", originalLoginUser);
        HttpServletRequest request = WebFrameworkUtils.getRequest();
        try {
            // 当前用户临时切换为任务审批人
            Long assigneeUserId = curTask.getAssignee();
            CommonResult<AdminUserRespDTO> userRes = adminUserApi.getUser(assigneeUserId);
            AdminUserRespDTO user = userRes.getData();
            if (user == null) return;
            LoginUser loginUser = new LoginUser().setId(assigneeUserId)
                    .setInfo(Map.of(
                            LoginUser.INFO_KEY_NICKNAME, user.getNickname(),
                            LoginUser.INFO_KEY_TENANT_ID, String.valueOf(user.getTenantId())))
                    .setExpiresTime(LocalDateTime.now().plusMinutes(10));
            //设置到Spring Security上下文
            Authentication authentication = new UsernamePasswordAuthenticationToken(loginUser, null, Collections.emptyList());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            SecurityFrameworkUtils.setLoginUser(loginUser, WebFrameworkUtils.getRequest());
            log.debug("当前用户临时切换为任务审批人: user={}", loginUser);
            BpmTaskApproveReqDTO reqDTO = new BpmTaskApproveReqDTO().setId(curTask.getId())
                    .setReason("检化验已全部完成，节点自动提交")
                    .setVariables(Map.of(MaterialConstants.ASSAY_RESULT_ALL_OUTPUT, 1));
            CommonResult<Boolean> result = bpmProcessInstanceApi.approveTask(reqDTO);
            if (!result.isSuccess()) {
                log.error("流程【{}】【{}】节点执行失败：{}", flowId, curTask.getName(), result.getMsg());
            } else {
                log.info("流程【{}】【{}】节点执行成功！", flowId, curTask.getName());
            }
        } finally {
            if (originalLoginUser != null) {
                SecurityFrameworkUtils.setLoginUser(originalLoginUser, request);
            } /*else {
                SecurityContextHolder.clearContext();
            }*/
            log.debug("已恢复登录用户上下文: user={}", SecurityFrameworkUtils.getLoginUser());
        }
    }

}
