package digital.laboratory.platform.entrustment.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import digital.laboratory.platform.common.core.exception.CheckedException;
import digital.laboratory.platform.entrustment.config.properties.ApiPathProperties;
import digital.laboratory.platform.entrustment.entity.Entrustment;
import digital.laboratory.platform.entrustment.entity.EntrustmentIdentificationMaterial;
import digital.laboratory.platform.entrustment.enums.EntrustStatusConstants;
import digital.laboratory.platform.entrustment.mapper.EntrustmentMapper;
import digital.laboratory.platform.entrustment.service.CommonFeignService;
import digital.laboratory.platform.entrustment.service.EntrustmentIdentificationMaterialService;
import digital.laboratory.platform.entrustment.service.EntrustmentService;
import digital.laboratory.platform.entrustment.service.PushDataToLabsCareService;
import digital.laboratory.platform.entrustment.vo.EntrustmentVO;
import digital.laboratory.platform.entrustment.vo.MaterialListForBookVo;
import digital.laboratory.platform.othersys.utils.HttpsUtils;
import digital.laboratory.platform.sys.entity.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;

import javax.annotation.Resource;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author ChenJiangBao
 * @version 1.0
 * @description: 推送数据到labscare平台接口
 * @date 2025/3/27 16:32
 */
@Slf4j
//@Service
public class PushDataToLabsCareServiceImpl implements PushDataToLabsCareService {

    @Resource
    private EntrustmentService entrustmentService;

    @Resource
    private EntrustmentMapper entrustmentMapper;

    @Resource
    private ApiPathProperties apiPathProperties;

    @Resource
    private CommonFeignService commonFeignService;

    @Resource
    private EntrustmentIdentificationMaterialService entrustmentIdentificationMaterialService;

    private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");

    // "#NULL#" 作为空数据的占位符, 对于系统中没有的信息以占位符代替
    public final static String NULL_PLACEHOLDER = "#NULL#";

    // 委托书的推送标识
    public final static String ENTRUST_LETTER = "EntrustLetter";

    // 事项确认书的推送标识
    public final static String ITEM_CONFIRM_LETTER = "ItemConfirmLetter";

    /**
     * 做一个定时推送，对于推送失败的委托进行重新推送， 每天凌晨1点推送
     */
//    @Scheduled(cron = "30 * * * * ?") // 测试
    @Scheduled(cron = "0 0 1 * * ?")  // 每天凌晨 1 点执行
    public void timingPushDataToLabsCare() throws IllegalAccessException {
        // 查询受理后推送失败的委托
        List<EntrustmentVO> entrustmentList = entrustmentMapper.getEntrustmentVOList(
                Wrappers.<Entrustment>query()
                        .in("e.status",
                                EntrustStatusConstants.ENTRUST_STATUS_ACCEPTED.getStatus(),
                                EntrustStatusConstants.ENTRUST_STATUS_TEST_FINISH.getStatus(),
                                EntrustStatusConstants.ENTRUST_STATUS_COMPLETED.getStatus())
                        .and(wrapper -> wrapper
                                .eq("e.push_flag", "")
                                .or()
                                .isNull("e.push_flag")
                                .or()
                                .like("e.push_flag", "false")
                        )
        );

        for (EntrustmentVO entrustmentVO : entrustmentList) {
            String pushFlag = entrustmentVO.getPushFlag();
            if (StrUtil.isBlank(pushFlag)) {
                pushEntrustLetterData(entrustmentVO);
                pushItemConfirmLetterData(entrustmentVO);
            } else {
                List<String> flagList = StrUtil.split(pushFlag, StrUtil.COMMA).stream().filter(str -> str.contains("false")).collect(Collectors.toList());
                for (String flag : flagList) {
                    if (flag.contains(ENTRUST_LETTER)) {
                        pushEntrustLetterData(entrustmentVO);
                    } else {
                        pushItemConfirmLetterData(entrustmentVO);
                    }
                }
            }
        }
    }

