package com.tmerclub.cloud.payment.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.multishop.feign.ShopBankCardFeignClient;
import com.tmerclub.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.tmerclub.cloud.api.multishop.vo.ShopBankCardVO;
import com.tmerclub.cloud.api.payment.allinpay.member.resp.*;
import com.tmerclub.cloud.api.payment.dto.BindCompanyAccountDTO;
import com.tmerclub.cloud.api.payment.dto.SetCompanyInfoDTO;
import com.tmerclub.cloud.api.payment.dto.UpdateCompanyInfoDTO;
import com.tmerclub.cloud.api.supplier.feign.SupplierBankCardFeignClient;
import com.tmerclub.cloud.api.supplier.feign.SupplierDetailFeignClient;
import com.tmerclub.cloud.api.supplier.vo.SupplierBankCardVO;
import com.tmerclub.cloud.common.cache.constant.CacheNames;
import com.tmerclub.cloud.common.cache.constant.PaymentCacheNames;
import com.tmerclub.cloud.common.cache.util.RedisUtil;
import com.tmerclub.cloud.common.constant.AllinpayConstant;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.IdCardCollectProcessStatus;
import com.tmerclub.cloud.common.constant.SignAcctType;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.payment.allinpay.OpenClient;
import com.tmerclub.cloud.payment.allinpay.member.constant.*;
import com.tmerclub.cloud.payment.allinpay.member.req.*;
import com.tmerclub.cloud.payment.allinpay.member.constant.*;
import com.tmerclub.cloud.payment.allinpay.member.req.*;
import com.tmerclub.cloud.payment.allinpay.member.resp.ApplyBindBankCardResp;
import com.tmerclub.cloud.payment.allinpay.member.resp.CardBinInfo;
import com.tmerclub.cloud.payment.allinpay.member.resp.PhoneVerificationResp;
import com.tmerclub.cloud.payment.allinpay.service.AllinpayMemberService;
import com.tmerclub.cloud.payment.config.AllinpayConfig;
import com.tmerclub.cloud.payment.constant.DistributedIdKey;
import com.tmerclub.cloud.payment.dto.*;
import com.tmerclub.cloud.payment.dto.*;
import com.tmerclub.cloud.payment.service.AllinpayCompanyService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author TRACK
 */
@Service
public class AllinpayCompanyServiceImpl implements AllinpayCompanyService {

    @Autowired
    private AllinpayMemberService allinpayMemberService;
    @Autowired
    private AllinpayConfig allinpayConfig;
    @Autowired
    private SegmentManager segmentManager;
    @DubboReference
    private ShopDetailFeignClient shopDetailFeignClient;
    @DubboReference
    private ShopBankCardFeignClient shopBankCardFeignClient;
    @DubboReference
    private SupplierDetailFeignClient supplierDetailFeignClient;
    @DubboReference
    private SupplierBankCardFeignClient supplierBankCardFeignClient;

    @Override
    public void createCompanyMember(String bizUserId) {
        CreateMember createMember = new CreateMember(bizUserId);
        createMember.setMemberType(MemberType.ENTERPRISE.value());
        createMember.setSource(VisitSourceType.PC.value());
        allinpayMemberService.createMember(createMember);
    }

    @Override
    @Cacheable(cacheNames = PaymentCacheNames.COMPANY_INFO, key = "#tenantId")
    public CompanyInfo getCompanyInfo(String tenantId) {
        GetMemberInfo getMemberInfo = new GetMemberInfo(tenantId);
        CompanyInfo companyInfo = allinpayMemberService.getCompanyInfo(getMemberInfo);
        // 解密
        OpenClient client = allinpayConfig.getClient();
        companyInfo.setLegalIds(Objects.isNull(companyInfo.getLegalIds()) ? null : client.decrypt(companyInfo.getLegalIds()));
        companyInfo.setAccountNo(Objects.isNull(companyInfo.getAccountNo()) ? null : client.encrypt(companyInfo.getAccountNo()));
        return companyInfo;
    }

    @Override
    public void sendVerificationCode(String bizUserId, VerificationCodeDTO verificationCodeDTO) {
        SendVerificationCode svc = new SendVerificationCode(bizUserId, verificationCodeDTO.getPhone());
        Integer type = verificationCodeDTO.getVerificationCodeType();
        if (type != null
                && VerificationCodeType.instance(type) != null) {
            svc.setVerificationCodeType(type);
        }
        allinpayMemberService.sendVerificationCode(svc);
    }

