package com.mmc.iuav.user.service.fdd.impl;

import com.alibaba.fastjson.JSONObject;
import com.fadada.sdk.base.client.FddBaseClient;
import com.fadada.sdk.base.model.req.*;
import com.fadada.sdk.utils.crypt.FddEncryptTool;
import com.mmc.iuav.general.CodeUtil;
import com.mmc.iuav.http.BizException;
import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.response.ResultEnum;
import com.mmc.iuav.user.constant.fdd.FddConnectConstant;
import com.mmc.iuav.user.constant.fdd.FddConstant;
import com.mmc.iuav.user.dao.CompanyAuthDao;
import com.mmc.iuav.user.dao.CompanyDao;
import com.mmc.iuav.user.dao.CooperationDao;
import com.mmc.iuav.user.dao.UserServiceDao;
import com.mmc.iuav.user.dao.fdd.ContractDao;
import com.mmc.iuav.user.dao.fdd.UserFddAuthDao;
import com.mmc.iuav.user.entity.CompanyAuthDO;
import com.mmc.iuav.user.entity.CompanyInfoDO;
import com.mmc.iuav.user.entity.UserApplyTagDO;
import com.mmc.iuav.user.entity.fdd.ContractInfoDO;
import com.mmc.iuav.user.entity.fdd.UserFddDO;
import com.mmc.iuav.user.enums.RoleEnums;
import com.mmc.iuav.user.model.dto.LoginSuccessDTO;
import com.mmc.iuav.user.model.fdd.dto.ContractInfoDTO;
import com.mmc.iuav.user.model.fdd.vo.ContractVO;
import com.mmc.iuav.user.model.vo.BUserAccountVO;
import com.mmc.iuav.user.model.vo.UserAccountVO;
import com.mmc.iuav.user.mq.MqProducer;
import com.mmc.iuav.user.service.BackUserAccountService;
import com.mmc.iuav.user.service.UserAccountService;
import com.mmc.iuav.user.service.fdd.ContractService;
import com.mmc.iuav.user.service.fdd.SealManageService;
import com.mmc.iuav.user.service.fdd.UserFddAuthService;
import com.mmc.iuav.user.util.SmsUtil;
import com.mmc.iuav.user.util.TDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @Author LW
 * @date 2022/9/5 14:38
 * 概要：
 */
@Service
@Slf4j
public class ContractServiceImpl implements ContractService {
    @Resource
    ContractDao contractDao;
    @Resource
    SealManageService sealManageService;
    @Resource
    private MqProducer mqProducer;
    @Resource
    UserFddAuthService userFddAuthService;
    @Resource
    UserServiceDao userServiceDao;
    @Resource
    UserFddAuthDao userFddAuthDao;

    @Autowired
    private BackUserAccountService backUserAccountService;

    @Autowired
    private UserAccountService userAccountService;

    @Autowired
    private CompanyDao companyDao;

    @Autowired
    private CompanyAuthDao companyAuthDao;
    @Autowired
    private CooperationDao cooperationDao;

    /**
     * 上传合同
     *
     * @param param
     * @return
     */
    @Override
    public ResultBody uploadContract(ContractVO param, LoginSuccessDTO loginSuccessDTO) {
        ResultBody resultBody = sealManageService.checkAuthStatus(param.getPort(), loginSuccessDTO);
        if (!resultBody.getCode().equals("200")) {
            return resultBody;
        }
        UserFddDO userFddDO = (UserFddDO) resultBody.getResult();
        FddBaseClient baseClient = new FddBaseClient(FddConnectConstant.APP_ID, FddConnectConstant.APP_KEY, FddConnectConstant.VERSION, FddConnectConstant.HOST);
        // 查询这个订单号之前有没有上传过合同有的话就删除
        ContractInfoDO contractInfoDO = contractDao.contractInfoByOrderNo(param.getOrderNo(), null);
        if (contractInfoDO != null) {
            // 把合同删除
            contractDao.deleteContractInfo(param.getOrderNo());
        }
        //自定义合同id 合同编号设置规则：YXF + 年份 + 8位随机数
        String contractId = FddConstant.YXF + TDateUtil.getCurrentYear() + CodeUtil.getRandomNum(8);
        // 调用法大大接口
        UploadDocsParams params = new UploadDocsParams();
        // 合同编号
        params.setContractId(contractId);
        //合同标题
        params.setDocTitle(param.getTitle());
        //PDF文档和下载地址二选一
        //合同公网下载地址
        params.setDocUrl(param.getDocUrl());
        //合同类型 目前仅支持pdf格式
        params.setDocType(".pdf");
        String result = baseClient.invokeUploadDocs(params);
        String code = JSONObject.parseObject(result).getString(FddConstant.CODE);
        String msg = JSONObject.parseObject(result).getString(FddConstant.MSG);
        if (FddConstant.SUCCESS_CODE.equals(code)) {
            // 保存合同信息到数据库
            ContractInfoDO contractInfo = new ContractInfoDO();
            contractInfo.setContractTitle(param.getTitle());
            contractInfo.setOrderNo(param.getOrderNo());
            contractInfo.setContractNo(contractId);
            contractInfo.setUnionId(userFddDO.getUnionId());
            contractDao.insertUavContractInfo(contractInfo);
            return ResultBody.success(contractInfo);
        } else {
            return ResultBody.error(msg);
        }
    }

