package com.sckw.contract.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sckw.contract.dao.KwcContractLogisticsMapper;
import com.sckw.contract.dao.KwcContractTradeMapper;
import com.sckw.contract.factory.AsyncFactory;
import com.sckw.contract.model.dto.req.EsignGetFlowReqDto;
import com.sckw.contract.model.dto.res.ESignSubmitResDto;
import com.sckw.contract.model.entity.KwcContractLogistics;
import com.sckw.contract.model.entity.KwcContractLogisticsUnit;
import com.sckw.contract.model.entity.KwcContractTrade;
import com.sckw.contract.model.entity.KwcContractTradeUnit;
import com.sckw.contract.model.vo.req.ESignCallBackReqVo;
import com.sckw.core.exception.SystemException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.ClientTypeEnum;
import com.sckw.core.model.enums.CooperateTypeEnum;
import com.sckw.core.utils.*;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.stream.function.StreamBridge;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
import com.sckw.order.api.model.ContractSignCompletedParam;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.api.dubbo.TransportService;
import com.sckw.transport.api.model.param.ContractSignLogisticsParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sckw.stream.enums.MessageEnum;
import com.sckw.stream.model.SckwMessage;
import com.sckw.stream.model.UserInfo;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Slf4j
@Service
@RequiredArgsConstructor
public class CommonBusinessService {

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TradeOrderInfoService tradeOrderInfoService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TransportService transportDubboService;

    @Autowired
    private KwcContractTradeMapper kwcContractTradeMapper;

    @Autowired
    private KwcContractLogisticsMapper kwcContractLogisticsMapper;

    @Autowired
    private KwcContractLogisticsService kwcContractLogisticsService;

    @Autowired
    private KwcContractTradeService kwcContractTradeService;

    @Autowired
    private KwcContractLogisticsTrackService kwcContractLogisticsTrackService;

    @Autowired
    private KwcContractTradeTrackService kwcContractTradeTrackService;

    @Autowired
    private KwcContractLogisticsUnitService kwcContractLogisticsUnitService;

    @Autowired
    private KwcContractTradeUnitService kwcContractTradeUnitService;

    private  final StreamBridge streamBridge;

    @Value("${eSignUrl}")
    private String eSignUrl;

    /**销售合同*/
    @Value(value = "${jumpUrl.saleSendContract}")
    private String saleSendContract;

    /**采购合同*/
    @Value(value = "${jumpUrl.purchaseSendContract}")
    private String purchaseSendContract;

    /**托运合同*/
    @Value(value = "${jumpUrl.consignmentSendContract}")
    private String consignmentSendContract;

    /**承运合同*/
    @Value(value = "${jumpUrl.acceptanceSendContract}")
    private String acceptanceSendContract;

    /**app销售合同*/
    @Value(value = "${jumpUrl.appSaleSendContract}")
    private String appSaleSendContract;

    /**app采购合同*/
    @Value(value = "${jumpUrl.appPurchaseSendContract}")
    private String appPurchaseSendContract;

    /**app托运合同*/
    @Value(value = "${jumpUrl.appConsignmentSendContract}")
    private String appConsignmentSendContract;

    /**app承运合同*/
    @Value(value = "${jumpUrl.appAcceptanceSendContract}")
    private String appAcceptanceSendContract;


    /**
     * @return Map
     * @desc: 查企业
     * @param: entIdList 企业id集合
     * @author: czh
     * @date 2023/7/16
     */
    public Map<Long, EntCacheResDto> queryEntCacheMapByIds(List<Long> entIdList) {
        return remoteSystemService.queryEntCacheMapByIds(entIdList);
    }

