
package com.tmerclub.cloud.payment.feign;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.auth.constant.SocialType;
import com.tmerclub.cloud.api.auth.constant.SysTypeEnum;
import com.tmerclub.cloud.api.payment.allinpay.member.resp.*;
import com.tmerclub.cloud.api.payment.allinpay.order.resp.PayByBackSmsResp;
import com.tmerclub.cloud.api.payment.allinpay.order.resp.QueryBalanceResp;
import com.tmerclub.cloud.api.payment.allinpay.order.resp.WithdrawApplyResp;
import com.tmerclub.cloud.api.payment.dto.AllinpayBalanceDTO;
import com.tmerclub.cloud.api.payment.dto.BindPayAcctDTO;
import com.tmerclub.cloud.api.payment.dto.SetCompanyInfoDTO;
import com.tmerclub.cloud.api.payment.dto.UpdateCompanyInfoDTO;
import com.tmerclub.cloud.api.payment.feign.AllinpayFeignClient;
import com.tmerclub.cloud.api.user.dto.UserExtensionDTO;
import com.tmerclub.cloud.api.user.feign.UserExtensionFeignClient;
import com.tmerclub.cloud.common.constant.AllinpayConstant;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.PayType;
import com.tmerclub.cloud.common.constant.PicType;
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.common.util.ImageUtil;
import com.tmerclub.cloud.payment.allinpay.constant.AllinpayNoticeUrl;
import com.tmerclub.cloud.payment.allinpay.member.constant.AuditStatus;
import com.tmerclub.cloud.payment.allinpay.member.constant.PayAcctType;
import com.tmerclub.cloud.payment.allinpay.member.constant.VisitSourceType;
import com.tmerclub.cloud.payment.allinpay.member.req.IdCardCollectByFileUpload;
import com.tmerclub.cloud.payment.allinpay.member.resp.QueryBindAcctResp;
import com.tmerclub.cloud.payment.allinpay.member.resp.UserInfo;
import com.tmerclub.cloud.payment.allinpay.order.req.PayByBackSmsReq;
import com.tmerclub.cloud.payment.allinpay.order.req.ResendPaySmsReq;
import com.tmerclub.cloud.payment.allinpay.order.resp.ResendPaySmsResp;
import com.tmerclub.cloud.payment.allinpay.service.AllinpayOrderService;
import com.tmerclub.cloud.payment.bo.PayInfoBO;
import com.tmerclub.cloud.payment.config.AllinpayConfig;
import com.tmerclub.cloud.payment.constant.DistributedIdKey;
import com.tmerclub.cloud.payment.constant.PayEntry;
import com.tmerclub.cloud.payment.constant.PayStatus;
import com.tmerclub.cloud.payment.dto.ApplyBindAcctDTO;
import com.tmerclub.cloud.payment.dto.IdCardCollectDTO;
import com.tmerclub.cloud.payment.dto.LockMemberDTO;
import com.tmerclub.cloud.payment.manager.AllinpayManager;
import com.tmerclub.cloud.payment.mapper.PayInfoMapper;
import com.tmerclub.cloud.payment.model.PayInfo;
import com.tmerclub.cloud.payment.service.AllinpayCompanyService;
import com.tmerclub.cloud.payment.service.AllinpayService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author TRACK
 */
@DubboService
public class AllinpayFeignController implements AllinpayFeignClient {

    private static final Logger log = LoggerFactory.getLogger(AllinpayFeignController.class);
    @Autowired
    private AllinpayCompanyService allinpayCompanyService;
    @Autowired
    private AllinpayService allinpayService;
    @Autowired
    private AllinpayOrderService allinpayOrderService;
    @Autowired
    private SegmentManager segmentManager;
    @Autowired
    private AllinpayManager allinpayManager;
    @Autowired
    private PayInfoMapper payInfoMapper;
    @Autowired
    private AllinpayConfig allinpayConfig;
    @DubboReference
    private UserExtensionFeignClient userExtensionFeignClient;

