package org.springblade.modules.app.manager;

import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.wn.common.perfmonitor.annotation.ServiceTimeLog;
import com.wn.common.validator.Validator;
import org.springblade.modules.app.common.dto.ApplicationInfoDTO;
import org.springblade.modules.app.common.dto.TransportDTO;
import org.springblade.modules.app.common.dto.WaybillDTO;
import org.springblade.modules.app.common.enums.*;
import org.springblade.modules.app.common.query.ApplicationQuery;
import org.springblade.modules.app.common.query.TransportQuery;
import org.springblade.modules.app.common.query.WaybillQuery;
import org.springblade.modules.app.common.vo.OutApiSyncParamVO;
import org.springblade.modules.app.common.vo.VerifyResultVO;
import org.springblade.modules.app.common.vo.WaybillResultVO;
import org.springblade.modules.app.common.vo.ZmtApprovalRecordVO;
import org.springblade.modules.app.constant.ErrorCode;
import org.springblade.modules.app.service.IApplicationInfoService;
import org.springblade.modules.app.service.ITransportService;
import org.springblade.modules.app.service.IWaybillService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@Component
@RefreshScope
public class SyncManager {

    @Value("${xyb.public.Key}")
    private String publicKey;

    @Autowired
    private IWaybillService waybillService;
    @Autowired
    private ITransportService transportService;
    @Autowired
    private IApplicationInfoService applicationInfoService;
    @Autowired
    private MessageLoggingManager messageLoggingManager;

    @ServiceTimeLog
    @Transactional(rollbackFor = Exception.class)
    public Boolean syncWaybillResult(OutApiSyncParamVO syncParamVO) {
        log.info("浙牧通返回备案单审批结果，result {}", JSON.toJSONString(syncParamVO));
        check(syncParamVO);
        WaybillResultVO waybillResultVO = JSON.parseObject(syncParamVO.getBus_content().toString(), WaybillResultVO.class);

        WaybillQuery waybillQuery = new WaybillQuery();
        String recordCode = waybillResultVO.getRecordCode();
        recordCode = recordCode.replace("备","");
        waybillQuery.setOutTradeNo(recordCode);
        WaybillDTO waybill = waybillService.getWaybill(waybillQuery);
        Validator.notNull(waybill, ErrorCode.WAYBILL_INFO_EXP);
        if (WaybillStateEnum.PASS.getCode() != waybill.getState()) {
            ZmtApprovalRecordVO zmtApprovalRecordVO = new ZmtApprovalRecordVO();
            zmtApprovalRecordVO.setApplyTime(new Date());
            zmtApprovalRecordVO.setResult(waybillResultVO.getResult());
            zmtApprovalRecordVO.setMessage(waybillResultVO.getMessage());
            String zmtApplyUpdateInfo = waybill.getZmtApplyUpdateInfo();
            List<ZmtApprovalRecordVO> list = new ArrayList<>();
            if (StringUtils.isNotBlank(zmtApplyUpdateInfo)) {
                list = JSON.parseArray(zmtApplyUpdateInfo, ZmtApprovalRecordVO.class);
            }
            list.add(zmtApprovalRecordVO);
            waybill.setZmtApplyUpdateInfo(JSON.toJSONString(list));
            waybillService.updateWaybill(waybill);
            return true;
        }
        ApplicationQuery applicationQuery = new ApplicationQuery();
        applicationQuery.setLinkId(waybill.getId());
        applicationQuery.setType(ApplicationTypeEnum.WAYBILL_APPROVAL.getCode());
        ApplicationInfoDTO applicationInfoDTO = applicationInfoService.getApplicationInfoByQuery(applicationQuery);
        int messageCode = 0;
        if (waybillResultVO.getResult().equals(YesNoEnum.YES.getCode())) {
            waybill.setState(WaybillStateEnum.FINISH.getCode());
            waybill.setOutTradeNo(recordCode);
            waybill.setFinishTime(new Date());
            applicationInfoDTO.setMessage(waybillResultVO.getMessage());
            applicationInfoDTO.setState(ApplicationStateEnum.PASS.getCode());
            messageCode = MessageEnum.WAYBILL_ADOPT.getCode();
        } else {
            waybill.setState(WaybillStateEnum.UNPASS.getCode());
            applicationInfoDTO.setMessage(waybillResultVO.getMessage());
            applicationInfoDTO.setState(ApplicationStateEnum.REJECT.getCode());
            messageCode = MessageEnum.WAYBILL_FAIL.getCode();
        }
        applicationInfoService.updateApplicationInfo(applicationInfoDTO);
        waybillService.updateWaybill(waybill);

        // 向备案单关联用户：经纪人/养殖场/屠宰场/代宰户发送消息
        if (ObjectUtils.isNotEmpty(waybill.getAgentUserId()) && waybill.getAgentUserId() != 0) {
            messageLoggingManager.messageHandling(waybill.getAgentUserId(), messageCode);
        }
        if (ObjectUtils.isNotEmpty(waybill.getSalerUserId())) {
            messageLoggingManager.messageHandling(waybill.getSalerUserId(), messageCode);
        }
        if (ObjectUtils.isNotEmpty(waybill.getBuyerUserId())) {
            messageLoggingManager.messageHandling(waybill.getBuyerUserId(), messageCode);
        }
        if (ObjectUtils.isNotEmpty(waybill.getSlaughterHouseId())) {
            messageLoggingManager.messageHandling(waybill.getSlaughterHouseId(), messageCode);
        }
        return true;
    }

