package org.dromara.main.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.main.domain.MainBackOrder;
import org.dromara.main.domain.MainOrder;
import org.dromara.main.domain.Payment;
import org.dromara.main.domain.PaymentConfig;
import org.dromara.main.domain.vo.PaymentVo;
import org.dromara.main.mapper.MainBackOrderMapper;
import org.dromara.main.mapper.MainOrderMapper;
import org.dromara.main.mapper.PaymentMapper;
import org.dromara.main.service.IPaymentConfigService;
import org.dromara.main.service.IPaymentService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

@Slf4j
@RequiredArgsConstructor
@Service
public class PaymentServiceImpl implements IPaymentService {

    private final PaymentMapper paymentMapper;
    private final MainOrderMapper mainOrderMapper;
    private final MainBackOrderMapper mainBackOrderMapper;
    private final IPaymentConfigService paymentConfigService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PaymentVo createAlipayQrCode(Long orderId, String tenantId) {
        MainOrder order = mainOrderMapper.selectById(orderId);
        if (order == null) {
            throw new ServiceException("订单不存在");
        }
        if (tenantId != null && !tenantId.equals(order.getTenantId())) {
            throw new ServiceException("无权操作该订单");
        }
        if (order.getPayStatus() != null && order.getPayStatus() != 0) {
            throw new ServiceException("订单已支付或已关闭");
        }

        Payment existPayment = paymentMapper.selectOne(
            Wrappers.<Payment>lambdaQuery()
                .eq(Payment::getOrderId, orderId)
                .in(Payment::getPaymentStatus, java.util.List.of(0, 1))
                .orderByDesc(Payment::getCreateTime)
                .last("limit 1")
        );
        if (existPayment != null) {
            try {
                String formHtml = createAlipayPagePayInternal(existPayment, order);
                PaymentVo vo = paymentMapper.selectVoById(existPayment.getId());
                vo.setQrCodeUrl(formHtml);
                return vo;
            } catch (AlipayApiException e) {
                throw new ServiceException("生成支付表单失败：" + e.getMessage());
            }
        }

        Payment payment = new Payment();
        payment.setPaymentNo(generatePaymentNo());
        payment.setOrderId(orderId);
        payment.setOrderNo(order.getOrderNo());
        payment.setPaymentType(3);
        payment.setPaymentAmount(order.getTotalAmount());
        payment.setPaymentStatus(0);
        paymentMapper.insert(payment);

        try {
            String formHtml = createAlipayPagePayInternal(payment, order);
            payment.setPaymentStatus(1);
            paymentMapper.updateById(payment);

            PaymentVo vo = paymentMapper.selectVoById(payment.getId());
            vo.setQrCodeUrl(formHtml);
            return vo;
        } catch (Exception e) {
            payment.setPaymentStatus(3);
            payment.setRemark("创建支付失败：" + e.getMessage());
            paymentMapper.updateById(payment);
            throw new ServiceException("创建支付失败：" + e.getMessage());
        }
    }

