package com.zhentao.service.impl;

import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.github.binarywang.wxpay.util.SignUtils;
import com.zhentao.entity.CourseOrder;
import com.zhentao.entity.Wx;
import com.zhentao.pojo.Users;
import com.zhentao.mapper.CourseOrderMapper;
import com.zhentao.service.CourseOrderService;
import com.zhentao.service.UsersService;
import com.zhentao.service.WxService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 课程订单服务实现
 */
@Slf4j
@Service
public class CourseOrderServiceImpl implements CourseOrderService {

    @Autowired
    private CourseOrderMapper courseOrderMapper;

    @Autowired
    private UsersService usersService;

    @Autowired
    private WxService wxService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> purchaseCourse(Long userId, Integer courseId, String courseName, Double price) throws WxPayException {
        // 1. 检查是否已购买
        if (checkPurchased(userId, courseId)) {
            throw new RuntimeException("您已购买过此课程");
        }

        // 2. 生成订单号
        String orderNo = generateOrderNo();
        LocalDateTime now = LocalDateTime.now();

        // 3. 创建待支付订单
        CourseOrder order = new CourseOrder();
        order.setUserId(userId);
        order.setCourseId(courseId);
        order.setCourseName(courseName);
        order.setOrderNo(orderNo);
        order.setPaymentAmount(BigDecimal.valueOf(price));
        order.setPaymentMethod("微信支付");
        order.setStatus(0); // 待支付
        order.setCreateTime(now);
        courseOrderMapper.insert(order);

        // 4. 构建微信支付请求
        WxPayUnifiedOrderRequest payRequest = buildWxPayRequest(orderNo, courseName, price, userId);
        WxPayUnifiedOrderResult wxPayResult = createWxPayOrder(payRequest);

        // 5. 生成前端调起支付的参数
        Map<String, Object> payParams = generatePayParams(wxPayResult, price);
        payParams.put("orderNo", orderNo);
        return payParams;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String handlePayNotify(String notifyData) throws WxPayException {
        // 1. 解析回调数据并验证签名
        WxPayConfig payConfig = getWxPayConfig();
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);

        WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(notifyData);
        String orderNo = notifyResult.getOutTradeNo();
        String transactionId = notifyResult.getTransactionId();

        // 2. 查询待支付订单
        CourseOrder order = courseOrderMapper.selectByOrderNo(orderNo);
        if (order == null || order.getStatus() != 0) {
            log.warn("课程订单不存在或已处理：{}", orderNo);
            return WxPayNotifyResponse.fail("订单不存在或已处理");
        }

        // 3. 验证支付金额
        int totalFee = order.getPaymentAmount().multiply(new BigDecimal("100")).intValue();
        if (Integer.parseInt(String.valueOf(notifyResult.getTotalFee())) != totalFee) {
            log.warn("课程订单金额不一致：{}，实际支付：{}", orderNo, notifyResult.getTotalFee());
            return WxPayNotifyResponse.fail("金额不一致");
        }

        // 4. 更新订单状态为已支付
        order.setStatus(1);
        order.setPaymentTime(LocalDateTime.now());
        order.setTransactionId(transactionId);
        order.setUpdateTime(LocalDateTime.now());
        courseOrderMapper.updateById(order);

        log.info("课程购买成功：用户{}，课程{}，订单{}", order.getUserId(), order.getCourseId(), orderNo);
        return WxPayNotifyResponse.success("处理成功");
    }

    @Override
    public boolean checkPurchased(Long userId, Integer courseId) {
        return courseOrderMapper.checkPurchased(userId, courseId) > 0;
    }

    @Override
    public List<Integer> getPurchasedCourseIds(Long userId) {
        return courseOrderMapper.selectPurchasedCourseIds(userId);
    }

    private String generateOrderNo() {
        return "COURSE" + System.currentTimeMillis() + RandomUtils.nextInt(1000, 9999);
    }

    private WxPayUnifiedOrderRequest buildWxPayRequest(String orderNo, String courseName, Double price, Long userId) {
        Users user = usersService.getById(userId);
        if (user == null || user.getWechatOpenid() == null) {
            throw new RuntimeException("用户微信信息未绑定");
        }

        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setOutTradeNo(orderNo);
        request.setBody("课程购买-" + courseName);
        request.setTotalFee(BigDecimal.valueOf(price).multiply(new BigDecimal("100")).intValue());
        request.setSpbillCreateIp("127.0.0.1");
        request.setNotifyUrl("https://mini.workervip.com/api/course-order/notify");
        request.setTradeType("JSAPI");
        request.setOpenid(user.getWechatOpenid());
        return request;
    }

    private WxPayUnifiedOrderResult createWxPayOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(getWxPayConfig());
        return wxPayService.unifiedOrder(request);
    }

    private Map<String, Object> generatePayParams(WxPayUnifiedOrderResult wxPayResult, Double price) {
        Wx wxConfig = wxService.list().get(0);
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = RandomStringUtils.randomAlphanumeric(32);
        String prepayId = wxPayResult.getPrepayId();

        Map<String, String> signParams = new HashMap<>();
        signParams.put("appId", wxConfig.getAppId());
        signParams.put("timeStamp", timeStamp);
        signParams.put("nonceStr", nonceStr);
        signParams.put("package", "prepay_id=" + prepayId);
        signParams.put("signType", "MD5");

        String paySign = SignUtils.createSign(signParams, "7f633cbabd894b4d213bc6edffe3b119");

        Map<String, Object> payParams = new HashMap<>();
        payParams.put("appId", wxConfig.getAppId());
        payParams.put("timeStamp", timeStamp);
        payParams.put("nonceStr", nonceStr);
        payParams.put("package", "prepay_id=" + prepayId);
        payParams.put("signType", "MD5");
        payParams.put("paySign", paySign);
        payParams.put("totalFee", BigDecimal.valueOf(price).multiply(new BigDecimal("100")).intValue());
        return payParams;
    }

    private WxPayConfig getWxPayConfig() {
        Wx wxConfig = wxService.list().get(0);
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(wxConfig.getAppId());
        payConfig.setMchId(wxConfig.getMchId());
        payConfig.setMchKey("7f633cbabd894b4d213bc6edffe3b119");
        payConfig.setNotifyUrl("https://mini.workervip.com/api/course-order/notify");
        return payConfig;
    }
}
