package com.seer.teach.pay.app.client.coin;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.TradeTypeEnum;
import com.seer.teach.common.enums.pay.PayChannelEnum;
import com.seer.teach.common.enums.pay.PayStatusEnum;
import com.seer.teach.common.enums.pay.RefundStatusEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.pay.app.client.AbstractPayClient;
import com.seer.teach.pay.app.client.dto.PayOrderCallBackRespDTO;
import com.seer.teach.pay.app.client.dto.PayOrderReqDTO;
import com.seer.teach.pay.app.client.dto.PayOrderRespDTO;
import com.seer.teach.pay.app.client.dto.PayRefundReqDTO;
import com.seer.teach.pay.app.client.dto.RefundNotificationRespDTO;
import com.seer.teach.pay.dto.RefundSubmitRespDTO;
import com.seer.teach.pay.entity.PayCoinAccountEntity;
import com.seer.teach.pay.entity.PayCoinAccountTradeLogEntity;
import com.seer.teach.pay.entity.PayOrderEntity;
import com.seer.teach.pay.entity.PayOrderExtensionEntity;
import com.seer.teach.pay.service.IPayCoinAccountService;
import com.seer.teach.pay.service.IPayCoinAccountTradeLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;

/**
 * 学豆支付策略实现
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CoinPayClient extends AbstractPayClient {

    private final IPayCoinAccountService payConAccountService;

    private final IPayCoinAccountTradeLogService userCoinAccountTradeLogService;

    /**
     * 获取支付渠道的编码
     *
     * @return 支付渠道编码
     */
    @Override
    public PayChannelEnum getChannel() {
        return PayChannelEnum.COIN;
    }

    @Override
    public boolean isAsyncCallback() {
        return false;
    }

    @Override
    protected RefundSubmitRespDTO doRefundOrder(PayRefundReqDTO payRefundReqDTO) {
        Integer userId = payRefundReqDTO.getUserId();
        Long refundAmount = payRefundReqDTO.getRefundPrice();
        BigDecimal refundPrice = BigDecimal.valueOf(refundAmount);
        PayCoinAccountEntity beforeAccount = payConAccountService.getByUserId(userId);

        // 增加用户学豆余额
        boolean addBalanceResult = payConAccountService.addBalance(userId, beforeAccount.getId(), refundPrice);
        log.info("确认退款的增加余额结果：{}", addBalanceResult);

        RefundStatusEnum statusEnum = RefundStatusEnum.REFUND_SUCCESS;
        if(addBalanceResult){
            // 添加用户账户流水
            PayCoinAccountEntity afterAccount = payConAccountService.getByUserId(userId);
            PayCoinAccountTradeLogEntity tradeLog = new PayCoinAccountTradeLogEntity();
            tradeLog.setTradeAmount(refundPrice);
            tradeLog.setTradeName(TradeTypeEnum.REFUND.getDesc());
            tradeLog.setTradeType(TradeTypeEnum.REFUND.getCode());
            tradeLog.setAfterBalance(afterAccount.getAvailableBalance());
            tradeLog.setTradeTime(LocalDateTime.now());
            tradeLog.setBeforeBalance(beforeAccount.getAvailableBalance());
            tradeLog.setUserId(beforeAccount.getUserId());
            tradeLog.setRelatedId(payRefundReqDTO.getRefundOrderId().intValue());
            userCoinAccountTradeLogService.saveLog(tradeLog);
        }else{
            statusEnum = RefundStatusEnum.WECHAT_REFUND_FAILED;
        }
        RefundSubmitRespDTO refundSubmitRespDTO = new RefundSubmitRespDTO();
        refundSubmitRespDTO.setStatus(statusEnum.getCode());
        refundSubmitRespDTO.setSuccessTime(LocalDateTime.now());
        refundSubmitRespDTO.setRefundOrderSn(payRefundReqDTO.getOutRefundNo());
        refundSubmitRespDTO.setPayOrderSn(payRefundReqDTO.getOutTradeNo());
        refundSubmitRespDTO.setCurrency("COIN");
        return refundSubmitRespDTO;
    }

    @Override
    public Optional<RefundNotificationRespDTO> parseRefundNotify(Map<String, String> headers, Map<String, String> params, String body) {
        return Optional.empty();
    }


    @Override
    public RefundSubmitRespDTO doQueryRefundStatus(String refundSn) {
        return null;
    }


    @Override
    public void init(String configJson) {
    }

    @Override
    public PayOrderCallBackRespDTO parseOrderNotify(Map<String, String> headers, Map<String, String> params, String body) {
        return null;
    }

    @Override
    protected Object getPrepayRequestParam(PayOrderReqDTO payOrderReqDTO) {
        return null;
    }


    @Override
    protected PayOrderRespDTO doPayOrder(PayOrderReqDTO payOrder, Object extrasRequest) {
        try {
            log.info("开始创建学豆支付订单，订单号：{}，用户ID：{}，支付学豆：{},",
                    payOrder.getPayOrderSn(), payOrder.getUserId(), payOrder.getTotalCoin());

            Integer userId = payOrder.getUserId();
            BigDecimal totalCoin = payOrder.getTotalCoin();

            // 获取用户学豆账户
            PayCoinAccountEntity coinAccount = payConAccountService.getByUserId(userId);
            AssertUtils.notNull(coinAccount, ResultCodeEnum.USER_NOT_FOUND);

            // 检查账户是否被冻结
            if (coinAccount.getIsBlock() != null && !coinAccount.isEnabled()) {
                throw new CommonException(ResultCodeEnum.USER_COIN_LOCK_ERROR);
            }

            // 检查学豆余额是否充足
            BigDecimal availableBalance = coinAccount.getAvailableBalance();
            if (availableBalance == null || availableBalance.compareTo(totalCoin) < 0) {
                log.warn("学豆余额不足，用户ID：{}，可用余额：{}，需要支付：{}", userId, availableBalance, totalCoin);
                throw new CommonException(ResultCodeEnum.USER_NOT_ENOUGH_COIN,
                        String.format("学豆余额不足，可用学豆余额：%s，需要支付学豆：%s", availableBalance, totalCoin));
            }

            // 扣减学豆余额
            boolean deductResult = payConAccountService.deductBalance(userId, coinAccount.getId(), totalCoin);
            if (!deductResult) {
                log.error("扣减学豆余额失败，用户ID：{}，账户ID：{}，扣减学豆：{}",
                        userId, coinAccount.getId(), totalCoin);
                throw new CommonException(ResultCodeEnum.USER_COIN_PAY_ERROR, "学豆扣减失败");
            }else {
                // 添加用户账户流水
                PayCoinAccountEntity afterAccount = payConAccountService.getByUserId(userId);
                PayCoinAccountTradeLogEntity tradeLog = new PayCoinAccountTradeLogEntity();
                tradeLog.setTradeAmount(totalCoin);
                tradeLog.setTradeName(TradeTypeEnum.PAY.getDesc());
                tradeLog.setTradeType(TradeTypeEnum.PAY.getCode());
                tradeLog.setAfterBalance(afterAccount.getAvailableBalance());
                tradeLog.setTradeTime(LocalDateTime.now());
                tradeLog.setBeforeBalance(coinAccount.getAvailableBalance());
                tradeLog.setUserId(userId);
                tradeLog.setRelatedId(payOrder.getParOrderId());
                userCoinAccountTradeLogService.saveLog(tradeLog);
            }
            // 构造返回结果
            PayOrderRespDTO response = new PayOrderRespDTO();
            response.setChannelCode(payOrder.getChannelCode());
            response.setStatus(PayStatusEnum.SUCCESS.getCode());
            response.setPayOrderSn(payOrder.getPayOrderSn());
            response.setPaySuccessTime(LocalDateTime.now());
            log.info("学豆支付订单完成，订单号：{}，支付学豆：{}", payOrder.getPayOrderSn(), payOrder.getTotalCoin());
            return response;

        } catch (Exception e) {
            log.error("创建学豆支付订单失败，订单号：{}，支付学豆：{}", payOrder.getPayOrderSn(), payOrder.getTotalCoin(), e);
            throw new CommonException(ResultCodeEnum.USER_COIN_PAY_ERROR, e.getMessage());
        }
    }

    /**
     * 查询学豆支付状态
     *
     * @param orderSn 订单号
     * @return 支付订单
     */
    @Override
    protected PayOrderEntity doQueryPayStatus(String orderSn) {
        log.info("查询学豆支付状态，订单号：{}", orderSn);
        PayOrderEntity payOrder = payOrderService.getOne(
                new LambdaQueryWrapper<PayOrderEntity>()
                        .eq(PayOrderEntity::getOrderSn, orderSn)
                        .eq(PayOrderEntity::getChannelCode, getChannel()));
        AssertUtils.notNull(payOrder, ResultCodeEnum.ORDER_NOT_FOUND);
        return payOrder;
    }

    /**
     * 关闭学豆支付订单
     *
     * @param orderSn 订单号
     * @return 关闭结果
     */
    @Override
    protected boolean doClosePayOrder(String orderSn) {
        try {
            log.info("关闭学豆支付订单，订单号：{}", orderSn);
            // 查询订单
            PayOrderEntity payOrder = payOrderService.getOne(
                    new LambdaQueryWrapper<PayOrderEntity>()
                            .eq(PayOrderEntity::getOrderSn, orderSn)
                            .eq(PayOrderEntity::getChannelCode, getChannel()));
            AssertUtils.notNull(payOrder, ResultCodeEnum.ORDER_NOT_FOUND);

            // 学豆支付订单是待支付状态才能关闭
            if (PayStatusEnum.PENDING.getCode() != payOrder.getStatus()) {
                log.warn("学豆支付订单状态不允许关闭，订单号：{}，当前状态：{}", orderSn, payOrder.getStatus());
                return false;
            }
            // 更新订单状态为已取消
            boolean updateResult = payOrderService.update(
                    new LambdaUpdateWrapper<PayOrderEntity>()
                            .set(PayOrderEntity::getStatus, PayStatusEnum.CANCEL.getCode())
                            .eq(PayOrderEntity::getId, payOrder.getId()));
            // 更新扩展表
            if (updateResult) {
                payOrderExtensionService.update(
                        new LambdaUpdateWrapper<PayOrderExtensionEntity>()
                                .eq(PayOrderExtensionEntity::getOrderId, payOrder.getId()));
            }
            log.info("关闭学豆支付订单结果：{}，订单号：{}", updateResult, orderSn);
            return updateResult;
        } catch (Exception e) {
            log.error("关闭学豆支付订单失败，订单号：{}", orderSn, e);
            return false;
        }
    }
}