    @Override
    public ResultBody viewContract(String contractId) {
        FddBaseClient baseClient = new FddBaseClient(FddConnectConstant.APP_ID, FddConnectConstant.APP_KEY, FddConnectConstant.VERSION, FddConnectConstant.HOST);
        ViewPdfURLParams params = new ViewPdfURLParams();
        //此处传入调用上传或填充合同接口成功时定义的合同编号
        params.setContractId(contractId);
        String result = baseClient.invokeViewPdfURL(params);
        String base64 = new String(FddEncryptTool.Base64Encode(result.getBytes())).trim();
        return ResultBody.success(base64);
    }

    @Override
    public ResultBody downloadContract(String contractId) {
        FddBaseClient baseClient = new FddBaseClient(FddConnectConstant.APP_ID, FddConnectConstant.APP_KEY, FddConnectConstant.VERSION, FddConnectConstant.HOST);
        DownloadPdfParams params = new DownloadPdfParams();
        // 合同编号
        params.setContractId(contractId);
        //如下，传setPath参数可以直接保存文件到本地，不传则返回url
//        params.setPath(""); // 指定路径，如：D:\\pdf\\uuidNew.pdf
        String result = baseClient.invokeDownloadPdf(params);
        String base64 = new String(FddEncryptTool.Base64Encode(result.getBytes())).trim();
        return ResultBody.success(base64);
    }


    @Override
    public ResultBody stamp(String contractId, LoginSuccessDTO loginSuccessDTO, String pages, Integer port, String customerId) {
        UserFddDO userFddDO;
        if (port.equals(0)) {
            // 根据客户id获取认证信息
            userFddDO = userFddAuthDao.getAppUserFddInfoByCustomerId(customerId);
            if (null == userFddDO) {
                return ResultBody.error(ResultEnum.BUSINESS_LICENSE_CHECK_ERROR);
            }
            boolean isPersonVerified = userFddDO.getAccountType().equals(1) && userFddDO.getPersonVerifyStatus().equals(2);
            boolean isEntVerified = userFddDO.getAccountType().equals(2) && userFddDO.getEntVerifyStatus().equals(4);
            if (!isPersonVerified && !isEntVerified) {
                return ResultBody.error(ResultEnum.BUSINESS_LICENSE_CHECK_NOT_PASS);
            }
        } else {
            ResultBody resultBody = sealManageService.checkAuthStatus(port, loginSuccessDTO);
            if (!resultBody.getCode().equals("200")) {
                return resultBody;
            }
            userFddDO = (UserFddDO) resultBody.getResult();
        }
        // 获取合同信息
        ContractInfoDO contractInfo = contractDao.contractInfoByOrderNo(null, contractId);
        FddBaseClient baseClient = new FddBaseClient(FddConnectConstant.APP_ID, FddConnectConstant.APP_KEY, FddConnectConstant.VERSION, FddConnectConstant.HOST);
        ExtSignParams params = new ExtSignParams();
        String transactionId = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        //平台自定义唯一交易号
        params.setTransactionId(transactionId);
        //此处传入调用上传或填充合同接口成功时定义的合同编号
        params.setContractId(contractId);
        params.setCustomerId(userFddDO.getCustomerId());
        params.setDocTitle(contractInfo.getContractTitle());
        if (pages != null) {
            params.setOpenEnvironment("1");
            params.setReturnUrl(pages);
        } else {
            params.setOpenEnvironment("0");
        }
        params.setNotifyUrl(FddConnectConstant.MMC_URL + FddConstant.NOTIFY_STAMP);
        if (port.equals(0) && userFddDO.getAccountType().equals(1)) {
            params.setMobileSignType("2");
        }
        String result = baseClient.invokeExtSign(params);
        // 将链接转成base64返回
        String base64 = new String(FddEncryptTool.Base64Encode(result.getBytes())).trim();
        ContractInfoDO updateContract = new ContractInfoDO();
        updateContract.setContractNo(contractId);
        if (contractInfo.getUnionId().equals(userFddDO.getUnionId())) {
            updateContract.setATransactionId(transactionId);
        } else {
            updateContract.setBTransactionId(transactionId);
        }
        contractDao.updateContractInfo(updateContract);
        return ResultBody.success(base64);
    }

