package com.yeejoin.amos.boot.module.jg.biz.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.map.MapBuilder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.controller.BaseController;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.boot.module.jg.api.dto.InstanceRuntimeData;
import com.yeejoin.amos.boot.module.jg.api.dto.JgCertificateReplenishDto;
import com.yeejoin.amos.boot.module.jg.api.dto.JgCertificateReplenishDto;
import com.yeejoin.amos.boot.module.jg.api.dto.WorkflowResultDto;
import com.yeejoin.amos.boot.module.jg.api.entity.*;
import com.yeejoin.amos.boot.module.jg.api.enums.BusinessTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.enums.CompanyTypeEnum;
import com.yeejoin.amos.boot.module.jg.api.mapper.JgCertificateReplenishMapper;
import com.yeejoin.amos.boot.module.jg.api.service.IJgCertificateReplenishService;
import com.yeejoin.amos.boot.module.jg.biz.context.EquipUsedCheckStrategyContext;
import com.yeejoin.amos.boot.module.jg.biz.feign.TzsServiceFeignClient;
import com.yeejoin.amos.boot.module.jg.biz.utils.FileExporter;
import com.yeejoin.amos.boot.module.ymt.api.entity.*;
import com.yeejoin.amos.boot.module.ymt.api.enums.ApplicationFormTypeEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.feign.workflow.model.ProcessTaskDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.rdbms.service.BaseService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 使用登记表补证服务实现类
 *
 * @author system_generator
 * @date 2025-03-19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class JgCertificateReplenishServiceImpl extends BaseService<JgCertificateReplenishDto, JgCertificateReplenish, JgCertificateReplenishMapper> implements IJgCertificateReplenishService {
    public static final String IDX_BIZ_VIEW_JG_ALL = "idx_biz_view_jg_all";
    public static final String equUseAddress = "equUseAddress";
    public static final String useRegistrationCode = "useRegistrationCode";
    public static final String USE_ORG_CODE = "USE_ORG_CODE";
    public static final String STATUS = "STATUS";
    public static final String record = "record";
    public static final String SEQUENCE_NBR = "SEQUENCE_NBR";
    public static final String FORM_DATA = "formData";
    public static final String EQU_LISTS = "equLists";
    private final List<String> NOT_FLOWING_STATE = Arrays.asList("6610", "6614", "6615", "6617", "6616");
    private static final String EQUIP_TRANSFER_PROCESS_KEY = "certificateReplenish";
    private final Map<String, Supplier> actionMap = new HashMap<>();
    /**
     * 通过
     */
    public static final String APPROVED = "APPROVED";
    /**
     * 驳回
     */
    public static final String REJECTED = "REJECTED";
    /**
     * 提交
     */
    public static final String SUBMITTED = "SUBMITTED";
    /**
     * 暂存
     */
    public static final String DRAFT = "DRAFT";
    ;
    /**
     * 是否要提交 true :提交进入审批 false：暂存单据
     */
    public static final String SHOULD_SUBMIT = "SHOULD_SUBMIT";
    private final CommonServiceImpl commonService;
    private final JgUseRegistrationManageServiceImpl registrationManageService;
    private final TzsServiceFeignClient tzsServiceFeignClient;
    private final RedisUtils redisUtils;
    private final RedissonClient redissonClient;
    private final CmWorkflowServiceImpl cmWorkflowService;
    private final JgCertificateReplenishEqServiceImpl certificateReplenishEqService;

    /**
     * 用户信息
     **/
    protected ReginParams getSelectedOrgInfo() {
        return JSONObject.parseObject(redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken())).toString(), ReginParams.class);
    }

    @PostConstruct
    public void init() {
        actionMap.put(APPROVED, () -> this.approved());
        actionMap.put(REJECTED, () -> this.rejected());
        actionMap.put(SUBMITTED, () -> this.submitted());
        actionMap.put(DRAFT, () -> this.draft());
    }


    public Object rejected() {
        return null;
    }

    public Object approved() {
        return null;
    }

    /**
     * 发起补证申请
     *
     * @param jsonObject
     * @return
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    public List<Map<String, Object>> save(JSONObject jsonObject) {
        JgCertificateReplenishDto model = JSON.parseObject(JSONObject.toJSONString(jsonObject), JgCertificateReplenishDto.class);
        List<Map<String, Object>> equLists = model.getEquLists();


        // 创建历史数据
        // this.saveOrUpdateHisDataBatch();
        return null;
    }

    public Object draft() {
        return null;
    }

    public Object submitted() {
        return null;
    }

    public void saveOrUpdateHisDataBatch(List<JgEquipTransfer> transferList, List<JgEquipTransferEq> jgEquipTransferEqList) {
        // commonService.saveOrUpdateHistory(BusinessTypeEnum.JG_REPLACEMENT_REGISTRATION.getName(), getEquipInfoJson(j.getEquId()), j.getEquId(), j.getEquipTransferId());
    }

    /**
     * 分页查询
     */
    public Page<JgCertificateReplenish> queryForJgCertificateReplenishPage(Page<JgCertificateReplenish> page, JgCertificateReplenishDto dto) {
        CompanyBo company = getSelectedOrgInfo().getCompany();
        boolean isCompany = company.getLevel().equals(BaseController.COMPANY_TYPE_COMPANY);
        boolean isSupervision = company.getLevel().equals(BaseController.COMPANY_TYPE_SUPERVISION);
        String useUnitCode = "";
        if (isCompany) {
            useUnitCode = CompanyTypeEnum.INDIVIDUAL.getName().equals(company.getCompanyType()) ?
                    company.getCompanyCode().split("_")[1] : company.getCompanyCode();
        }
        Page<JgCertificateReplenish> result = new Page<>();
        IPage<JgCertificateReplenish> replenishIPage = this.lambdaQuery()
                // 监管
                .eq(isSupervision, JgCertificateReplenish::getReceiveOrgCode, company.getCompanyCode())
                // 非监管
                .eq(isCompany, JgCertificateReplenish::getUseUnitCode, useUnitCode)
                .eq(JgCertificateReplenish::getIsDelete, Boolean.FALSE)
                .eq(!ValidationUtil.isEmpty(dto.getUseRegistrationCode()), JgCertificateReplenish::getUseRegistrationCode, dto.getUseRegistrationCode())
                .eq(!ValidationUtil.isEmpty(dto.getEquListCode()), JgCertificateReplenish::getEquListCode, dto.getEquListCode())
                .eq(!ValidationUtil.isEmpty(dto.getApplyNo()), JgCertificateReplenish::getApplyNo, dto.getApplyNo())
                .eq(!ValidationUtil.isEmpty(dto.getApplyStatus()), JgCertificateReplenish::getApplyStatus, dto.getApplyStatus())
                .eq(!ValidationUtil.isEmpty(dto.getUseUnitCode()), JgCertificateReplenish::getUseUnitCode, dto.getUseUnitCode())
                .eq(!ValidationUtil.isEmpty(dto.getApplicationReason()), JgCertificateReplenish::getApplicationReason, dto.getApplicationReason())
                .eq(!ValidationUtil.isEmpty(dto.getLossDamageTime()), JgCertificateReplenish::getLossDamageTime, dto.getLossDamageTime())
                .eq(!ValidationUtil.isEmpty(dto.getInstanceStatus()), JgCertificateReplenish::getInstanceStatus, dto.getInstanceStatus())
                .eq(!ValidationUtil.isEmpty(dto.getAcceptDate()), JgCertificateReplenish::getAcceptDate, dto.getAcceptDate())
                .page(page);
        result.setRecords(replenishIPage.getRecords());
        result.setTotal(replenishIPage.getTotal());
        return result;
    }

    /**
     * 补证申请表生成
     *
     * @param jsonObject
     * @return
     */
    @Override
    public Map<String, Object> getCertReplenishFormUrl(JSONObject jsonObject) {
        // 生成申请编号
        String applyNo = "";
        ResponseModel<List<String>> listResponseModel = tzsServiceFeignClient.applicationFormCode(ApplicationFormTypeEnum.BZDJ.getCode(), 1);
        if (!listResponseModel.getResult().isEmpty()) {
            applyNo = listResponseModel.getResult().get(0);
        }
        JSONObject formData = this.writeCertReplenishFormData(jsonObject.getJSONObject(FORM_DATA), applyNo);
        String wordPath = "CertificateReplenish.ftl";
        String fileName = "使用登记证补证申请表_";
        File pdfFile = null;
        try {
            pdfFile = commonService.wordToPdf(fileName, wordPath, formData);
            return MapBuilder.<String, Object>create()
                    .put("certReplenishFormUrl", commonService.uploadFile(pdfFile, "certificateReplenishFiles"))
                    .put("applyNo", applyNo)
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                assert pdfFile != null;
                Files.deleteIfExists(pdfFile.toPath());
            } catch (Exception e) {
                log.error("文件找不到，删除失败：{}", e);
            }
        }
    }

    /**
     * 补证pdf流生成
     *
     * @param jsonObject
     * @param response
     */
    @Override
    public void getCertReplenishFormStream(JSONObject jsonObject, HttpServletResponse response) {
        JSONObject formData = this.writeCertReplenishFormData(jsonObject, "");
        String wordPath = "CertificateReplenish.ftl";
        String fileName = "使用登记证补证申请表_";
        File pdfFile;
        try {
            pdfFile = commonService.wordToPdf(fileName, wordPath, formData);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            byte[] bytes = CommonServiceImpl.file2byte(pdfFile);
            String docTitle = pdfFile.getName();
            FileExporter.exportFile(FileExporter.FileType.valueOf("pdf"), docTitle, bytes, response);
        } catch (Exception e) {
            log.error("pdf文件转换失败：{}", e);
        } finally {
            try {
                Files.deleteIfExists(pdfFile.toPath());
            } catch (Exception e) {
                log.error("文件找不到，删除失败：{}", e);
            }
        }
    }

    private JSONObject writeCertReplenishFormData(JSONObject jsonObject, String applyNo) {
        JSONArray equLists = jsonObject.getJSONArray(EQU_LISTS);
        JSONObject result = new JSONObject();
        result.put("applyNo", applyNo);
        result.put("useUnitName", jsonObject.getString("useUnitName"));
        result.put("equUseAddress", jsonObject.getString("equUseAddress"));
        result.put("applicationReason", jsonObject.getString("applicationReason"));
        result.put("lossDamageTime", jsonObject.getString("lossDamageTime"));
        result.put("safetyManagerName", jsonObject.getString("safetyManagerId").split("_")[1]);
        result.put("safetyManagerPhone", jsonObject.getString("safetyManagerPhone"));
        JSONArray equListsAfterAssembly = new JSONArray();
        for (int i = 0; i < equLists.size(); i++) {
            JSONObject item = equLists.getJSONObject(i);
            equListsAfterAssembly.add(MapBuilder.<String, Object>create()
                                              .put("index", i + 1)
                                              .put("productName", item.getString("PRODUCT_NAME"))
                                              .put("equCode", item.getString("EQU_CODE"))
                                              .put("useRegistrationCode", item.getString("USE_ORG_CODE"))
                                              .put("factoryNum", item.getString("FACTORY_NUM"))
                                              .build());
        }
        result.put(EQU_LISTS, equListsAfterAssembly);
        result.put("handler", getSelectedOrgInfo().getUserModel().getRealName());
        result.put("applicationDateYear", DateTime.now().year());
        result.put("applicationDateMonth", DateTime.now().month());
        result.put("applicationDateDay", DateTime.now().dayOfMonth());
        return result;
    }

    /**
     * 根据证的sequenceNbr 批量查询证下面的所有设备
     *
     * @param sequenceNbr
     * @return
     */
    public Map<String, Object> queryEquByCertSeq(String sequenceNbr) {
        JgUseRegistrationManage registrationManage = registrationManageService.getBaseMapper().selectOne(new LambdaQueryWrapper<JgUseRegistrationManage>().eq(JgUseRegistrationManage::getSequenceNbr, sequenceNbr).eq(JgUseRegistrationManage::getIsDelete, 0).select(JgUseRegistrationManage::getUseRegistrationCode, JgUseRegistrationManage::getEquUseAddress));
        HashMap<String, Object> result = new HashMap<>();
        if (ValidationUtil.isEmpty(registrationManage)) {
            return result;
        }
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(USE_ORG_CODE, registrationManage.getUseRegistrationCode());
        boolQuery.must(termQueryBuilder);
        BoolQueryBuilder meBuilder = QueryBuilders.boolQuery();
        meBuilder.should(QueryBuilders.matchQuery(STATUS, "已认领"));
        meBuilder.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery(STATUS)));
        meBuilder.should(QueryBuilders.boolQuery().must(QueryBuilders.matchPhraseQuery(STATUS, "")));
        meBuilder.minimumShouldMatch(1);
        boolQuery.must(meBuilder);
        List<JSONObject> equipmentLists = Collections.emptyList();
        try {
            equipmentLists = registrationManageService.searchResponse(IDX_BIZ_VIEW_JG_ALL, boolQuery, hit -> JSONObject.parseObject(hit.getSourceAsString(), JSONObject.class)).stream().map(item -> {
                JSONObject newItem = new JSONObject(item);
                newItem.put(record, Objects.toString(newItem.get(SEQUENCE_NBR), ""));
                return newItem;
            }).collect(Collectors.toList());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        result.put(EQU_LISTS, equipmentLists);
        result.put(useRegistrationCode, registrationManage.getUseRegistrationCode());
        result.put(equUseAddress, registrationManage.getEquUseAddress());
        return result;
    }

    /**
     * 撤回
     *
     * @param dto
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    public void cancel(JgCertificateReplenishDto dto) {
        String instanceId = dto.getInstanceId();
        String nextTaskId = dto.getNextTaskId();
        String lockKey = CommonServiceImpl.buildJgExecuteLockKey(instanceId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean isLocked = lock.tryLock(0, 180, TimeUnit.SECONDS);
            if (!isLocked) {
                throw new BadRequest("当前流程已经被执行！请重新打开页面查看并执行！");
            }
            // 流程执行时，状态及权限校验
            commonService.checkForRevocationFlow(nextTaskId, instanceId);
            JgCertificateReplenish certRep = baseMapper.selectById(dto.getSequenceNbr());
            // 回滚工作流
            ProcessTaskDTO processTaskDTO = cmWorkflowService.rollBack(dto.getInstanceId());
            WorkflowResultDto workflowResultDto = commonService.buildWorkFlowInfo(Collections.singletonList(processTaskDTO)).get(0);
            certRep.setPromoter("");
            certRep.setNextExecuteIds(workflowResultDto.getNextExecutorRoleIds());
            certRep.setNextExecuteUserIds(workflowResultDto.getNextExecutorUserIds());
            certRep.setApplyStatus(String.valueOf(FlowStatusEnum.ROLLBACK.getCode()));
            certRep.setNextTaskId(workflowResultDto.getNextTaskId());
            baseMapper.updateById(certRep);
            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(certRep));
            jsonObject.put("nextExecuteUser", certRep.getNextExecuteIds());
            jsonObject.put("taskType", BusinessTypeEnum.JG_REPLACEMENT_REGISTRATION.getCode());
            jsonObject.put("flowStatus", FlowStatusEnum.ROLLBACK.getCode());
            jsonObject.put("flowStatusLabel", FlowStatusEnum.ROLLBACK.getName());
            commonService.rollbackTask(certRep.getInstanceId(), jsonObject);
            commonService.saveExecuteFlowData2Redis(instanceId, this.buildInstanceRuntimeData(certRep));
            this.delRepeatUseEquipData(certRep.getSequenceNbr(), certRep.getApplyStatus(), certRep.getUseUnitCode());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 删除redis校验重复引用设备的数据
     */
    private void delRepeatUseEquipData(Long id, String status, String companyCode) {
        List<JgCertificateReplenishEq> list = certificateReplenishEqService.lambdaQuery().eq(JgCertificateReplenishEq::getCertificateReplenishId, id).list();
        // 获取单位变更设备列表
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<String> records = list.stream().map(JgCertificateReplenishEq::getEquId).collect(Collectors.toList());
        if (NOT_FLOWING_STATE.contains(status)) {
            EquipUsedCheckStrategyContext.getUsedStrategy(EQUIP_TRANSFER_PROCESS_KEY)
                    .delDataForCheckEquipRepeatUsed(records, companyCode);
        }
    }

    public InstanceRuntimeData buildInstanceRuntimeData(JgCertificateReplenish certRep) {
        return InstanceRuntimeData.builder()
                .nextExecuteUserIds(certRep.getNextExecuteUserIds())
                .promoter(certRep.getPromoter())
                .nextTaskId(certRep.getNextTaskId())
                .build();
    }
}