package com.izouma.nineth.service;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.izouma.nineth.config.PayeasenetProperties;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.DivMoneyRepo;
import com.izouma.nineth.repo.OrderRepo;
import com.izouma.nineth.repo.TransferMoneyInfoRepo;
import com.izouma.nineth.repo.UserBankCardRepo;
import com.izouma.nineth.service.pay.PayHelper;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import com.izouma.nineth.utils.payeasenet.PayeasenetClient;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Service
@AllArgsConstructor
@Slf4j
public class PayeasenetService {

    private PayeasenetProperties payeasenetProperties;

    private OrderRepo orderRepo;

    private PayHelper payHelper;

    private PayeasenetClient payeasenetClient;

    private SnowflakeIdWorker snowflakeIdWorker;

    private DivMoneyRepo divMoneyRepo;

    private TransferMoneyInfoRepo transferMoneyInfoRepo;

    private UserBankCardRepo userBankCardRepo;

    /**
     * 解析请求内容
     * @param requestBody
     * @return
     * @throws Exception
     */
    public JSONObject checkSuccessBody(String requestBody, String encryptKey) throws Exception{
        JSONObject wrappedData = JSONObject.parseObject(requestBody);
        return payeasenetClient.checkSuccessBody(wrappedData, encryptKey);
    }


    /**
     * 统一支付
     * @param paymentInfo
     * @return
     * @throws Exception
     */
    public JSONObject unifyPay(PaymentInfo paymentInfo, String clientIp) throws Exception{

        int orderAmount = paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue();
        JSONObject bodyJson = new JSONObject();

        bodyJson.put("merchantId", payeasenetProperties.getMerchantId() );
        bodyJson.put("orderAmount", orderAmount);//订单金额（分）
        bodyJson.put("orderCurrency", "CNY");//订单币种
        bodyJson.put("requestId", paymentInfo.getOrderNo());//订单号
        bodyJson.put("partnerId", payeasenetProperties.getPartnerId());
        bodyJson.put("notifyUrl", paymentInfo.getNotifyUrl());

        String returnUrl = payHelper.resolveReturnUrl(paymentInfo);
        bodyJson.put("callbackUrl", returnUrl);
        bodyJson.put("remark", paymentInfo.getGoodsTitle());

        String paymentModeCode = "ALIPAY-WAP-P2P";//支付宝H5支付
        if(paymentInfo.getPayMethod() == PayMethod.ALIPAY){
            paymentModeCode = "ALIPAY-WAP-P2P";
        }else if(paymentInfo.getPayMethod() == PayMethod.WEIXIN){
            paymentModeCode = "APP-WEIXIN-P2P";
        }else if(paymentInfo.getPayMethod() == PayMethod.BANK){
            paymentModeCode = "BANK_CARD-QUICKPASS_UNIONPAY-P2P";
        }

        //非收银台模式需要传入此项，不传可提供多种选择
        bodyJson.put("paymentModeCode", paymentModeCode);
//        bodyJson.put("authCode", "");
//        bodyJson.put("appId", "");
//        bodyJson.put("openId", "");

        JSONArray productDetails = new JSONArray();
        JSONObject product = new JSONObject();
        product.put("name", paymentInfo.getGoodsTitle());
        product.put("quantity", 1);
        int amount = paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue();
        product.put("amount", amount);
        //product.put("receiver", "");
        product.put("description", paymentInfo.getGoodsTitle());
        productDetails.add(product);

        bodyJson.put("productDetails", productDetails);

        //分账标识，DO_SPLIT 分账 ， NOT_DO_SPLIT 不分账
        //bodyJson.put("splitMark", "DO_SPLIT");
        JSONObject payer = new JSONObject();
        bodyJson.put("payer", payer);

        bodyJson.put("clientIp", clientIp);

        //失效间隔，分钟
        int expireInterval = payHelper.getExpireInterval();
        bodyJson.put("timeout", expireInterval);

        bodyJson.put("merchantUserId", paymentInfo.getUserId());
        //bodyJson.put("bindCardId", "");
        //bodyJson.put("reportSerialNo", "");
        //bodyJson.put("limitAccType", "");
        //bodyJson.put("subsidyMark", "");
        //bodyJson.put("subsidyAmount", "");
        //bodyJson.put("needOpenLink", "");

        JSONObject res = payeasenetClient.postForm("/onlinePay/order", bodyJson );
        return res;
    }


