package com.gree.mall.manager.logic.fadada;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.gree.mall.manager.constant.Constant;
import com.gree.mall.manager.enums.IsYesNoEnum;
import com.gree.mall.manager.enums.contract.SignContractStatusEnum;
import com.gree.mall.manager.exception.RemoteServiceException;
import com.gree.mall.manager.plus.entity.AdminWebsit;
import com.gree.mall.manager.plus.entity.CompanyCaAuth;
import com.gree.mall.manager.plus.entity.WebsitContractSignItem;
import com.gree.mall.manager.plus.entity.WebsitContractSignRecord;
import com.gree.mall.manager.plus.service.AdminWebsitService;
import com.gree.mall.manager.plus.service.CompanyCaAuthService;
import com.gree.mall.manager.plus.service.WebsitContractSignItemService;
import com.gree.mall.manager.plus.service.WebsitContractSignRecordService;
import com.gree.mall.manager.utils.fadada.Auth4FDDUtil;
import com.gree.mall.manager.utils.oss.OSSUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

@Service
@Slf4j
@RequiredArgsConstructor
public class FDDNotifyLogic {

    private final RedisLockRegistry redisLockRegistry;
    private final OSSUtil ossUtil;
    private final CompanyCaAuthService companyCaAuthService;
    private final AdminWebsitService adminWebsitService;
    private final WebsitContractSignRecordService websitContractSignRecordService;
    private final WebsitContractSignItemService websitContractSignItemService;
    @Value("${fadada.company.auth.auto.notify.url}")
    private String fddAuthAutoNotifyUrl;

    /**
     * CA实名企业认证回调
     * @param params
     */
    public void caCompanyAuthResult(Map<String, String> params) {
        log.info("CA法大大实名企业认证回调通知结果：{}", JSONUtil.toJsonStr(params));
        if (!validCACompanyAuthSign(params)) {
            return;
        }
        this.queryCACompanyAuthResult(params.get("serialNo"));
    }

    private boolean validCACompanyAuthSign(Map<String, String> params) {
        if (CollectionUtil.isEmpty(params)) {
            return false;
        }
        String authenticationType = params.get("authenticationType");
        String certStatus = params.get("certStatus");
        String customerId = params.get("customerId");
        String serialNo = params.get("serialNo");
        String status = params.get("status");
        String statusDesc = params.get("statusDesc");
        String timestamp = params.get("timestamp");
        String sign = params.get("sign");
        String signStr = authenticationType + certStatus + customerId + serialNo + status + statusDesc;
        String newSign = Auth4FDDUtil.getMsgDigest(signStr, timestamp);
        log.info("CA法大大实名企业认证回调验签：{} {}", sign, newSign);
        return sign.equals(newSign);
    }