    private String createAlipayPagePayInternal(Payment payment, MainOrder order) throws AlipayApiException {
        PaymentConfig config = paymentConfigService.getEnabledAlipayConfig();
        if (config == null) {
            throw new ServiceException("未找到启用的支付宝配置");
        }

        AlipayClient client = new DefaultAlipayClient(
            config.getGatewayUrl(),
            config.getAppId(),
            config.getPrivateKey(),
            defaultIfBlank(config.getFormat(), "json"),
            defaultIfBlank(config.getCharset(), "UTF-8"),
            config.getPublicKey(),
            defaultIfBlank(config.getSignType(), "RSA2")
        );

        com.alipay.api.request.AlipayTradePagePayRequest request =
            new com.alipay.api.request.AlipayTradePagePayRequest();
        request.setNotifyUrl(config.getPayNotifyUrl());
        request.setReturnUrl(config.getReturnUrl());

        JSONObject bizContent = JSONUtil.createObj();
        bizContent.set("out_trade_no", payment.getPaymentNo());
        bizContent.set("total_amount", payment.getPaymentAmount().toString());
        bizContent.set("subject", "背调服务订单-" + order.getOrderNo());
        bizContent.set("body", "背调服务订单支付");
        bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");
        bizContent.set("timeout_express", "30m");
        request.setBizContent(bizContent.toString());

        com.alipay.api.response.AlipayTradePagePayResponse response = client.pageExecute(request);
        if (!response.isSuccess()) {
            throw new ServiceException("支付宝返回错误：" + response.getSubMsg());
        }
        return response.getBody();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String handleAlipayNotify(Map<String, String> params) {
        try {
            PaymentConfig config = paymentConfigService.getEnabledReceiveConfig();
            if (config == null) {
                log.error("未找到启用的支付宝配置");
                return "failure";
            }

            boolean signVerified = AlipaySignature.rsaCheckV1(
                params,
                config.getPublicKey(),
                defaultIfBlank(config.getCharset(), "UTF-8"),
                defaultIfBlank(config.getSignType(), "RSA2")
            );
            if (!signVerified) {
                log.error("支付宝回调签名验证失败");
                return "failure";
            }

            String outTradeNo = params.get("out_trade_no");
            String tradeNo = params.get("trade_no");
            String tradeStatus = params.get("trade_status");
            String totalAmount = params.get("total_amount");

            Payment payment = paymentMapper.selectOne(
                Wrappers.<Payment>lambdaQuery()
                    .eq(Payment::getPaymentNo, outTradeNo)
                    .last("limit 1")
            );
            if (payment == null) {
                return "failure";
            }
            if (payment.getPaymentStatus() != null && payment.getPaymentStatus() == 2) {
                return "success";
            }

            BigDecimal notifyAmount = new BigDecimal(totalAmount);
            if (notifyAmount.compareTo(payment.getPaymentAmount()) != 0) {
                log.error("支付金额不匹配：expect={}, actual={}", payment.getPaymentAmount(), notifyAmount);
                return "failure";
            }

            if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                payment.setTradeNo(tradeNo);
                payment.setTradeStatus(tradeStatus);
                payment.setPaymentMethod(2);
                payment.setPaymentStatus(2);
                payment.setPayTime(new Date());
                paymentMapper.updateById(payment);

                MainOrder order = mainOrderMapper.selectById(payment.getOrderId());
                if (order != null && order.getOrderStatus() != null && order.getOrderStatus() == 0) {
                    order.setOrderStatus(1);
                    order.setPayStatus(2);
                    order.setPaidAmount(payment.getPaymentAmount());
                    order.setPayTime(new Date());
                    mainOrderMapper.updateById(order);

                    if (order.getOrderType() != null && order.getOrderType() == 3 && order.getBusinessId() != null) {
                        MainBackOrder backOrder = mainBackOrderMapper.selectById(order.getBusinessId());
                        if (backOrder != null && "0".equals(backOrder.getStatus())) {
                            backOrder.setStatus("1");
                            mainBackOrderMapper.updateById(backOrder);
                        }
                    }
                }
                return "success";
            }
            return "success";
        } catch (Exception e) {
            log.error("处理支付宝回调异常", e);
            return "failure";
        }
    }

    @Override
    public Boolean alipayRefund(String tradeNo, BigDecimal refundAmount, String refundNo, String refundReason) {
        try {
            PaymentConfig config = paymentConfigService.getEnabledAlipayConfig();
            if (config == null) {
                throw new ServiceException("支付宝配置不存在");
            }

            AlipayClient alipayClient = new DefaultAlipayClient(
                config.getGatewayUrl(),
                config.getAppId(),
                config.getPrivateKey(),
                defaultIfBlank(config.getFormat(), "json"),
                defaultIfBlank(config.getCharset(), "UTF-8"),
                config.getPublicKey(),
                defaultIfBlank(config.getSignType(), "RSA2")
            );

            com.alipay.api.request.AlipayTradeRefundRequest request =
                new com.alipay.api.request.AlipayTradeRefundRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.set("trade_no", tradeNo);
            bizContent.set("refund_amount", refundAmount);
            bizContent.set("refund_reason", refundReason);
            bizContent.set("out_request_no", refundNo);
            request.setBizContent(bizContent.toString());

            com.alipay.api.response.AlipayTradeRefundResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                log.info("支付宝退款成功：tradeNo={}, refundAmount={}, refundNo={}", tradeNo, refundAmount, refundNo);
                return true;
            }

            log.error("支付宝退款失败：tradeNo={}, code={}, msg={}, subCode={}, subMsg={}",
                tradeNo, response.getCode(), response.getMsg(), response.getSubCode(), response.getSubMsg());
            return false;
        } catch (AlipayApiException e) {
            log.error("支付宝退款异常：tradeNo={}, error={}", tradeNo, e.getMessage(), e);
            throw new ServiceException("支付宝退款失败：{}", e.getMessage());
        }
    }

    @Override
    public PaymentVo queryPaymentStatus(Long orderId) {
        Payment payment = paymentMapper.selectOne(
            Wrappers.<Payment>lambdaQuery()
                .eq(Payment::getOrderId, orderId)
                .orderByDesc(Payment::getCreateTime)
                .last("limit 1")
        );
        return payment == null ? null : paymentMapper.selectVoById(payment.getId());
    }

    @Override
    public PaymentVo queryByPaymentNo(String paymentNo) {
        Payment payment = paymentMapper.selectOne(
            Wrappers.<Payment>lambdaQuery()
                .eq(Payment::getPaymentNo, paymentNo)
                .last("limit 1")
        );
        return payment == null ? null : paymentMapper.selectVoById(payment.getId());
    }

    private String generatePaymentNo() {
        return "PAY" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomNumbers(4);
    }

    private String defaultIfBlank(String value, String defaultValue) {
        return (value == null || value.isBlank()) ? defaultValue : value;
    }
}