    /**
     * @param reqVo e签宝回调参数
     * @desc: 审批
     * @author: czh
     * @date: 2023/8/14
     */
    @Transactional(rollbackFor = {})
    public void approval(ESignCallBackReqVo reqVo) {
        Long contractId = reqVo.getContractId();
        KwcContractTrade kwcContractTrade = kwcContractTradeMapper.selectById(contractId);
        if (Objects.nonNull(kwcContractTrade)) {
            kwcContractTradeService.approval(reqVo.getContractId(), reqVo.getStatus(), reqVo.getRemark());
            kwcContractTradeTrackService.saveContractTradeTrack(contractId, reqVo.getStatus());
            notifyOrder(contractId, kwcContractTrade.getCreateBy());
            sendTradePassMessage(kwcContractTrade);
            return;
        }

        KwcContractLogistics kwcContractLogistics = kwcContractLogisticsMapper.selectById(contractId);
        if (Objects.nonNull(kwcContractLogistics)) {
            kwcContractLogisticsService.approval(reqVo.getContractId(), reqVo.getStatus(), reqVo.getRemark());
            kwcContractLogisticsTrackService.saveContractLogisticsTrack(contractId, reqVo.getStatus());
            notifyOrder(contractId, kwcContractLogistics.getCreateBy());
            sendLogisticsPassMessage(kwcContractLogistics);
            return;
        }
        throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.CONTRACT_NOT_EXISTS);
    }


    public void sendLogisticsPassMessage(KwcContractLogistics kwcContractLogistics) {
        List<KwcContractLogisticsUnit> kwcContractLogisticsUnits = kwcContractLogisticsUnitService.queryByContractId(kwcContractLogistics.getId());
        Map<Integer, KwcContractLogisticsUnit> collect = kwcContractLogisticsUnits.stream().collect(Collectors.toMap(KwcContractLogisticsUnit::getUnitType, Function.identity()));

        KwcContractLogisticsUnit kwcContractLogisticsUnit = collect.get(CooperateTypeEnum.CARRIAGE.getCode());
        Long entId1 = kwcContractLogisticsUnit.getEntId();

        EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntCacheById(entId1);
        Map<String, Object> map = new HashMap<>();
        map.put("entName", entCacheResDto1.getFirmName());
        map.put("contract_no", kwcContractLogistics.getContractNo());
        map.put("name", kwcContractLogistics.getName());
        sendSystemMessage(Collections.singletonList(new UserInfo().setUserId(kwcContractLogistics.getCreateBy()).setEntId(kwcContractLogistics.getEntId())),
                MessageEnum.SAELCONTRACT_SUCCESS_CONTRACT,
                map,
                consignmentSendContract,
                appConsignmentSendContract);

        EntCacheResDto entCacheResDto = remoteSystemService.queryEntCacheById(entId1);
        KwcContractLogisticsUnit kwcContractLogisticsUnit2 = collect.get(CooperateTypeEnum.CONSIGN.getCode());
        EntCacheResDto entCacheResDto2 = remoteSystemService.queryEntCacheById(kwcContractLogisticsUnit2.getEntId());
        map.put("entName", entCacheResDto2.getFirmName());
        sendSystemMessage(Collections.singletonList(new UserInfo().setUserId(entCacheResDto.getContactsId()).setEntId(entCacheResDto.getId())),
                MessageEnum.BUYCONTRACT_SUCCESS_CONTRACT,
                map,
                acceptanceSendContract,
                appAcceptanceSendContract);
    }



    public void sendTradePassMessage(KwcContractTrade kwcContractTrade) {
        try {
            List<KwcContractTradeUnit> kwcContractTradeUnits = kwcContractTradeUnitService.queryByContractId(kwcContractTrade.getId());
            Map<Integer, KwcContractTradeUnit> collect = kwcContractTradeUnits.stream().collect(Collectors.toMap(KwcContractTradeUnit::getUnitType, Function.identity()));

            KwcContractTradeUnit kwcContractTradeUnit = collect.get(CooperateTypeEnum.PURCHASER.getCode());
            Long entId1 = kwcContractTradeUnit.getEntId();

            EntCacheResDto entCacheResDto1 = remoteSystemService.queryEntCacheById(entId1);
            Map<String, Object> map = new HashMap<>();
            map.put("entName", entCacheResDto1.getFirmName());
            map.put("contract_no", kwcContractTrade.getContractNo());
            map.put("name", kwcContractTrade.getName());
            sendSystemMessage(Collections.singletonList(new UserInfo().setUserId(kwcContractTrade.getCreateBy()).setEntId(kwcContractTrade.getEntId())),
                    MessageEnum.SAELCONTRACT_SUCCESS_CONTRACT,
                    map,
                    saleSendContract,
                    appSaleSendContract);

            EntCacheResDto entCacheResDto = remoteSystemService.queryEntCacheById(entId1);
            KwcContractTradeUnit kwcContractTradeUnit2 = collect.get(CooperateTypeEnum.SUPPLIER.getCode());
            EntCacheResDto entCacheResDto2 = remoteSystemService.queryEntCacheById(kwcContractTradeUnit2.getEntId());
            map.put("entName", entCacheResDto2.getFirmName());
            sendSystemMessage(Collections.singletonList(new UserInfo().setUserId(entCacheResDto.getContactsId()).setEntId(entCacheResDto.getId())),
                    MessageEnum.BUYCONTRACT_SUCCESS_CONTRACT,
                    map,
                    purchaseSendContract,
                    appPurchaseSendContract);
        } catch (Exception e) {
           log.error("合同签约成功消息出错:", e);
        }
    }

    /**
     * @param contractId 合同id   userId用户id
     * @desc: 通知订单模块更新状态
     * @author: czh
     * @date: 2023/8/14
     */
    public void notifyOrder(Long contractId, Long userId) {
        ContractSignCompletedParam contractSignCompletedParam = new ContractSignCompletedParam();
        UserCacheResDto userCacheResDto = remoteSystemService.queryUserCacheById(userId);
        String name = Objects.isNull(userCacheResDto) ? "" : userCacheResDto.getName();
        contractSignCompletedParam.setContractId(contractId);
        contractSignCompletedParam.setUpdateBy(userId);
        contractSignCompletedParam.setUpdateByName(name);
        tradeOrderInfoService.contractSignCompleted(contractSignCompletedParam);

        ContractSignLogisticsParam contractSignLogisticsParam = new ContractSignLogisticsParam();
        contractSignLogisticsParam.setContractId(contractId);
        contractSignLogisticsParam.setUpdateBy(userId);
        contractSignLogisticsParam.setUpdateByName(name);
        transportDubboService.contractSignLogisticsCompleted(contractSignLogisticsParam);
    }


    /**
     * @param firstAccount 发起方签约电话
     *                     secondAccount 对方签约电话
     *                     orgFirst 发起方企业id
     *                     orgSeconId 对方企业id
     *                     contractFile 合同文件
     *                     id 合同id
     *                     contractName 合同名
     * @desc: 调e签宝
     * @author: czh
     * @date: 2023/8/14
     */
    public void postToEsign(String firstAccount, String secondAccount, Long orgFirst, Long orgSeconId, String contractFile, Long id, String contractName) {
        AsyncFactory.execute(new AsyncProcess(firstAccount, secondAccount, orgFirst, orgSeconId, contractFile, id, contractName, remoteSystemService, eSignUrl, kwcContractLogisticsMapper, kwcContractTradeMapper));
    }




    public void sendSystemMessage(List<UserInfo> userInfos, MessageEnum messageEnum, Map<String, Object> map, String msgUrl, String appMsgUrl) {
        SckwMessage msg = new SckwMessage();
        Map<String, String> msgUrls = new HashMap<>(Global.NUMERICAL_FOUR);
        msgUrls.put(ClientTypeEnum.pc.getValue(), msgUrl);
        msgUrls.put(ClientTypeEnum.app.getValue(), appMsgUrl);
        msg.setRequestId(UUIDUtils.get32UUID())
                .setMessageEnum(messageEnum)
                .setParams(map)
                .setMsgUrls(msgUrls)
                .setUserInfos(userInfos)
                .setCreateBy(LoginUserHolder.getUserId());
        AsyncThreadUtils.submit(new AsyncProcessMessage(msg, streamBridge));
    }

    static class AsyncProcessMessage implements Runnable {

        private SckwMessage sckwMessage;

        private StreamBridge streamBridge;

        AsyncProcessMessage(SckwMessage sckwMessage, StreamBridge streamBridge) {
            this.sckwMessage = sckwMessage;
            this.streamBridge = streamBridge;
        }

        @Override
        public void run() {
            streamBridge.send("sckw-message", JSON.toJSONString(sckwMessage));
        }
    }

    static class AsyncProcess implements Runnable {

        private final String firstAccount;
        private final String secondAccount;
        private final Long orgFirst;
        private final Long orgSeconId;
        private final String contractFile;
        private final Long id;
        private final String contractName;

        private RemoteSystemService remoteSystemService;
        private String eSignUrl;
        private KwcContractLogisticsMapper kwcContractLogisticsMapper;
        private KwcContractTradeMapper kwcContractTradeMapper;

        public AsyncProcess(String firstAccount,
                            String secondAccount,
                            Long orgFirst,
                            Long orgSeconId,
                            String contractFile,
                            Long id,
                            String contractName,
                            RemoteSystemService remoteSystemService,
                            String eSignUrl,
                            KwcContractLogisticsMapper kwcContractLogisticsMapper,
                            KwcContractTradeMapper kwcContractTradeMapper) {
            this.firstAccount = firstAccount;
            this.secondAccount = secondAccount;
            this.orgFirst = orgFirst;
            this.orgSeconId = orgSeconId;
            this.contractFile = contractFile;
            this.id = id;
            this.contractName = contractName;
            this.remoteSystemService = remoteSystemService;
            this.eSignUrl = eSignUrl;
            this.kwcContractLogisticsMapper = kwcContractLogisticsMapper;
            this.kwcContractTradeMapper = kwcContractTradeMapper;
        }

        @Override
        public void run() {
            EsignGetFlowReqDto esignGetFlowReqDto = new EsignGetFlowReqDto();
            JSONArray jsonArray = JSONArray.parseArray(contractFile);
            JSONObject jsonObject = jsonArray.getJSONObject(0);
            String fileName = jsonObject.getString("name");
            String url = FileUtils.splice(jsonObject.getString("url"));
            File file = getFileByHttpURL(url, fileName);
            List<Long> entIds = new ArrayList<>(2);
            entIds.add(orgFirst);
            entIds.add(orgSeconId);
            Map<Long, EntCacheResDto> longListMap = remoteSystemService.queryEntCacheMapByIds(entIds);

            esignGetFlowReqDto.setFile(file);
            esignGetFlowReqDto.setSeqId(String.valueOf(id));
            esignGetFlowReqDto.setSignFlowTitle(contractName);
            esignGetFlowReqDto.setOrgFirstName(longListMap.get(orgFirst).getFirmName());
            esignGetFlowReqDto.setPsnFirstAccount(firstAccount);
            esignGetFlowReqDto.setOrgSecondName(longListMap.get(orgSeconId).getFirmName());
            esignGetFlowReqDto.setPsnSecondAccount(secondAccount);
            Map<String, Object> map = BeanUtils.convertToMap(esignGetFlowReqDto);
            log.info("E签宝入参: url:{}, param:{}", eSignUrl, JSON.toJSONString(map));
            String res = OkHttpUtils.doPostUploadFile(eSignUrl, map);
            log.info("E签宝返参:{}", res);
            ESignSubmitResDto eSignSubmitResDto = JSONObject.parseObject(res, ESignSubmitResDto.class);
            if (eSignSubmitResDto.getStatus()) {
                String signFlowId = eSignSubmitResDto.getData().getSignFlowId();
                KwcContractLogistics kwcContractLogistics = kwcContractLogisticsMapper.selectById(id);
                if (Objects.nonNull(kwcContractLogistics)) {
                    kwcContractLogistics.setBusinessId(signFlowId);
                    kwcContractLogisticsMapper.updateById(kwcContractLogistics);
                    return;
                }

                KwcContractTrade kwcContractTrade = kwcContractTradeMapper.selectById(id);
                if (Objects.nonNull(kwcContractTrade)) {
                    kwcContractTrade.setBusinessId(signFlowId);
                    kwcContractTradeMapper.updateById(kwcContractTrade);
                }
            }
        }

        public static File getFileByHttpURL(String newUrl, String fileName) {
            //得到最后一个分隔符后的名字
            File file = null;
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                file = new File(System.getProperty("java.io.tmpdir") + new String(fileName.getBytes("gbk"), StandardCharsets.UTF_8));
                URL urlFile = new URL(newUrl);
                inputStream = urlFile.openStream();
                outputStream = new FileOutputStream(file);

                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != outputStream) {
                        outputStream.close();
                    }
                    if (null != inputStream) {
                        inputStream.close();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return file;
        }
    }

    public static File getFileByHttpURL(String newUrl, String fileName) {
        //得到最后一个分隔符后的名字
        File file = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            file = new File(System.getProperty("java.io.tmpdir") + new String(fileName.getBytes(), StandardCharsets.UTF_8));
            URL urlFile = new URL(newUrl);
            inputStream = urlFile.openStream();
            outputStream = new FileOutputStream(file);

            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != outputStream) {
                    outputStream.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return file;
    }

}