    public void queryCACompanyAuthResult(String transactionNo) {
        CompanyCaAuth companyCaAuth = companyCaAuthService.lambdaQuery()
                .eq(CompanyCaAuth::getFadadaTransactionNo, transactionNo)
                .one();
        if (Objects.isNull(companyCaAuth)) {
            log.error("法大大实名企业交易号不存在：" + transactionNo);
            return;
        }

        JSONObject info = Auth4FDDUtil.findCompanyCertInfo(transactionNo);
        JSONObject data = info.getJSONObject("data");
        JSONObject company = data.getJSONObject("company");
        JSONObject manager = data.getJSONObject("manager");
        String companyStatus = company.get("status", String.class);
        String managerStatus = manager.get("status", String.class);
        if (companyStatus.equals("4") && managerStatus.equals("2")) {
            String authAutoId = IdWorker.get32UUID();
            String authAutoContractId = IdWorker.getIdStr();
            String authAutoUrl = Auth4FDDUtil.beforeAuthAuto(authAutoId, authAutoContractId,
                    companyCaAuth.getFadadaCustomerId(), null, this.fddAuthAutoNotifyUrl);
            companyCaAuthService.lambdaUpdate()
                    .set(CompanyCaAuth::getFadadaIsAuth, IsYesNoEnum.YES.getKey())
                    .set(CompanyCaAuth::getFadadaStatus, companyStatus)
                    .set(CompanyCaAuth::getFadadaAuditFailReason, null)
                    .set(CompanyCaAuth::getFadadaAuthAutoId, authAutoId)
                    .set(CompanyCaAuth::getFadadaAuthAutoContractId, authAutoContractId)
                    .set(CompanyCaAuth::getFadadaAuthAutoUrl, authAutoUrl)
                    .eq(CompanyCaAuth::getCompanyCaAuthId, companyCaAuth.getCompanyCaAuthId())
                    .update();
        } else {
            String statusDesc = "";
            if (!managerStatus.equals("2")) {
                statusDesc = manager.get("auditFailReason", String.class);
                companyCaAuthService.lambdaUpdate()
                        .set(CompanyCaAuth::getFadadaIsAuth, IsYesNoEnum.NO.getKey())
                        .set(CompanyCaAuth::getFadadaStatus, "M" + managerStatus)
                        .set(CompanyCaAuth::getFadadaAuditFailReason, statusDesc)
                        .eq(CompanyCaAuth::getCompanyCaAuthId, companyCaAuth.getCompanyCaAuthId())
                        .update();
            } else {
                statusDesc = company.get("auditFailReason", String.class);
                companyCaAuthService.lambdaUpdate()
                        .set(CompanyCaAuth::getFadadaIsAuth, IsYesNoEnum.NO.getKey())
                        .set(CompanyCaAuth::getFadadaStatus, "C" + companyStatus)
                        .set(CompanyCaAuth::getFadadaAuditFailReason, statusDesc)
                        .eq(CompanyCaAuth::getCompanyCaAuthId, companyCaAuth.getCompanyCaAuthId())
                        .update();
            }
        }
    }

    public void caCompanyAuthAutoResult(Map<String, String> params) {
        log.info("CA法大大实名企业授权自动签回调通知结果：{}", JSONUtil.toJsonStr(params));
        if (!validCACompanyAuthAutoSign(params)) {
            return;
        }
        this.queryCACompanyAuthAutoResult(params);
    }

    private boolean validCACompanyAuthAutoSign(Map<String, String> params) {
        if (CollectionUtil.isEmpty(params)) {
            return false;
        }
        String transactionId = params.get("transaction_id");
        String timestamp = params.get("timestamp");
        String sign = params.get("msg_digest");
        String newSign = Auth4FDDUtil.getMsgDigest(transactionId, timestamp);
        log.info("CA法大大实名企业授权自动签回调验签：{} {}", sign, newSign);
        return sign.equals(newSign);
    }

    private void queryCACompanyAuthAutoResult(Map<String, String> params) {
        String transactionId = params.get("transaction_id");
        String contractId = params.get("contract_id");
        String viewPdfUrl = params.get("viewpdf_url");
        String downloadUrl = params.get("download_url");
        CompanyCaAuth companyCaAuth = companyCaAuthService.lambdaQuery()
                .eq(CompanyCaAuth::getFadadaAuthAutoId, transactionId)
                .eq(CompanyCaAuth::getFadadaAuthAutoContractId, contractId)
                .one();
        if (Objects.isNull(companyCaAuth)) {
            log.error("法大大企业授权自动签交易号不存在：" + transactionId);
            return;
        }

        JSONObject info = Auth4FDDUtil.queryAuthAutoStatus(companyCaAuth.getFadadaCustomerId());
        JSONObject data = info.getJSONObject("data");
        String queryTransactionNo = data.get("transactionId", String.class);
        String queryContractId = data.get("contractId", String.class);
        String queryStatus = data.get("status", String.class);
        if (queryTransactionNo.equals(transactionId) && queryContractId.equals(contractId) && queryStatus.equals("1")) {
            companyCaAuthService.lambdaUpdate()
                    .set(CompanyCaAuth::getFadadaAuthAutoStatus, IsYesNoEnum.YES.getKey())
                    .set(CompanyCaAuth::getFadadaAuthAutoViewpdfUrl, viewPdfUrl)
                    .set(CompanyCaAuth::getFadadaAuthAutoDownloadUrl, downloadUrl)
                    .eq(CompanyCaAuth::getCompanyCaAuthId, companyCaAuth.getCompanyCaAuthId())
                    .update();
        }
    }