    @Override
    public void bindPhone(String bizUserId, VerificationCodeDTO verificationCodeDTO) {
        BindPhone bindPhone = new BindPhone(bizUserId, verificationCodeDTO.getPhone(), verificationCodeDTO.getVerificationCode());
        allinpayMemberService.bindPhone(bindPhone);
        // 更新绑定手机号码状态
        if (bizUserId.contains(AllinpayConstant.SHOP)) {
            ServerResponseEntity<Void> response = shopDetailFeignClient.updateAllinpayBindPhoneStatus(bizUserId, 1);
            if (!response.isSuccess()) {
                throw new LuckException(response.getMsg());
            }
        } else if (bizUserId.contains(AllinpayConstant.SUPPLIER)) {
            ServerResponseEntity<Void> response = supplierDetailFeignClient.updateAllinpayBindPhoneStatus(bizUserId, 1);
            if (!response.isSuccess()) {
                throw new LuckException(response.getMsg());
            }
        }
    }

    @Override
    public void unbindPhone(String bizUserId, VerificationCodeDTO verificationCodeDTO) {
        UnbindPhone unbindPhone = new UnbindPhone(bizUserId, verificationCodeDTO.getPhone(), verificationCodeDTO.getVerificationCode());
        PhoneVerificationResp phoneVerificationResp = allinpayMemberService.unbindPhone(unbindPhone);
        if (Objects.equals(Constant.ERROR, phoneVerificationResp.getResult())) {
            throw new LuckException("解绑手机失败");
        }
        // 更新绑定手机号码状态
        if (bizUserId.contains(AllinpayConstant.SHOP)) {
            ServerResponseEntity<Void> response = shopDetailFeignClient.updateAllinpayBindPhoneStatus(bizUserId, 0);
            if (!response.isSuccess()) {
                throw new LuckException(response.getMsg());
            }
        } else if (bizUserId.contains(AllinpayConstant.SUPPLIER)) {
            ServerResponseEntity<Void> response = supplierDetailFeignClient.updateAllinpayBindPhoneStatus(bizUserId, 0);
            if (!response.isSuccess()) {
                throw new LuckException(response.getMsg());
            }
        }
    }

    @Override
    public SetCompanyInfoResp setCompanyInfo(String tenantId, String backUrl, SetCompanyInfoDTO setCompanyInfoDTO) {
        OpenClient client = allinpayConfig.getClient();
        CompanyBasicInfo companyBasicInfo = new CompanyBasicInfo();
        BeanUtils.copyProperties(setCompanyInfoDTO, companyBasicInfo);
        companyBasicInfo.setLegalIds(client.encrypt(companyBasicInfo.getLegalIds()));
        companyBasicInfo.setAccountNo(client.encrypt(companyBasicInfo.getAccountNo()));
        companyBasicInfo.setAuthType(2);
        companyBasicInfo.setIdentityType(1);
        SetCompanyInfo setCompanyInfo = new SetCompanyInfo(tenantId, backUrl, companyBasicInfo);
        return allinpayMemberService.setCompanyInfo(setCompanyInfo);
    }

    @Override
    public UpdateCompanyInfoResp updateCompanyInfo(String tenantId, String backUrl, UpdateCompanyInfoDTO updateCompanyInfoDTO) {
        UpdateCompanyInfo updateCompanyInfo = new UpdateCompanyInfo();
        BeanUtils.copyProperties(updateCompanyInfoDTO, updateCompanyInfo);
        Long reqSn = segmentManager.getDateFormatSegmentId(DistributedIdKey.tmerclub_ALLINPAY_UPDATE_COMPANY_SN);
        updateCompanyInfo.setReqsn(String.valueOf(reqSn));
        updateCompanyInfo.setBackUrl(backUrl);
        updateCompanyInfo.setBizUserId(tenantId);
        updateCompanyInfo.setIdentityType(IdentityType.ID_CARD.value());
        if (Objects.nonNull(updateCompanyInfoDTO.getLegalIds()) && StrUtil.isNotBlank(updateCompanyInfoDTO.getLegalIds())) {
            OpenClient client = allinpayConfig.getClient();
            updateCompanyInfo.setLegalIds(client.encrypt(updateCompanyInfoDTO.getLegalIds()));
        }
        return allinpayMemberService.updateCompanyInfo(updateCompanyInfo);
    }