    private static final Integer KEY_LENGTH = 15;

    @Value("${application.domainUrl}")
    private String domainUrl;

    @Override
    public ServerResponseEntity<Void> batchCreateMember(List<String> bizUserIds) {
        for (String bizUserId : bizUserIds) {
            allinpayCompanyService.createCompanyMember(bizUserId);
        }
        return ServerResponseEntity.success();
    }

    @Override
    public ServerResponseEntity<Integer> batchCreatePersonalMember(List<String> bizUserIds) {
        if (CollectionUtils.isEmpty(bizUserIds)) {
            return ServerResponseEntity.success();
        }
        List<Long> createdUserIds = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (String bizUserId : bizUserIds) {
            try {
                allinpayService.createMember(bizUserId, SysTypeEnum.ORDINARY.value());
                createdUserIds.add(Long.valueOf(bizUserId));
            } catch (Exception e) {
                if (e.getMessage().contains("已经存在此用户")) {
                    createdUserIds.add(Long.valueOf(bizUserId));
                }
                log.error("用户{}, 创建通联个人会员失败: {}", bizUserId, e.getMessage());
            }
        }
        // 更新用户拓展信息
        UserExtensionDTO userExtensionDTO = new UserExtensionDTO();
        userExtensionDTO.setAllinpayCreate(1);
        userExtensionFeignClient.updateBatchStatus(userExtensionDTO, createdUserIds);
        return ServerResponseEntity.success(createdUserIds.size());
    }

    @Override
    public ServerResponseEntity<CompanyInfo> getCompanyInfo(String bizUserId) {
        CompanyInfo companyInfo = allinpayCompanyService.getCompanyInfo(bizUserId);
        return ServerResponseEntity.success(companyInfo);
    }

    @Override
    public ServerResponseEntity<PersonalMemberInfo> getPersonalMemberInfo(String bizUserId) {
        UserInfo userInfo = allinpayService.getUserInfo(bizUserId);
        PersonalMemberInfo personalMemberInfo = new PersonalMemberInfo();
        BeanUtils.copyProperties(userInfo, personalMemberInfo);
        return ServerResponseEntity.success(personalMemberInfo);
    }

    @Override
    public ServerResponseEntity<SetCompanyInfoResp> setCompanyInfo(SetCompanyInfoDTO setCompanyInfoDTO) {
        String backUrl = domainUrl + AllinpayNoticeUrl.SET_COMPANY_INFO;
        SetCompanyInfoResp setCompanyInfoResp = allinpayCompanyService.setCompanyInfo(setCompanyInfoDTO.getBizUserId(), backUrl, setCompanyInfoDTO);
        if (Objects.equals(setCompanyInfoResp.getResult(), AuditStatus.FAIL.getCode())) {
            throw new LuckException(setCompanyInfoResp.getFailReason());
        }
        allinpayCompanyService.deleteCache(setCompanyInfoDTO.getBizUserId());
        return ServerResponseEntity.success(setCompanyInfoResp);
    }

    @Override
    public ServerResponseEntity<UpdateCompanyInfoResp> updateCompanyInfo(UpdateCompanyInfoDTO updateCompanyInfoDTO) {
        String bizUserId = updateCompanyInfoDTO.getBizUserId();
        // 会员要通过审核
        CompanyInfo companyInfo = allinpayCompanyService.getCompanyInfo(bizUserId);
        if (Objects.isNull(companyInfo) || !Objects.equals(companyInfo.getStatus(), AuditStatus.SUCCESS.getCode())) {
            throw new LuckException("企业会员尚未通过审核，无法修改信息");
        }
        String backUrl = domainUrl + AllinpayNoticeUrl.UPDATE_COMPANY_INFO;
        UpdateCompanyInfoResp updateCompanyInfoResp = allinpayCompanyService.updateCompanyInfo(bizUserId, backUrl, updateCompanyInfoDTO);
        allinpayCompanyService.deleteCache(bizUserId);
        return ServerResponseEntity.success(updateCompanyInfoResp);
    }

