package com.seer.teach.pay.admin.refund.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.pay.PayStatusEnum;
import com.seer.teach.common.enums.pay.RefundStatusEnum;
import com.seer.teach.common.enums.pay.RefundTypeEnum;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.MoneyUtil;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.pay.admin.recharge.service.IAdminCoinRechargeService;
import com.seer.teach.pay.admin.refund.controller.req.AdminRefundQueryReq;
import com.seer.teach.pay.admin.refund.controller.req.AdminRefundReviewReq;
import com.seer.teach.pay.admin.refund.controller.resp.AdminRefundResponse;
import com.seer.teach.pay.admin.refund.controller.resp.WechatRefundResp;
import com.seer.teach.pay.admin.refund.convert.AdminCoinRefundConvert;
import com.seer.teach.pay.admin.refund.service.IAdminCoinRefundService;
import com.seer.teach.pay.api.refund.RefundOrderServiceApi;
import com.seer.teach.pay.api.refund.dto.RefundOrderRequestDTO;
import com.seer.teach.pay.api.refund.dto.RefundResponseDTO;
import com.seer.teach.pay.api.wallet.CoinAccountRefundServiceApi;
import com.seer.teach.pay.entity.CoinRechargeEntity;
import com.seer.teach.pay.entity.CoinRefundEntity;
import com.seer.teach.pay.entity.CoinRefundLogEntity;
import com.seer.teach.pay.mapper.CoinRefundMapper;
import com.seer.teach.pay.service.ICoinRefundLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 后端退款服务实现类
 * </p>
 *
 * @author Wang
 * @since 2025-06-18
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdminCoinRefundServiceImpl extends ServiceImpl<CoinRefundMapper, CoinRefundEntity> implements IAdminCoinRefundService {


    private final CoinAccountRefundServiceApi coinAccountRefundServiceApi;

    private final RefundOrderServiceApi refundOrderServiceApi;

    private final ICoinRefundLogService coinRefundLogService;

    private final IAdminCoinRechargeService adminCoinRechargeService;

    @Override
    public PageListBean<AdminRefundResponse> pageList(AdminRefundQueryReq request) {
        IPage<CoinRefundEntity> pageParams = new Page<>(request.getPageNum(), request.getPageSize());
        IPage<CoinRefundEntity> iPage = super.page(pageParams, new LambdaQueryWrapper<>(CoinRefundEntity.class)
                .eq(Objects.nonNull(request.getStatus()), CoinRefundEntity::getStatus, request.getStatus())
                .eq(Objects.nonNull(request.getRefundSn()), CoinRefundEntity::getRefundSn, request.getRefundSn())
                .orderByDesc(CoinRefundEntity::getId));
        return PageConverterUtils.convertPageListBean(iPage, AdminCoinRefundConvert.INSTANCE::convertList);
    }

    @Transactional(rollbackFor = Exception.class, timeout = 120)
    @Override
    public boolean reviewRefund(AdminRefundReviewReq adminRefundReviewReq) {
        int userId = StpUtil.getLoginIdAsInt();
        CoinRefundEntity coinRefund = super.getOne(new LambdaQueryWrapper<CoinRefundEntity>().eq(CoinRefundEntity::getId, adminRefundReviewReq.getRefundId()));
        AssertUtils.notNull(coinRefund, ResultCodeEnum.COIN_RECHARGE_NOT_FOUND);
        log.info("获取退款申请:{}", coinRefund);

        CoinRechargeEntity coinRecharge = adminCoinRechargeService.getById(coinRefund.getRechargeId());
        // 判断订单是否存在
        AssertUtils.notNull(coinRecharge, ResultCodeEnum.COIN_RECHARGE_NOT_FOUND);
        log.info("获取充值记录:{}", coinRecharge);

        // 判断订单是否申请退款状态
        AssertUtils.isTrue(PayStatusEnum.APPLY_REFUND.getCode() == coinRecharge.getPayStatus().intValue(), ResultCodeEnum.COIN_RECHARGE_NOT_APPLY_REFUND);
        boolean updateRefundsResult = super.update(new LambdaUpdateWrapper<CoinRefundEntity>()
                .eq(CoinRefundEntity::getId, adminRefundReviewReq.getRefundId())
                .set(CoinRefundEntity::getStatus, adminRefundReviewReq.getStatus())
                .set(CoinRefundEntity::getRemark, adminRefundReviewReq.getRemark()));
        log.info("更新退款申请结果：{}", updateRefundsResult);
        // 如果审核通过，则需要调用API发起微信退款
        RefundResponseDTO refundResponse = null;
        PayStatusEnum payStatusEnum = null;
        if (RefundStatusEnum.REVIEW_APPROVED.getCode() == adminRefundReviewReq.getStatus()) {
            payStatusEnum = PayStatusEnum.REVIEW_APPROVED;
            // 使用统一的退款接口
            BigDecimal rechargeAmount = coinRecharge.getRechargeAmount();
            Long refundAmount = MoneyUtil.yuanToCent(rechargeAmount);
            RefundOrderRequestDTO refundRequest = RefundOrderRequestDTO.builder()
                    .merchantRefundSn(coinRecharge.getRechargeSn())
                    .refundReason(coinRefund.getRefundReason())
                    .refundAmount(refundAmount)
                    .totalAmount(refundAmount)
                    .merchantRefundSn(coinRefund.getRefundSn())
                    .refundType(RefundTypeEnum.COIN_RECHARGE)
                    .build();
            log.info("发起统一退款请求：{}", refundRequest);
            // 提交退款申请，发起统一退款
            refundResponse = refundOrderServiceApi.submitRefund(refundRequest);
            log.info("发起统一退款结果：{}", refundResponse);
        } else {
            payStatusEnum = PayStatusEnum.REVIEW_REJECTED;
        }
        // 更新充值记录表状态
        boolean updateRechargeStatusResult = adminCoinRechargeService.update(new LambdaUpdateWrapper<CoinRechargeEntity>()
                .eq(CoinRechargeEntity::getId, adminRefundReviewReq.getRefundId())
                .set(CoinRechargeEntity::getPayStatus, payStatusEnum.getCode()));
        log.info("用户 {} 更新退款申请[申请记录Id ： {}] 的结果为:{}", userId, adminRefundReviewReq.getRefundId(), updateRechargeStatusResult);

        // 插入退款日志
        boolean saveLogResult = saveRefundLog(adminRefundReviewReq, refundResponse);
        log.info("保存退款日志结果：{}", saveLogResult);

        return updateRefundsResult;
    }

    private boolean saveRefundLog(AdminRefundReviewReq adminRefundReviewReq, RefundResponseDTO refundResponse) {
        CoinRefundLogEntity refundLog = new CoinRefundLogEntity();
        refundLog.setRefundId(adminRefundReviewReq.getRefundId());
        refundLog.setOperationName("管理员审核");
        refundLog.setOperationTime(LocalDateTime.now());
        refundLog.setStatus(adminRefundReviewReq.getStatus());
        if (Objects.nonNull(refundResponse)) {
            refundLog.setWxResponseJson(refundResponse.getRefundResJson());
        }
        return coinRefundLogService.save(refundLog);
    }

    @Override
    public List<CoinRefundLogEntity> getRefundLogsByRefundId(Integer refundId) {
        return coinRefundLogService.list(new LambdaQueryWrapper<>(CoinRefundLogEntity.class).eq(CoinRefundLogEntity::getRefundId, refundId));
    }

    @Override
    public WechatRefundResp getRefundResult(String refundSn) {
        RefundResponseDTO refundResponse = refundOrderServiceApi.queryRefundStatus(refundSn);
        // 转换为WechatRefundResp
        WechatRefundResp resp = new WechatRefundResp();
        resp.setRefundId(refundResponse.getRefundId());
        resp.setRefundNo(refundResponse.getRefundNo());
        resp.setTransactionId(refundResponse.getTransactionId());
        resp.setOutTradeNo(refundResponse.getOutTradeNo());
        resp.setChannel(refundResponse.getChannel());
        resp.setSuccessTime(refundResponse.getSuccessTime());
        resp.setStatus(refundResponse.getStatus());
        resp.setRefundResJson(refundResponse.getRefundResJson());
        return resp;
    }
}