    /**
     * 推送鉴定事项确认书数据
     *
     * @param entrustVO 委托vo
     */
    @Override
    public void pushItemConfirmLetterData(EntrustmentVO entrustVO) {
        JSONObject jsonObject = buildItemConfirmLetterJsonPayload(entrustVO);
        String successFlag = ITEM_CONFIRM_LETTER + ":true";
        String failureFlag = ITEM_CONFIRM_LETTER + ":false";
        try {
            ResponseEntity<String> response = exchangeRemoteApi(jsonObject, apiPathProperties.getConfirmLetter());

            if (response.getStatusCode().is2xxSuccessful() && response.getBody().contains("\"status\":200")) {
                updatePushFlag(entrustVO, ITEM_CONFIRM_LETTER, successFlag);
                log.info("推送鉴定事项确认书数据成功, 受理编号: {}, 响应: {}", entrustVO.getAcceptNo(), response.getBody());
            } else {
                updatePushFlag(entrustVO, ITEM_CONFIRM_LETTER, failureFlag);
                log.warn("推送鉴定事项确认书数据失败, 受理编号: {}, 状态码: {}, 响应: {}",
                        entrustVO.getAcceptNo(), response.getStatusCode(), response.getBody());
            }
        } catch (RestClientException e) {
            log.error("推送鉴定事项确认书数据到 LabsCare 失败, 受理编号: {}", entrustVO.getAcceptNo(), e);
        }
    }

    /**
     * 推送委托函数据
     *
     * @param entrustVO
     */
    @Override
    public void pushEntrustLetterData(EntrustmentVO entrustVO) throws IllegalAccessException {
        JSONObject jsonObject = buildEntrustLetterJsonPayload(entrustVO);

        String successFlag = ENTRUST_LETTER + ":true";
        String failureFlag = ENTRUST_LETTER + ":false";
        try {
            ResponseEntity<String> response = exchangeRemoteApi(jsonObject, apiPathProperties.getEntrustLetter());

            if (response.getStatusCode().is2xxSuccessful() && response.getBody().contains("\"status\":200")) {
                updatePushFlag(entrustVO, ENTRUST_LETTER, successFlag);
                log.info("推送鉴定委托书数据成功, 委托编号: {}, 响应: {}", entrustVO.getEntrustmentNo(), response.getBody());
            } else {
                updatePushFlag(entrustVO, ENTRUST_LETTER, failureFlag);
                log.warn("推送鉴定委托书数据失败, 委托编号: {}, 状态码: {}, 响应: {}",
                        entrustVO.getEntrustmentNo(), response.getStatusCode(), response.getBody());
            }
        } catch (RestClientException e) {
            log.error("推送鉴定委托书数据到 LabsCare 失败, 委托编号: {}", entrustVO.getEntrustmentNo(), e);
        }
    }

    /**
     * 获取推送鉴定委托书的数据
     * @param entrustId 委托id
     * @return
     */
    @Override
    public JSONObject fetchEntrustLetterData(String entrustId) {
        // 获取委托信息
        EntrustmentVO entrustVO = validFetchParam(entrustId);
        return buildEntrustLetterJsonPayload(entrustVO);
    }

    /**
     * 获取推送鉴定事项确认书的数据
     * @param entrustId 委托id
     * @return
     */
    @Override
    public JSONObject fetchItemConfirmLetterData(String entrustId) {
        // 获取委托信息
        EntrustmentVO entrustVO = validFetchParam(entrustId);
        return buildItemConfirmLetterJsonPayload(entrustVO);
    }


    /**
     * 构建委托函的JSON负载
     *
     * @param entrustVO 委托VO对象
     * @return 构建好的JSON对象
     */
    private JSONObject buildEntrustLetterJsonPayload(EntrustmentVO entrustVO) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("afsj", entrustVO.getHappenTime()); // 案发时间
        jsonObject.set("ajmc", entrustVO.getCaseName()); // 案事件名称
        jsonObject.set("dwgz", entrustVO.getClientOrgName()); // 单位盖章
        jsonObject.set("jyaq", entrustVO.getCaseBrief()); // 简要案情
        jsonObject.set("sjdwfzr", entrustVO.getDeliverer1Name() + "、" + entrustVO.getDeliverer2Name()); // 	单位负责人签名
        jsonObject.set("sjr1", entrustVO.getDeliverer1Name()); // 送检人
        jsonObject.set("sjr2", entrustVO.getDeliverer2Name());
        jsonObject.set("sjr1dh", entrustVO.getDeliverer1Phone());
        jsonObject.set("sjr2dh", entrustVO.getDeliverer2Phone());
        jsonObject.set("slrq", entrustVO.getAcceptTime().format(formatter));
        jsonObject.set("wtdw", entrustVO.getClientOrgName());
        jsonObject.set("wtsj", entrustVO.getEntrustmentTime().format(formatter));
        jsonObject.set("yjdqk", entrustVO.getOldIdentificationResult());