    @Override
    public IdCardCollectResp idCardCollect(IdCardCollectDTO idCardCollectDTO, String backUrl) {
        IdCardCollect idCardCollect = new IdCardCollect();
        BeanUtils.copyProperties(idCardCollectDTO, idCardCollect);
        idCardCollect.setOcrComparisonResultBackUrl(backUrl);
        return allinpayMemberService.idCardCollect(idCardCollect);
    }

    @Override
    public IdCardCollectByFileUploadResp idcardCollectByFileUpload(IdCardCollectByFileUpload idCardCollectByFileUpload) {
        return allinpayMemberService.idcardCollectByFileUpload(idCardCollectByFileUpload);
    }

    @Override
    public CardBinInfo getBankCardBin(String cardNo) {
        GetBankCardBin getBankCardBin = new GetBankCardBin();
        OpenClient client = allinpayConfig.getClient();
        getBankCardBin.setCardNo(client.encrypt(cardNo));
        return allinpayMemberService.getBankCardBin(getBankCardBin);
    }

    @Override
    public void applyBindBankCard(String tenantId, ApplyBankCardDTO applyBankCardDTO, String legalName) {
        // 最多只能绑定一张法人账户
        checkLegalCard(tenantId);
        OpenClient client = allinpayConfig.getClient();
        ApplyBindBankCard applyBindBankCard = new ApplyBindBankCard();
        BeanUtils.copyProperties(applyBankCardDTO, applyBindBankCard);
        applyBindBankCard.setName(legalName);
        applyBindBankCard.setBizUserId(tenantId);
        applyBindBankCard.setCardCheck(8);
        applyBindBankCard.setIdentityType(IdentityType.ID_CARD.value());
        applyBindBankCard.setIdentityNo(client.encrypt(applyBankCardDTO.getIdentityNo()));
        applyBindBankCard.setCardNo(client.encrypt(applyBankCardDTO.getCardNo()));
        ApplyBindBankCardResp applyBindBankCardResp = allinpayMemberService.applyBindBankCard(applyBindBankCard);
        ShopBankCardVO shopBankCardVO = getShopBankCard(applyBindBankCardResp, legalName);
        if (tenantId.contains(AllinpayConstant.SHOP)) {
            shopBankCardFeignClient.saveBandCardByAllinpay(tenantId, shopBankCardVO);
        } else if (tenantId.contains(AllinpayConstant.SUPPLIER)) {
            SupplierBankCardVO supplierBankCardVO = new SupplierBankCardVO();
            BeanUtils.copyProperties(shopBankCardVO, supplierBankCardVO);
            supplierBankCardFeignClient.saveBandCardByAllinpay(tenantId, supplierBankCardVO);
        }
    }

    private void checkLegalCard(String tenantId) {
        List<BindCard> bindCards = queryBankCard(tenantId, null);
        long bindCount = bindCards.stream().filter(card -> Objects.equals(card.getBankCardPro(), 0) && Objects.equals(card.getBindState(), 1)).count();
        if (bindCount == 1) {
            throw new LuckException("当前已绑定一张法人银行卡，无法继续绑定");
        }
    }

    @Override
    public void bindBankCard(String tenantId, BindBankCardDTO bindBankCardDTO, String legalName) {
        // 目前采用四要素绑卡，不需要调用这个方法
        // 最多只能绑定一张法人账户
        checkLegalCard(tenantId);
        BindBankCard bindBankCard = new BindBankCard();
        BeanUtils.copyProperties(bindBankCardDTO, bindBankCard);
        bindBankCard.setBizUserId(tenantId);
        allinpayMemberService.bindBankCard(bindBankCard);
    }

    private ShopBankCardVO getShopBankCard(ApplyBindBankCardResp bindBankCardResp, String legalName) {
        List<BindCard> bindCardList = queryBankCard(bindBankCardResp.getBizUserId(), null);
        List<BindCard> cardList = bindCardList.stream().filter(card -> Objects.equals(card.getBankCardPro(), 0) && Objects.equals(card.getBindState(), 1)).collect(Collectors.toList());
        BindCard bindCard = cardList.get(0);
        ShopBankCardVO shopBankCardVO = new ShopBankCardVO();
        shopBankCardVO.setBankName(bindCard.getBankName());
        shopBankCardVO.setCardNo(bindCard.getBankCardNo());
        shopBankCardVO.setRecipientName(legalName);
        shopBankCardVO.setOpeningBank(bindCard.getBankName());
        shopBankCardVO.setBranchName(bindCard.getBranchBankName());
        shopBankCardVO.setUnionBank(bindCard.getUnionBank());
        shopBankCardVO.setBankCardNo(bindCard.getBankCardNo());
        shopBankCardVO.setBankCardPro(0);
        return shopBankCardVO;
    }