    @Override
    public ResultBody notifyStamp(Map<String, String> map) {
        log.info("合同签署异步回调返回数据，{}", map.toString());
        String transactionId = map.get("transaction_id");// 交易号
        String contractId = map.get("contract_id");// 合同编号
        String resultCode = map.get("result_code");// 返回的code码
        String resultDesc = map.get("result_desc");// 签章结果描述信息
        String timestamp = map.get("timestamp");// 时间戳
        String msgDigest = map.get("msg_digest");// 摘要
        String sha1 = FddEncryptTool.sha1(FddConnectConstant.APP_KEY + transactionId);
        try {
            String md5 = FddEncryptTool.md5Digest(timestamp);
            String outSha1 = FddEncryptTool.sha1(FddConnectConstant.APP_ID + md5 + sha1);
            String base64 = new String(FddEncryptTool.Base64Encode(outSha1.getBytes())).trim();
            if (!base64.equals(msgDigest)) {
                return ResultBody.error(ResultEnum.NOT_FOUND);
            }
        } catch (Exception e) {
            return ResultBody.error(ResultEnum.NOT_FOUND);
        }
        // 获取合同信息
        ContractInfoDO contractInfoDO = contractDao.contractInfoByOrderNo(null, contractId);
        log.info(contractInfoDO.toString());
        String orderNo = contractInfoDO.getOrderNo();
        ContractInfoDO updateSignStatus = new ContractInfoDO();
        updateSignStatus.setContractNo(contractId);
        if (contractInfoDO.getSignStatus() == 0 && FddConstant.SIGN_SUCCESS.equals(resultCode) && contractInfoDO.getATransactionId().equals(transactionId)) {
            // 甲方公司签章成功
            updateSignStatus.setSignStatus(2);
            updateSignStatus.setARemark(resultDesc);
        } else if (contractInfoDO.getSignStatus() == 0 && FddConstant.SIGN_FAIL.equals(resultCode) && contractInfoDO.getATransactionId().equals(transactionId)) {
            // 甲方公司签章失败
            updateSignStatus.setSignStatus(1);
            updateSignStatus.setBRemark(resultDesc);
        } else if (contractInfoDO.getSignStatus() == 2 && FddConstant.SIGN_SUCCESS.equals(resultCode) && contractInfoDO.getBTransactionId().equals(transactionId)) {
            // 乙方公司签章成功
            log.info("成功进入");
            updateSignStatus.setSignStatus(4);
            updateSignStatus.setBRemark(resultDesc);
            updateSignStatus.setSingerTime(new Date());

            if(orderNo.startsWith(FddConstant.FN)) {
                // 乙方生成后台对应的账号
                UserApplyTagDO userApplyTag = cooperationDao.getUserApplyTagByContractId(contractId);
                BUserAccountVO bUserAccountVO = this.generateBackUserAccountVO(userApplyTag);
                log.info("check apply cooperation tag, bUserAccountVO:{}", com.alibaba.fastjson2.JSONObject.toJSONString(bUserAccountVO));
                ResultBody resultBody = backUserAccountService.insertBAccount(bUserAccountVO, null);
                log.info(resultBody.toString());
                if (!resultBody.getCode().equals(ResultEnum.SUCCESS.getResultCode())) {
                    // 生成账号失败处理
                    log.info("生成失败");
                    throw new BizException(ResultEnum.COOPERATION_CHECK_NOT_PASS_ERROR);
                }
                SmsUtil.sendPassCooperationApply(bUserAccountVO.getPhoneNum());
            }
            // 同步订单状态
            ContractInfoDTO contractInfoDTO = contractInfoDO.buildContractInfoDTO();
            contractInfoDTO.setSignStatus(4);
            log.info("到达mq");
            log.info("到达mq");
            mqProducer.sentFinishOrderSign(contractInfoDTO);
        } else if (contractInfoDO.getSignStatus() == 2 && FddConstant.SIGN_FAIL.equals(resultCode) && contractInfoDO.getBTransactionId().equals(transactionId)) {
            // 乙方公司签章失败
            updateSignStatus.setSignStatus(3);
            updateSignStatus.setBRemark(resultDesc);
        }
        log.info(updateSignStatus.toString());
        log.info(updateSignStatus.toString());
        contractDao.updateContractInfo(updateSignStatus);
        return ResultBody.success();
    }