    @ServiceTimeLog
    public Boolean syncVerifyResult(OutApiSyncParamVO syncParamVO) {
        log.info("浙牧通返回检查站报检结果，result {}", JSON.toJSONString(syncParamVO));
        check(syncParamVO);
        VerifyResultVO verifyResultVO = JSON.parseObject(syncParamVO.getBus_content().toString(), VerifyResultVO.class);

        TransportQuery transportQuery = new TransportQuery();
        transportQuery.setWaybillOutCode(verifyResultVO.getRecordCode());
        TransportDTO transport = transportService.getTransport(transportQuery);
        Validator.notNull(transport, ErrorCode.TRANSPORT_INFO_NULL);
        Validator.isTrue(transport.getState() == WaybillStateEnum.TRANSPORT.getCode(), ErrorCode.TRANSPORT_INFO_EXP);
        transport.setVerifyResultInfo(JSON.toJSONString(verifyResultVO));
        transportService.updateTransport(transport);

        // 查询申请人，推送结果消息
        ApplicationQuery applicationQuery = new ApplicationQuery();
        applicationQuery.setLinkId(transport.getId());
        applicationQuery.setType(ApplicationTypeEnum.TRANSPORT.getCode());
        ApplicationInfoDTO applicationInfoDTO = applicationInfoService.getApplicationInfoByQuery(applicationQuery);
        messageLoggingManager.messageHandling(applicationInfoDTO.getSubmitUserId(),
                verifyResultVO.getResult().equals(YesNoEnum.YES.getCode()) ? MessageEnum.VERIFY_STATION_ADOPT.getCode() : MessageEnum.VERIFY_STATION_FAIL.getCode());
        return true;
    }

    public void check(OutApiSyncParamVO syncParamVO) {
        // 参数列表
        Map<String, Object> params = new HashMap<>(16);
        params.put("charset", "UTF-8");
        params.put("bus_content", syncParamVO.getBus_content());
        params.put("utc_timestamp", syncParamVO.getUtc_timestamp());
        params.put("version", "1.0.0");
        //验签
        Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, null, publicKey);
        //验证签名
        byte[] data = getSignContent(params).getBytes();
        //解密
        byte[] signbyte = Base64.decode(syncParamVO.getSignature());
        boolean verify = sign.verify(data, signbyte);
        log.info("验签结果，time：{}，isSign：{}", syncParamVO.getUtc_timestamp(), verify);
        Validator.isTrue(verify, ErrorCode.VERIFY_SIGN_ERROR);
    }

    public String getSignContent(Map<String, Object> sortedParams) {
        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<>(sortedParams.keySet());
        Collections.sort(keys);
        int index = 0;
        for (String key : keys) {
            String value = sortedParams.get(key).toString();
            if (cn.hutool.core.lang.Validator.isNotEmpty(key) && cn.hutool.core.lang.Validator.isNotEmpty(value)) {
                content.append(index == 0 ? "" : "&").append(key).append("=").append(value);
                index++;
            }
        }
        return content.toString();
    }


}