    @Override
    public void unbindBankCard(String tenantId, UnbindBankCardDTO unbindBankCardDTO) {
        if (Objects.isNull(unbindBankCardDTO.getShopBankCardId())) {
            throw new LuckException("shopBankCardId不能为空");
        }
        List<BindCard> bindCards = queryBankCard(tenantId, unbindBankCardDTO.getCardNo());
        if (CollUtil.isEmpty(bindCards)) {
            throw new LuckException("当前银行卡不存在或未绑定");
        }
        if (!Objects.equals(bindCards.get(0).getBankCardPro(), 0)) {
            throw new LuckException("只有法人银行卡才能解绑");
        }
        if (tenantId.contains(AllinpayConstant.SHOP)) {
            ServerResponseEntity<Void> response = shopBankCardFeignClient.deleteLegalBankCard(unbindBankCardDTO.getShopBankCardId());
            if (!response.isSuccess()) {
                throw new LuckException(response.getMsg());
            }
        } else if (tenantId.contains(AllinpayConstant.SUPPLIER)) {
            ServerResponseEntity<Void> response = supplierBankCardFeignClient.deleteLegalBankCard(unbindBankCardDTO.getShopBankCardId());
            if (!response.isSuccess()) {
                throw new LuckException(response.getMsg());
            }
        }

        OpenClient client = allinpayConfig.getClient();
        UnbindBankCard unbindBankCard = new UnbindBankCard();
        unbindBankCard.setBizUserId(tenantId);
        unbindBankCard.setCardNo(client.encrypt(unbindBankCardDTO.getCardNo()));
        allinpayMemberService.unbindBankCard(unbindBankCard);
    }

    @Override
    public List<BindCard> queryBankCard(String tenantId, String cardNo) {
        QueryBankCard queryBankCard = new QueryBankCard(tenantId);
        if (cardNo != null) {
            OpenClient client = allinpayConfig.getClient();
            queryBankCard.setCardNo(client.encrypt(cardNo));
        }
        return allinpayMemberService.queryBankCard(queryBankCard);
    }

    @Override
    public void bindCompanyAccount(String bizUserId, BindCompanyAccountDTO bindCompanyAccountDTO, String companyName) {
        List<BindCard> bindCards = allinpayMemberService.queryBankCard(new QueryBankCard(bizUserId));
        if (CollUtil.isNotEmpty(bindCards)) {
            long bindCount = bindCards.stream().filter(card -> Objects.equals(card.getBankCardPro(), 1) && Objects.equals(card.getBindState(), 1)).count();
            if (bindCount >= Constant.MAX_COMPANY_CARD_NUM) {
                throw new LuckException("当前绑定对公户账户已超过10张，无法继续绑定");
            }
        }
        BindCompanyAccount bindCompanyAccount = new BindCompanyAccount();
        BeanUtils.copyProperties(bindCompanyAccountDTO, bindCompanyAccount);
        OpenClient client = allinpayConfig.getClient();
        bindCompanyAccount.setAccountNo(client.encrypt(bindCompanyAccountDTO.getAccountNo()));
        bindCompanyAccount.setBizUserId(bizUserId);
        allinpayMemberService.bindCompanyAccount(bindCompanyAccount);
        // 保存到数据库
        ShopBankCardVO shopBankCardVO = getShopBankCardVO(bindCompanyAccountDTO, companyName);
        if (bizUserId.contains(AllinpayConstant.SHOP)) {
            shopBankCardFeignClient.saveBandCardByAllinpay(bizUserId, shopBankCardVO);
        } else if (bizUserId.contains(AllinpayConstant.SUPPLIER)) {
            SupplierBankCardVO supplierBankCardVO = new SupplierBankCardVO();
            BeanUtils.copyProperties(shopBankCardVO, supplierBankCardVO);
            supplierBankCardFeignClient.saveBandCardByAllinpay(bizUserId, supplierBankCardVO);
        }
    }