    @Override
    public ServerResponseEntity<IdCardCollectResp> idCardCollect(String imageUrl, Integer picType, String fileType, String bizUserId) {
        String picture = ImageUtil.encodeImageToBase64(imageUrl, fileType);
        IdCardCollectDTO idCardCollectDTO = new IdCardCollectDTO();
        idCardCollectDTO.setPicture(picture);
        idCardCollectDTO.setPicType(picType);
        idCardCollectDTO.setBizUserId(bizUserId);
        String backUrl = domainUrl + AllinpayNoticeUrl.ID_CARD_COLLECT;
        IdCardCollectResp idCardCollectResp = allinpayCompanyService.idCardCollect(idCardCollectDTO, backUrl);
        return ServerResponseEntity.success(idCardCollectResp);
    }

    @Override
    public ServerResponseEntity<IdCardCollectByFileUploadResp> idCardCollectByFileUpload(String legalPicFaceToken, String legalPicEmblemToken, Integer picType, String token, String bizUserId) {
        IdCardCollectByFileUpload idCardCollectByFileUpload = new IdCardCollectByFileUpload();
        idCardCollectByFileUpload.setBizUserId(bizUserId);
        Long reqSerialNo = segmentManager.getDateFormatSegmentId(DistributedIdKey.tmerclub_FILE_UPLOAD, IdCardCollectByFileUpload.REQ_SERIAL_NO_LENGTH);
        idCardCollectByFileUpload.setReqSerialNo(String.valueOf(reqSerialNo));
        idCardCollectByFileUpload.setOcrComparisonResultBackUrl(domainUrl + AllinpayNoticeUrl.ID_CARD_COLLECT);
        if (StrUtil.isNotBlank(legalPicFaceToken)) {
            legalPicFaceToken = allinpayConfig.uploadFile(legalPicFaceToken);
            idCardCollectByFileUpload.setLegalPicFaceToken(legalPicFaceToken);
        }
        if (StrUtil.isNotBlank(legalPicEmblemToken)) {
            if (StrUtil.isNotBlank(legalPicFaceToken)) {
                // 避免请求过于频繁
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    log.error("InterruptedException", e);
                }
            }
            legalPicEmblemToken = allinpayConfig.uploadFile(legalPicEmblemToken);
            idCardCollectByFileUpload.setLegalPicEmblemToken(legalPicEmblemToken);
        }
        if (Objects.equals(picType, PicType.BUSINESS_LICENSE.getCode()) && StrUtil.isNotBlank(token)) {
            idCardCollectByFileUpload.setPicType(picType);
            token = allinpayConfig.uploadFile(token);
            idCardCollectByFileUpload.setToken(token);
        }
        IdCardCollectByFileUploadResp upload = allinpayCompanyService.idcardCollectByFileUpload(idCardCollectByFileUpload);
        return ServerResponseEntity.success(upload);
    }

    @Override
    public ServerResponseEntity<List<BindCard>> listBindCard(String bizUserId, String cardNo) {
        List<BindCard> bindCards = allinpayCompanyService.queryBankCard(bizUserId, cardNo);
        CompanyInfo companyInfo = allinpayCompanyService.getCompanyInfo(bizUserId);
        bindCards.forEach(card -> card.setAccountNo(companyInfo.getAccountNo()));
        return ServerResponseEntity.success(bindCards);
    }

    @Override
    public ServerResponseEntity<QueryBalanceResp> queryBalance(String bizUserId, Integer sysType) {
        QueryBalanceResp queryBalanceResp = allinpayService.queryBalance(bizUserId, sysType);
        return ServerResponseEntity.success(queryBalanceResp);
    }

    @Override
    public ServerResponseEntity<Void> resendPaySms(String bizOrderNo) {
        ResendPaySmsResp resendPaySmsResp = allinpayOrderService.resendPaySms(new ResendPaySmsReq(bizOrderNo));
        log.info("订单号{}重发短信验证码至手机{}成功", resendPaySmsResp.getBizOrderNo(), resendPaySmsResp.getPhone());
        return ServerResponseEntity.success();
    }

    @Override
    public ServerResponseEntity<WithdrawApplyResp> withdrawApply(String bizUserId, Long amount,
                                                                 String bankCardNo, Integer sysType) {
        Integer source = Objects.equals(sysType, SysTypeEnum.ORDINARY.value()) ? VisitSourceType.MOBILE.value() : VisitSourceType.PC.value();
        List<BindCard> bindCards = allinpayCompanyService.queryBankCard(bizUserId, bankCardNo);
        if (CollUtil.isEmpty(bindCards)) {
            throw new LuckException("银行卡不存在");
        }
        BindCard bindCard = bindCards.get(0);
        if (!Objects.equals(bindCard.getBindState(), 1)) {
            throw new LuckException("银行卡未绑定");
        }
        Long payId = segmentManager.getSegmentIdWithDateTime(DistributedIdKey.tmerclub_WITHDRAW_CASH, 0L);
        String backUrl = domainUrl + AllinpayNoticeUrl.WITHDRAW_APPLY;

        // validateType:交易验证方式 0无验证 1短信验证码 2支付密码
        Long validateType = 1L;
        WithdrawApplyResp withdrawApplyResp = allinpayManager.withdrawApply(payId, bizUserId, amount, backUrl, bindCard, source, validateType);
        return ServerResponseEntity.success(withdrawApplyResp);
    }

    @Override
    public ServerResponseEntity<PayByBackSmsResp> payByBackSms(String bizUserId, String bizOrderNo, String verificationCode) {
        PayByBackSmsResp payByBackSmsResp = allinpayManager.payByBackSms(new PayByBackSmsReq(bizUserId, bizOrderNo, verificationCode));
        return ServerResponseEntity.success(payByBackSmsResp);
    }

    @Override
    public ServerResponseEntity<?> rechargeApply(Long amount, Long shopId, Long walletLogId, String returnUrl) {

        Long payId = segmentManager.getSegmentIdWithDateTime(DistributedIdKey.tmerclub_PAY, shopId);
        // 保存预支付信息
        String bizUserId = AllinpayConstant.SHOP + shopId;
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payId);
        payInfo.setRefundId(0L);
        payInfo.setPayScore(0L);
        payInfo.setUserId(shopId);
        payInfo.setPayAmount(amount);
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setSysType(SysTypeEnum.MULTISHOP.value());
        payInfo.setPayType(PayType.WECHATPAY_SWEEP_CODE.value());
        payInfo.setVersion(0);
        payInfo.setOrderIds(walletLogId.toString());
        payInfo.setPayEntry(PayEntry.RECHARGE.value());
        payInfoMapper.save(payInfo);

        // 进行支付
        PayInfoBO payInfoBO = new PayInfoBO();
        payInfoBO.setSystemType(VisitSourceType.PC.value());
        payInfoBO.setValidateType(1L);
        payInfoBO.setUserId(bizUserId);
        payInfoBO.setBizUserId(bizUserId);
        payInfoBO.setAllinpayUserId(bizUserId);
        payInfoBO.setOrderIds(String.valueOf(payId));
        payInfoBO.setIsRecharge(true);
        String backUrl = domainUrl + AllinpayNoticeUrl.RECHARGE_APPLY;
        payInfoBO.setReturnUrl(returnUrl);
        payInfoBO.setPayAmount(amount);
        payInfoBO.setApiNoticeUrl(backUrl);
        payInfoBO.setPayId(payId);
        payInfoBO.setPayType(PayType.WECHATPAY_SWEEP_CODE.value());
        return allinpayManager.doAllinPay(payInfoBO);
    }

    @Override
    public ServerResponseEntity<Integer> getIdCardStatus(String bizUserId) {
        CompanyInfo companyInfo = allinpayCompanyService.getCompanyInfo(bizUserId);
        Integer status = allinpayCompanyService.getIdCardStatus(companyInfo.getOcrRegnumComparisonResult(), companyInfo.getOcrIdcardComparisonResult());
        return ServerResponseEntity.success(status);
    }

    @Override
    public void updateAllinpayMemberStatus(Long userId, Integer status) {
        LockMemberDTO lockMemberDTO = new LockMemberDTO(userId);
        if (status == 0) {
            allinpayService.lockMember(lockMemberDTO);
        } else {
            allinpayService.unlockMember(lockMemberDTO);
        }
    }

    @Override
    public void bindPayAcct(Long userId, String payAcct, Integer socialType) {
        String bizUserId = userId.toString();
        ApplyBindAcctDTO applyBindAcctDTO = new ApplyBindAcctDTO();
        applyBindAcctDTO.setAcct(payAcct);
        if (Objects.equals(socialType, SocialType.MA.value())) {
            // 微信小程序
            applyBindAcctDTO.setAcctType(PayAcctType.WECHAT_MINI_PROGRAM.value());
        } else if (Objects.equals(socialType, SocialType.MP.value())) {
            // 微信公众号
            applyBindAcctDTO.setAcctType(PayAcctType.WECHAT_PUBLIC.value());
        }
        allinpayService.applyBindAcct(bizUserId, applyBindAcctDTO);
    }

    @Override
    public void batchBindPayAcct(List<BindPayAcctDTO> bindPayAcctDTOList) {
        if (CollectionUtils.isEmpty(bindPayAcctDTOList)) {
            return;
        }
        for (BindPayAcctDTO bindPayAcctDTO : bindPayAcctDTOList) {
            try {
                ApplyBindAcctDTO applyBindAcctDTO = new ApplyBindAcctDTO();
                applyBindAcctDTO.setAcct(bindPayAcctDTO.getAcct());
                if (Objects.equals(bindPayAcctDTO.getSocialType(), SocialType.MA.value())) {
                    // 微信小程序
                    applyBindAcctDTO.setAcctType(PayAcctType.WECHAT_MINI_PROGRAM.value());
                } else if (Objects.equals(bindPayAcctDTO.getSocialType(), SocialType.MP.value())) {
                    // 微信公众号
                    applyBindAcctDTO.setAcctType(PayAcctType.WECHAT_PUBLIC.value());
                }
                allinpayService.applyBindAcct(bindPayAcctDTO.getBizUserId(), applyBindAcctDTO);
                // 更新用户拓展信息为已绑定
                UserExtensionDTO userExtensionDTO = new UserExtensionDTO();
                userExtensionDTO.setUserId(Long.valueOf(bindPayAcctDTO.getBizUserId()));
                userExtensionDTO.setAllinpayPayAcctBind(1);
                userExtensionFeignClient.updateExtension(userExtensionDTO);
            } catch (Exception e) {
                log.error("用户[{}]通联支付用户标识[{}]绑定失败，原因为{}", bindPayAcctDTO.getBizUserId(), bindPayAcctDTO.getAcct(), e.getMessage());
            }
        }
    }

    @Override
    public ServerResponseEntity<Boolean> isBindPayAcct(Long userId) {
        QueryBindAcctResp queryBindAcctResp = allinpayService.queryBindAcct(userId.toString());
        if (queryBindAcctResp == null || CollectionUtils.isEmpty(queryBindAcctResp.getAcctInfoList())) {
            return ServerResponseEntity.success(false);
        }
        return ServerResponseEntity.success(true);
    }

    @Override
    public ServerResponseEntity<AllinpayBalanceDTO> getAllinpayBalance(Long userId, Integer sysType) {
        String bizUserId = userId.toString();
        QueryBalanceResp queryBalanceResp = allinpayService.queryBalance(bizUserId, sysType);
        AllinpayBalanceDTO allinpayBalanceDTO = new AllinpayBalanceDTO();
        BeanUtils.copyProperties(queryBalanceResp, allinpayBalanceDTO);
        return ServerResponseEntity.success(allinpayBalanceDTO);
    }
}