    public void websitAuthResultHandle(AdminWebsit websit) {
        JSONObject info = Auth4FDDUtil.findCompanyCertInfo(websit.getFadadaWebsitNo());
        if (!info.containsKey("data")) {
            log.error("法大大网点企业认证data不存在：" + websit.getFadadaWebsitNo());
            return;
        }
        JSONObject data = info.getJSONObject("data");
        JSONObject person = data.getJSONObject("company");
        String status = person.get("status", String.class);
        String auditFailReason = person.get("auditFailReason", String.class, true);
        String regFormPath = person.get("regFormPath", String.class, true);
        String organizationPath = person.get("organizationPath", String.class, true);
        if (!status.equals("4")) {
            websit.setFadadaWebsitRealStatus(IsYesNoEnum.NO.getKey())
                    .setFadadaAuthFailReason(auditFailReason);
        } else {
            websit.setFadadaWebsitRealStatus(IsYesNoEnum.YES.getKey())
                    .setFadadaAuthFailReason("")
                    .setFadadaRegFormPath(regFormPath)
                    .setFadadaOrganizationPath(organizationPath);
        }
    }

    public void websitPersonAuthResultHandle(AdminWebsit websit) {
        JSONObject info = Auth4FDDUtil.findPersonCertInfo(websit.getFadadaCustomerNo());
        if (!info.containsKey("data")) {
            log.error("法大大网点负责人认证data不存在：" + websit.getFadadaCustomerNo());
            return;
        }
        JSONObject data = info.getJSONObject("data");
        JSONObject person = data.getJSONObject("person");

        String status = person.get("status", String.class);
        String auditFailReason = person.get("auditFailReason", String.class, true);
        String photoUuid = person.get("photoUuid", String.class, true);
        String headPhotoPath = person.get("headPhotoPath", String.class, true);
        String backgroundIdCardPath = person.get("backgroundIdCardPath", String.class, true);
        Date auditorTime = person.get("auditorTime", Date.class, true);
        if (!status.equals("2")) {
            websit.setFadadaCustomerRealStatus(IsYesNoEnum.NO.getKey())
                    .setFadadaAuthFailReason(auditFailReason);
        } else {
            websit.setFadadaCustomerRealStatus(IsYesNoEnum.YES.getKey())
                    .setFadadaAuthFailReason("");
            websit.setFadadaCustomerHeadPhotoPath(headPhotoPath);
            if (StringUtils.isNotBlank(photoUuid)) {
                websit.setFadadaCustomerAuditorTime(auditorTime)
                        .setFadadaCustomerPhotoUuid(photoUuid);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void websitAuthResult(Map<String, String> params) {
        log.info("法大大实名网点企业认证回调通知结果：{}", JSONUtil.toJsonStr(params));
        this.queryWebsitAuthResult(params.get("serialNo"));
    }

    private void queryWebsitAuthResult(String transactionNo) {
        AdminWebsit websit = adminWebsitService.lambdaQuery()
                .eq(AdminWebsit::getFadadaWebsitNo, transactionNo).last("limit 1")
                .one();

        if (Objects.isNull(websit)) {
            log.error("法大大企业认证交易号不存在：" + transactionNo);
            return;
        }

        this.websitAuthResultHandle(websit);

        adminWebsitService.lambdaUpdate()
                .set(AdminWebsit::getFadadaWebsitRealStatus, websit.getFadadaWebsitRealStatus())
                .set(AdminWebsit::getFadadaAuthFailReason, websit.getFadadaAuthFailReason())
                .set(AdminWebsit::getFadadaRegFormPath, websit.getFadadaRegFormPath())
                .set(AdminWebsit::getFadadaOrganizationPath, websit.getFadadaOrganizationPath())
                .eq(AdminWebsit::getWebsitId, websit.getWebsitId())
                .update();
    }

    public void websitPersonAuthResul(Map<String, String> params) {
        log.info("法大大实名网点负责人认证回调通知结果：{}", JSONUtil.toJsonStr(params));
        this.websitPersonAuthResul(params.get("serialNo"));
    }

    public void websitPersonAuthResul(String transactionNo) {
        AdminWebsit websit = adminWebsitService.lambdaQuery()
                .eq(AdminWebsit::getFadadaCustomerNo, transactionNo)
                .one();

        if (Objects.isNull(websit)) {
            log.error("法大大网点负责人认证交易号不存在：" + transactionNo);
            return;
        }

        this.websitPersonAuthResultHandle(websit);

        adminWebsitService.lambdaUpdate()
                .set(AdminWebsit::getFadadaCustomerRealStatus, websit.getFadadaCustomerRealStatus())
                .set(AdminWebsit::getFadadaAuthFailReason, websit.getFadadaAuthFailReason())
                .set(AdminWebsit::getFadadaCustomerHeadPhotoPath, websit.getFadadaCustomerHeadPhotoPath())
                .set(AdminWebsit::getFadadaCustomerAuditorTime, websit.getFadadaCustomerAuditorTime())
                .set(AdminWebsit::getFadadaCustomerPhotoUuid, websit.getFadadaCustomerPhotoUuid())
                .eq(AdminWebsit::getWebsitId, websit.getWebsitId())
                .update();
    }

    public void websitBatchSignResult(Map<String, String> params) throws InterruptedException {

        log.info("法大大企业批量签署回调通知结果：{}", JSONUtil.toJsonStr(params));
        String transactionId = params.get("transaction_id");
        String contractId = params.get("contract_id");
        String resultCode = params.get("result_code");
        String msgDigest = params.get("msg_digest");
        String timestamp = params.get("timestamp");
//        String viewpdfUrl = params.get("viewpdf_url");
//        String downloadUrl = params.get("download_url");

        // 验签
        String newMsgDigest = Auth4FDDUtil.getMsgDigest(transactionId, timestamp);

        if (msgDigest.equals(newMsgDigest) && resultCode.equals("3000")) {
            // 签署成功执行以下逻辑
            WebsitContractSignItem websitFile = websitContractSignItemService.lambdaQuery()
                    .eq(WebsitContractSignItem::getFadadaTransactionId, transactionId)
                    .or()
                    .eq(WebsitContractSignItem::getManagerTransactionId, transactionId)
                    .one();

            if (Objects.isNull(websitFile)) {
                return;
            }

            WebsitContractSignRecord record = websitContractSignRecordService.getById(websitFile.getWebsitContractSignRecordId());

            Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.FDD_BATCH_SIGN_NOTIFY + record.getWebsitId());
            if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
                throw new RemoteServiceException("冻结二级网点");
            }
            try {
                AdminWebsit websit = adminWebsitService.getById(record.getWebsitId());

                if (!record.getStatus().equals(SignContractStatusEnum.WAIT_SIGN.getKey())) {
                    log.info("签约流程完结: " + websit.getWebsitId() + websit.getName());
                    return;
                }

                List<WebsitContractSignItem> websitFiles = websitContractSignItemService.lambdaQuery()
                        .eq(WebsitContractSignItem::getWebsitContractSignRecordId, record.getId())
                        .isNotNull(WebsitContractSignItem::getFadadaTemplateId)
                        .list();

                // 判断公章签约
                final long companySign = websitFiles.stream()
                        .filter(v -> v.getNeedCompanySign().equals(IsYesNoEnum.YES.getKey()) && v.getCompanySignStatus().equals(IsYesNoEnum.NO.getKey()))
                        .count();
                if (companySign > 0) {
                    // 遍历查询签章状态
                    boolean sign = false;
                    for (WebsitContractSignItem file : websitFiles) {
                        if (file.getNeedCompanySign().equals(IsYesNoEnum.YES.getKey())) {
                            JSONObject object = Auth4FDDUtil.querySignStatus(file.getFadadaContractId(), websit.getFadadaWebsitId(), file.getFadadaTransactionId());
                            Integer code = object.get("code", Integer.class);
                            String msg = object.get("msg", String.class);
                            JSONObject data = object.getJSONObject("data");
                            if (code != 1) {
                                log.error("查询公章签约出错: " + msg);
                                throw new RemoteServiceException(msg);
                            }
                            String result = data.get("result", String.class);
                            String result_desc = data.get("result_desc", String.class);
                            sign = result.equals("3000");
                            if (!result.equals("3000")) {
                                log.error("查询公章签署状态: " + result + result_desc);
                                return;
                            }
                            file.setCompanySignStatus(IsYesNoEnum.YES.getKey());
                        }
                    }

                    if (sign) {
                        websitContractSignItemService.lambdaUpdate()
                                .set(WebsitContractSignItem::getCompanySignStatus, IsYesNoEnum.YES.getKey())
                                .eq(WebsitContractSignItem::getWebsitContractSignRecordId, record.getId())
                                .update();
                    }
                    // 公章签约流程后判断是否还需要负责人签，不需要就继续执行下去
                    final long count = websitFiles.stream()
                            .filter(v -> v.getNeedManagerSign().equals(IsYesNoEnum.YES.getKey()) && v.getManagerSignStatus().equals(IsYesNoEnum.NO.getKey()))
                            .count();
                    if (count > 0) {
                        return;
                    }
                    final long allOK = websitFiles.stream()
                            .filter(v -> v.getNeedCompanySign().equals(IsYesNoEnum.YES.getKey()) && v.getCompanySignStatus().equals(IsYesNoEnum.NO.getKey()))
                            .count();
                    if (allOK == 0) {
                        // 无需法人签，直接把记录改为待审核
                        websitContractSignItemService.lambdaUpdate()
                                .set(WebsitContractSignItem::getSignDate, DateUtil.date())
                                .set(WebsitContractSignItem::getContractStatus, SignContractStatusEnum.WAIT.getKey())
                                .eq(WebsitContractSignItem::getWebsitContractSignRecordId, record.getId())
                                .update();
                        record.setFadadaWebsitId(websit.getFadadaWebsitId())
                                .setAuthStatus(IsYesNoEnum.YES.getKey())
                                .setFadadaWebsitNo(websit.getFadadaWebsitNo())
                                .setFadadaCustomerId(websit.getFadadaCustomerId())
                                .setFadadaCustomerNo(websit.getFadadaCustomerNo())
                                .setStatus(SignContractStatusEnum.WAIT.getKey())
                                .updateById();
                        return;
                    }
                }

                // 判断法人签约
                final long managerSign = websitFiles.stream()
                        .filter(v -> v.getNeedManagerSign().equals(IsYesNoEnum.YES.getKey()) && v.getManagerSignStatus().equals(IsYesNoEnum.NO.getKey()))
                        .count();
                if (managerSign > 0) {
                    boolean sign = false;
                    for (WebsitContractSignItem file : websitFiles) {
                        if (file.getNeedManagerSign().equals(IsYesNoEnum.YES.getKey()) && StringUtils.isNotBlank(file.getManagerTransactionId())) {
                            JSONObject object = Auth4FDDUtil.querySignStatus(file.getFadadaContractId(), websit.getFadadaCustomerId(), file.getManagerTransactionId());
                            Integer code = object.get("code", Integer.class);
                            String msg = object.get("msg", String.class);
                            JSONObject data = object.getJSONObject("data");
                            if (code != 1) {
                                log.error("查询法人签约出错: " + msg);
                                throw new RemoteServiceException(msg);
                            }
                            String result = data.get("result", String.class);
                            String result_desc = data.get("result_desc", String.class);
                            sign = result.equals("3000");
                            if (!result.equals("3000")) {
                                log.error("查询法人签署状态: " + result + result_desc);
                                return;
                            }
                            file.setManagerSignStatus(IsYesNoEnum.YES.getKey());
                        }
                    }
                    if (sign) {
                        websitContractSignItemService.lambdaUpdate()
                                .set(WebsitContractSignItem::getManagerSignStatus, IsYesNoEnum.YES.getKey())
                                .set(WebsitContractSignItem::getSignDate, DateUtil.date())
                                .set(WebsitContractSignItem::getContractStatus, SignContractStatusEnum.WAIT.getKey())
                                .eq(WebsitContractSignItem::getWebsitContractSignRecordId, record.getId())
                                .update();
                        record.setSignTime(DateUtil.date())
                                .setAuthStatus(IsYesNoEnum.YES.getKey())
                                .setFadadaWebsitId(websit.getFadadaWebsitId())
                                .setFadadaWebsitNo(websit.getFadadaWebsitNo())
                                .setFadadaCustomerId(websit.getFadadaCustomerId())
                                .setFadadaCustomerNo(websit.getFadadaCustomerNo())
                                .setStatus(SignContractStatusEnum.WAIT.getKey())
                                .updateById();
                    }
                }


            } finally {
                obtain.unlock();
            }
        }
    }
}