    private static ShopBankCardVO getShopBankCardVO(BindCompanyAccountDTO bindCompanyAccountDTO, String companyName) {
        ShopBankCardVO shopBankCardVO = new ShopBankCardVO();
        shopBankCardVO.setBankName(bindCompanyAccountDTO.getParentBankName());
        shopBankCardVO.setRecipientName(companyName);
        shopBankCardVO.setCardNo(bindCompanyAccountDTO.getAccountNo());
        shopBankCardVO.setOpeningBank(bindCompanyAccountDTO.getParentBankName());
        shopBankCardVO.setBranchName(bindCompanyAccountDTO.getBankName());
        shopBankCardVO.setUnionBank(bindCompanyAccountDTO.getUnionBank());
        shopBankCardVO.setBankCardNo(bindCompanyAccountDTO.getAccountNo());
        shopBankCardVO.setBankCardPro(1);
        return shopBankCardVO;
    }

    @Override
    public void deleteCache(String tenantId) {
        RedisUtil.del(PaymentCacheNames.COMPANY_INFO + CacheNames.UNION + tenantId);
    }

    @Override
    public String signAcctProtocol(String bizUserId, String backUrl, SignAcctProtocolDTO signAcctProtocolDTO) {
        if (Objects.isNull(signAcctProtocolDTO.getJumpUrl()) || Objects.isNull(signAcctProtocolDTO.getNoContractUrl())) {
            throw new LuckException("跳转地址不能为空");
        }
        // 企业会员账户提现协议签约前须完成设置企业信息，且企业信息审核成功。
        CompanyInfo companyInfo = getCompanyInfo(bizUserId);
        if (Objects.isNull(companyInfo) || !Objects.equals(companyInfo.getStatus(), AuditStatus.SUCCESS.getCode())) {
            throw new LuckException("企业会员尚未通过审核，无法进行签约");
        }
        if (Objects.isNull(companyInfo.getPhone())) {
            throw new LuckException("尚未绑定手机号码，无法进行签约");
        }
        if (Objects.equals(signAcctProtocolDTO.getSignAcctType(), SignAcctType.LEGAL_PERSON.getValue())) {
            //  个人会员账户提现协议签约前须绑定银行卡成功。
            List<BindCard> bindCards = queryBankCard(bizUserId, null);
            long bindCount = bindCards.stream().filter(card -> Objects.equals(card.getBankCardPro(), 0) && Objects.equals(card.getBindState(), 1)).count();
            if (bindCount < 1) {
                throw new LuckException("当前未绑定法人银行卡，请进行绑定");
            }
        }
        SignAcctProtocol signAcctProtocol = new SignAcctProtocol();
        BeanUtils.copyProperties(signAcctProtocolDTO, signAcctProtocol);
        signAcctProtocol.setSignAcctName(Objects.equals(signAcctProtocolDTO.getSignAcctType(), 2) ? companyInfo.getLegalName() : companyInfo.getCompanyName());
        signAcctProtocol.setBizUserId(bizUserId);
        signAcctProtocol.setBackUrl(backUrl);
        signAcctProtocol.setSource(VisitSourceType.PC.value());
        return allinpayMemberService.signAcctProtocol(signAcctProtocol);
    }

    @Override
    public String signContractQuery(String bizUserId, SignAcctProtocolDTO signAcctProtocolDTO) {
        SignContractQuery signContractQuery = new SignContractQuery();
        BeanUtils.copyProperties(signAcctProtocolDTO, signContractQuery);
        signContractQuery.setBizUserId(bizUserId);
        signContractQuery.setSource(VisitSourceType.PC.value());
        return allinpayMemberService.signContractQuery(signContractQuery);
    }

    @Override
    public Integer getIdCardStatus(Integer ocrRegnumComparisonResult, Integer ocrIdcardComparisonResult) {
        if (Objects.isNull(ocrRegnumComparisonResult) && Objects.isNull(ocrIdcardComparisonResult)) {
            return IdCardCollectProcessStatus.UN_COMMITTED.value();
        }
        boolean companySuccess = Objects.equals(ocrRegnumComparisonResult, 1);
        boolean idCardSuccess = Objects.equals(ocrIdcardComparisonResult, 1);
        Integer status;
        if (companySuccess && idCardSuccess) {
            status = IdCardCollectProcessStatus.ALL.value();
        } else if (!companySuccess && !idCardSuccess) {
            status = IdCardCollectProcessStatus.WAIT_AUDIT.value();
        } else if (companySuccess) {
            status = IdCardCollectProcessStatus.REG.value();
        } else {
            status = IdCardCollectProcessStatus.ID_CARD.value();
        }
        return status;
    }

}