    /**
     * 退款操作
     * @param paymentInfo
     * @param refundReason
     * @return
     */
    public JSONObject refund(PaymentInfo paymentInfo, String refundReason) throws Exception{
        String requestId = String.valueOf(snowflakeIdWorker.nextId());
        int refundAmount = paymentInfo.getPayAmt().multiply(new BigDecimal(100)).intValue();
        String notifyUrl = payHelper.resolveRefundNotifyUrl(paymentInfo.getOrderNo());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("merchantId", payeasenetProperties.getMerchantId());
        bodyJson.put("requestId", requestId);
        bodyJson.put("orderId", paymentInfo.getTransactionId());
        bodyJson.put("amount", refundAmount);

        bodyJson.put("notifyUrl", notifyUrl);
        //bodyJson.put("isCollect", "");
        //bodyJson.put("refundCollectDetail", "");
        bodyJson.put("remark", refundReason);
        //1 退款补贴
        //0 不退款补贴
        //默认为不退款补贴
        //bodyJson.put("refundSubsidy", "0");
        //bodyJson.put("subsidyMoney", "0");

        JSONObject res = payeasenetClient.postForm("/onlinePay/refund", bodyJson );
        return res;
    }



    /**
     * 提交转账
     * @param tradeNo
     * @param userBankCard
     * @param amount
     * @return
     */
    public JSONObject submitTransfer(String tradeNo, UserBankCard userBankCard, BigDecimal amount, String transferReason) throws Exception{
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("merchantId", payeasenetProperties.getMerchantId());
        int transferAmount = amount.multiply(new BigDecimal(100)).intValue();

        bodyJson.put("requestId", tradeNo);
        bodyJson.put("amount", transferAmount);
        bodyJson.put("currency", "CNY");

        String notifyUrl = payHelper.resolveTransferNotifyUrl(tradeNo);

        bodyJson.put("notifyUrl", notifyUrl);
        bodyJson.put("remark", transferReason);

        //收款人信息
        JSONObject payee = new JSONObject();
        payee.put("name", userBankCard.getRealName());//收款方姓名
        payee.put("bankCardNum", userBankCard.getBankNo());
        payee.put("bankName", userBankCard.getBankName());
        payee.put("branchBankName", "");//支行名称

        bodyJson.put("payee", payee);

        JSONObject res = payeasenetClient.postForm("/transferDomestic/single/order", bodyJson);

        return res;
    }

    /**
     * 转账交易结果查询
     * @return
     */
    public JSONObject queryTransfer(String tradeNo) throws Exception{
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("merchantId", payeasenetProperties.getMerchantId());
        bodyJson.put("requestId", tradeNo);

        JSONObject res = payeasenetClient.postForm("/transferDomestic/single/query", bodyJson);
        return res;
    }


    /**
     * 余额查询
     * @return
     */
    public JSONObject queryBalance() throws Exception{
        String requestId = String.valueOf(snowflakeIdWorker.nextId());
        JSONObject bodyJson = new JSONObject();
        bodyJson.put("merchantId", payeasenetProperties.getMerchantId());
        bodyJson.put("requestId", requestId);
        JSONObject res = payeasenetClient.postForm("/transferDomestic/account/availableTransferBalance", bodyJson );
        return res;
    }