        // 组装材料信息
        List<EntrustmentIdentificationMaterial> materialList = entrustmentIdentificationMaterialService.handleMaterialWeightRounding(entrustVO.getId());
        AtomicInteger index = new AtomicInteger(1);
        List<JSONObject> table = materialList.stream().map(material -> {
            JSONObject materialJson = new JSONObject();
            materialJson.set("bzsfwz", material.getPackComplete() ? "是" : "否");
            materialJson.set("jyjdyq", material.getDrugsValue() + material.getAnalysisOptionValue());
            materialJson.set("lcygs", material.getRtSampleQuantity());
            materialJson.set("projectName", index.getAndIncrement());
            materialJson.set("tqdd", material.getDrawPlace());
            materialJson.set("tqsj", material.getDrawTime().format(formatter));
            materialJson.set("xzms", material.getFormName());
            materialJson.set("yswzl", material.getName());
            materialJson.set("zltj", material.getQuantity() + material.getUnit());
            return materialJson;
        }).collect(Collectors.toList());

        jsonObject.set("table", table);
        return jsonObject;
    }

    /**
     * 构建鉴定事项确认书的JSON负载
     *
     * @param entrustVO 委托单VO对象，包含构建JSON负载所需的数据
     * @return 包含鉴定事项确认书数据的JSONObject对象
     */
    private JSONObject buildItemConfirmLetterJsonPayload(EntrustmentVO entrustVO) {
        JSONObject jsonObject = new JSONObject();
        SysUser sysUser = commonFeignService.remoteGetUserById(entrustVO.getAcceptUser());
        jsonObject.set("ajmc", entrustVO.getCaseName()); //  案件名称
        jsonObject.set("dwfzr", StrUtil.join("、", entrustVO.getDeliverer1Name(), entrustVO.getDeliverer2Name())); // 送检人签名
        // 检材处理要求，这里的值是直接复制了确认书里的值
        jsonObject.set("jcclyq", "以上检材均按照《办理毒品犯罪案件毒品提取、扣押、称量、取样和送检程序若干问题的规定》、《贵阳市公安局关于进一步规范毒品取样、保管及送检程序的通知》要求的提取部位和提取方法进行取样。");
        jsonObject.set("jdjbrqm", sysUser.getName()); /// 鉴定机构经办人签字 ，我们系统是单位自己打印出来，线下自己手签
        jsonObject.set("jdyq", entrustVO.getEntrustRequirement()); // 鉴定要求
        jsonObject.set("jyaq", entrustVO.getCaseBrief()); // 简要案情
        jsonObject.set("lqrqm", StrUtil.join("、", entrustVO.getDeliverer1Name(), entrustVO.getDeliverer2Name())); // 领取人签名
        jsonObject.set("sjr1", entrustVO.getDeliverer1Name()); // 送检人1姓名
        jsonObject.set("sjr2", entrustVO.getDeliverer2Name()); // 送检人2姓名
        jsonObject.set("sjr1dh", entrustVO.getDeliverer1Phone()); // 送检人电话
        jsonObject.set("sjr2dh", entrustVO.getDeliverer2Phone());
        jsonObject.set("sjr1zjh", StrUtil.join("：", entrustVO.getDeliverer1Cert(), entrustVO.getDeliverer1Id())); // 送检人证件和号码
        jsonObject.set("sjr2zjh", StrUtil.join("：", entrustVO.getDeliverer2Cert(), entrustVO.getDeliverer2Id()));
        jsonObject.set("sjr1zw", entrustVO.getDeliverer1Position()); // 送检人职务
        jsonObject.set("sjr2zw", entrustVO.getDeliverer2Position());
        jsonObject.set("slbh", entrustVO.getAcceptNo());
        jsonObject.set("slrq", entrustVO.getAcceptTime().format(formatter));
        jsonObject.set("slr", sysUser.getName());
        jsonObject.set("slrqm", sysUser.getName()); // 鉴定机构受理人签字
        jsonObject.set("wtbh", entrustVO.getAcceptNo()); // 委托书编号
        jsonObject.set("wtdw", entrustVO.getClientOrgName());
        jsonObject.set("wtsj", entrustVO.getEntrustmentTime().format(formatter));
        List<EntrustmentIdentificationMaterial> materialList = entrustmentIdentificationMaterialService.list(Wrappers.<EntrustmentIdentificationMaterial>lambdaQuery()
                .eq(EntrustmentIdentificationMaterial::getEntrustmentId, entrustVO.getId()));
        List<MaterialListForBookVo> materialBookVoList = entrustmentService.getMaterialBookVoList(materialList);
        List<JSONObject> table = materialBookVoList.stream().map(materialBookVo -> {
            JSONObject materialBookVoJson = new JSONObject();
            materialBookVoJson.set("baozhuang", materialBookVo.isPackComplete() ? "是" : "否");
            materialBookVoJson.set("bh", materialBookVo.getOrderNo());
            materialBookVoJson.set("yswzl", materialBookVo.getMaterialName());
            materialBookVoJson.set("bz", StrUtil.isBlank(materialBookVo.getRemark()) ? NULL_PLACEHOLDER : materialBookVo.getRemark());
            materialBookVoJson.set("lcygs", materialBookVo.getRtSampleQuantity());
            materialBookVoJson.set("sl", materialBookVo.getTotalSampleDes());
            materialBookVoJson.set("xzms", materialBookVo.getFormName());
            return materialBookVoJson;
        }).collect(Collectors.toList());
        jsonObject.put("table", table);
        return jsonObject;
    }


    /**
     * 通过POST请求与远程API进行交互
     *
     * @param jsonObject 包含请求数据的JSONObject对象
     * @param url        远程API的URL
     * @return ResponseEntity<String> 包含远程API响应数据的ResponseEntity对象
     */
    private ResponseEntity<String> exchangeRemoteApi(JSONObject jsonObject, String url) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);  // 设置为 application/json
        HttpEntity<JSONObject> requestEntity = new HttpEntity<>(jsonObject, headers);
        ResponseEntity<String> response = HttpsUtils
                .genRestTemplate()
                .exchange(
                        url,
                        HttpMethod.POST,
                        requestEntity,
                        String.class
                );
        return response;
    }

    /**
     * 更新推送标志
     *
     * @param entrustVO   委托VO对象
     * @param pushType    推送类型 EntrustLetter 委托书 | ItemConfirmLetter 事项确认书
     * @param newFlag     新的推送标志
     */
    private void updatePushFlag(EntrustmentVO entrustVO, String pushType, String newFlag) {
        List<String> flagList = Optional.ofNullable(StrUtil.split(entrustVO.getPushFlag(), StrUtil.COMMA))
                .orElse(new ArrayList<>());

        // 判断是否已有 指定的推送类型，如果有就替换，否则添加
        boolean exists = flagList.stream().anyMatch(flag -> flag.contains(pushType));
        if (exists) {
            flagList.replaceAll(flag -> flag.contains(pushType) ? newFlag : flag);
        } else {
            flagList.add(newFlag);
        }
        // 更新标识, 防止定时任务那里连续推送数据时推送标识更新出错
        entrustVO.setPushFlag(String.join(",", flagList));
        // 更新数据库
        entrustmentService.update(Wrappers.<Entrustment>lambdaUpdate()
                .eq(Entrustment::getId, entrustVO.getId())
                .set(Entrustment::getPushFlag, String.join(",", flagList)));
    }

    /**
     * 根据委托ID验证并获取委托信息
     *
     * @param entrustId 委托ID
     * @return 委托信息对象 EntrustmentVO
     * @throws CheckedException 当未找到对应的委托信息时抛出此异常
     */
    private EntrustmentVO validFetchParam(String entrustId) {
        EntrustmentVO entrustVO = entrustmentService.getEntrustmentVOById(entrustId);
        if (entrustVO == null) {
            log.error("未找到委托信息, entrustId={}", entrustId);
            throw new CheckedException(String.format("未找到委托信息, entrustId=%s", entrustId));
        }
        return entrustVO;
    }
}