    @Override
    public ResultBody file(String contractId, LoginSuccessDTO loginSuccessDTO, Integer port) {
        ResultBody resultBody = sealManageService.checkAuthStatus(port, loginSuccessDTO);
        if (!resultBody.getCode().equals("200")) {
            return resultBody;
        }
        // 判断该合同状态是否可以归档
        ContractInfoDO contractInfoDO = contractDao.contractInfoByOrderNo(null, contractId);
        if (!contractInfoDO.getSignStatus().equals(4)) {
            return ResultBody.error("当前状态不可进行归档操作！");
        }
        FddBaseClient baseClient = new FddBaseClient(FddConnectConstant.APP_ID, FddConnectConstant.APP_KEY, FddConnectConstant.VERSION, FddConnectConstant.HOST);
        ContractFillingParams params = new ContractFillingParams();
        //此处传入调用上传或填充合同接口成功时定义的合同编号
        params.setContractId(contractId);
        String result = baseClient.invokeContractFilling(params);
        if (!JSONObject.parseObject(result).getString(FddConstant.CODE).equals(FddConstant.SUCCESS_CODE)) {
            return ResultBody.error(JSONObject.parseObject(result).getString(FddConstant.MSG));
        }
        ContractInfoDO contractDetailDO = new ContractInfoDO();
        contractDetailDO.setContractNo(contractId);
        contractDetailDO.setSignStatus(5);
        contractDetailDO.setArchiveDate(new Date());
        contractDao.updateContractInfo(contractDetailDO);
        return ResultBody.success(JSONObject.parseObject(result));
    }

    @Override
    public List<ContractInfoDTO> listContractInfoByOrderNo(List<String> orderNos) {
        // 根据订单编号获取合同信息
        List<ContractInfoDO> contractInfoDOList = contractDao.listContractInfoByOrderNo(orderNos);
        return contractInfoDOList == null ? null : contractInfoDOList.stream().map(ContractInfoDO::buildContractInfoDTO).collect(Collectors.toList());
    }


    private BUserAccountVO generateBackUserAccountVO(UserApplyTagDO userApplyTagDO) {
        BUserAccountVO bUserAccountVO = new BUserAccountVO();
        UserAccountVO userAccountVO = userAccountService.getUserAccountById(userApplyTagDO.getUserAccountId());
        bUserAccountVO.setAccountNo(userAccountVO.getPhoneNum());
        bUserAccountVO.setUserName(userApplyTagDO.getApplyName());
        bUserAccountVO.setPhoneNum(userAccountVO.getPhoneNum());
        // String password = "YXF123456";
        bUserAccountVO.setPassWord(userAccountVO.getPhoneNum());
        bUserAccountVO.setAlertPwd(userAccountVO.getPhoneNum());
        bUserAccountVO.setAccountStatus(1);
        // 根据加盟类型分配角色
        if (userApplyTagDO.getCooperationTagId().equals(3)) {
            bUserAccountVO.setRoleId(RoleEnums.LEASE_FRANCHISEE.getId());
        } else if (userApplyTagDO.getCooperationTagId().equals(5)) {
            bUserAccountVO.setRoleId(RoleEnums.SERVICE_FRANCHISEE.getId());
        } else {
            bUserAccountVO.setRoleId(RoleEnums.FRANCHISEE.getId());
        }
        // 添加单位id
        CompanyInfoDO companyInfo = this.getCompanyInfo(userApplyTagDO);
        bUserAccountVO.setCompanyId(companyInfo.getId());
        bUserAccountVO.setRemark("加盟商自动生成");
        return bUserAccountVO;
    }

    private CompanyInfoDO getCompanyInfo(UserApplyTagDO userApplyTagDO) {
        // 查询小程序用户认证单位信息
        CompanyAuthDO companyAuth = companyAuthDao.getCompanyAuth(userApplyTagDO.getUserAccountId());
        // 验证是否已经添加单位信息
        CompanyInfoDO existCompanyInfo = companyDao.getCompanyInfoByName(companyAuth.getCompanyName());
        // 添加单位信息
        if (existCompanyInfo == null) {
            CompanyInfoDO companyInfoDO = new CompanyInfoDO();
            companyInfoDO.setCompanyType(1);
            companyInfoDO.setCompanyName(companyAuth.getCompanyName());
            companyInfoDO.setFullName(companyAuth.getCompanyName());
            companyInfoDO.setCompanyUserName(userApplyTagDO.getApplyName());
            companyInfoDO.setPhoneNum(userApplyTagDO.getApplyPhone());
            companyDao.addCompanyInfo(companyInfoDO);
            return companyInfoDO;
        } else {
            return existCompanyInfo;
        }
    }
}