    /**
     * 转账给分账用户
     * @param divMoneyId
     * @return
     */
    @Transactional
    public TransferMoneyInfo transferDivMoney(Long divMoneyId, String reason){
        DivMoney divMoney = divMoneyRepo.findById(divMoneyId).orElseThrow(new BusinessException("分账记录不存在"));
        if(divMoney.getUserId() == null){
            throw new BusinessException("分账的用户ID不存在");
        }

        Order order = orderRepo.findById(divMoney.getOrderId()).orElseThrow(new BusinessException("分账订单未找到"));
        if(order.getStatus() != OrderStatus.FINISH){
            throw new BusinessException("订单状态不正确");
        }

        if(divMoney.getAmount().compareTo(order.getPrice()) > 0){
            throw new BusinessException("分账金额不正确");
        }

        UserBankCard userBankCard = userBankCardRepo.findByUserId(divMoney.getUserId()).stream()
                .findAny().orElseThrow(new BusinessException("未绑定银行卡，无法分账"));


        //无论成功与否，直接标记已处理
        divMoney.setStatus(DivStatus.PROCESSED);
        divMoney.setProcessTime(LocalDateTime.now());


        if(divMoney.getTransferMoneyId() != null){
            //历史记录
            TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.findById(divMoney.getTransferMoneyId()).orElseThrow(new BusinessException("历史转账记录不存在"));
            //是否卡号不重复
            if(transferMoneyInfo.getAccountNo().equals(userBankCard.getBankNo())){
                throw new BusinessException("不允许对重复的卡号重新转账");
            }
        }

        //保存新的转账记录
        String tradeNo = String.valueOf(snowflakeIdWorker.nextId());
        TransferMoneyInfo.TransferMoneyInfoBuilder builder = TransferMoneyInfo.builder();
        builder.tradeNo(tradeNo).toUserId(divMoney.getUserId()).transferMethod(TransferMethod.THIRD_ACCOUNT)
                .accountType(AccountType.BANK_CARD.name())
                .accountNo(userBankCard.getBankNo())
                .accountName(userBankCard.getRealName())
                .thirdAccountId(userBankCard.getThirdAccountId())
                .amount(divMoney.getAmount())
                .payPlatform(divMoney.getPayPlatform())
                .reason(reason)
                .divMoneyId(divMoneyId);
        TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.save(builder.build());


        //记录转账记录ID
        divMoney.setTransferMoneyId(transferMoneyInfo.getId());

        try {
            JSONObject res = submitTransfer(transferMoneyInfo.getTradeNo(), userBankCard, transferMoneyInfo.getAmount(), reason);
            String requestId = res.getString("requestId");

            //统一处理中，是否成功通知和查询决定
            String resultStr = "处理中";
            transferMoneyInfo.setStatus(TransferStatus.PROCESSING);

            transferMoneyInfo.setTransferOrderId(requestId);
            transferMoneyInfo.setTransactionId(null);
            transferMoneyInfo.setTransferDate(null);
            transferMoneyInfo.setResult(resultStr);

            divMoney.setTransferResult(resultStr);

        }catch(Exception e){
            log.error("转账失败，分账ID:" + divMoneyId, e);
            transferMoneyInfo.setStatus(TransferStatus.FAILED);
            transferMoneyInfo.setResult(e.getMessage());
            divMoney.setStatus(DivStatus.ERROR);
            divMoney.setTransferResult(e.getMessage());
        }

        transferMoneyInfoRepo.save(transferMoneyInfo);
        divMoneyRepo.save(divMoney);

        return transferMoneyInfo;
    }



    /**
     * 检查转账结果
     * @param transferMoneyId
     */
    @Transactional(rollbackOn = Exception.class)
    public TransferMoneyInfo checkTransferResult(Long transferMoneyId) throws Exception{

        TransferMoneyInfo transferMoneyInfo = transferMoneyInfoRepo.findById(transferMoneyId).orElseThrow(new BusinessException("转账记录不存在"));
        JSONObject res = queryTransfer(transferMoneyInfo.getTradeNo());
        String status = res.getString("status");
        String serialNumber = res.getString("serialNumber");
        String completeDateTime = res.getString("completeDateTime");

        String resultStr = "查询结果成功";
        //SUCCESS 代付到账成功
        //FAILED 代付失败，商户可重新发起
        //CANCEL 代付取消，商户可重新发起
        //INIT 代付待处理，等待后再次查询，如果长时间保持此状态请联系首信易
        //REMITING 代付中，等待后再次查询，如果长时间保持此状态请联系首信易
        //ERROR (此状态的返回参数见异常情况说明)
        if("SUCCESS".equals(status)){
            transferMoneyInfo.setStatus(TransferStatus.SUCCESS);
        }else if("FAILED".equals(status) || "CANCEL".equals(status) || "ERROR".equals(status)){
            transferMoneyInfo.setStatus(TransferStatus.FAILED);
            resultStr = "响应状态为失败：" + status;
        }else{
            transferMoneyInfo.setStatus(TransferStatus.PROCESSING);
            resultStr = "处理中:" + status;
        }

        transferMoneyInfo.setTransactionId(serialNumber);
        transferMoneyInfo.setTransferDate(completeDateTime);
        transferMoneyInfo.setResult(resultStr);
        transferMoneyInfoRepo.save(transferMoneyInfo);

        return transferMoneyInfo;


    }




}
