package com.dora.controller;

import com.dora.common.Result;
import com.dora.dto.WxPayRequestDto;
import com.dora.dto.WxOrderQueryDto;
import com.dora.dto.WxCloseOrderDto;
import com.dora.dto.WxRefundRequestDto;
import com.dora.entity.Order;
import com.dora.mapper.OrderMapper;
import com.dora.service.WxPayCallbackService;
import com.dora.util.SecurityUtil;
import com.dora.util.ServletAdapter;
import com.hh.enums.PayType;
import com.hh.factory.factories.PayFactory;
import com.hh.factory.products.PayProduct;
import com.hh.factory.vo.req.PayReqVO;
import com.hh.factory.vo.req.RefundReqVO;
import com.hh.factory.vo.resp.WxOrderRespVO;
import com.hh.wx.v2.enums.WxPayEnum;
import com.hh.wx.v2.enums.WxRefundEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付控制器
 */
@Slf4j
@RestController
@RequestMapping("/user/pay")
@Tag(name = "微信支付", description = "微信支付相关接口")
public class WxPayController {

    @Autowired
    private PayFactory payFactory;

    @Autowired
    private ServletAdapter servletAdapter;

    @Autowired
    private WxPayCallbackService wxPayCallbackService;
    
    @Autowired
    private OrderMapper orderMapper;

    @Value("${wx2.mchKey}")
    private String mchKey;

    /**
     * 下单
     */
    @PostMapping("/placeOrder")
    @Operation(summary = "微信支付下单", description = "创建微信支付订单")
    public Result<Map<String, String>> placeOrder(@Validated @RequestBody WxPayRequestDto requestDto) {
        try {
            // 初始化支付工厂，类型选择微信支付V2版本
            PayProduct payProduct = payFactory.init(PayType.WX_V2);
            
            // 构建支付请求参数
            PayReqVO payReqVO = new PayReqVO();
            payReqVO.setAmounts(requestDto.getAmounts());
            payReqVO.setOrderNo(requestDto.getOrderNo());
            payReqVO.setDescription(requestDto.getDescription());
            payReqVO.setTradeType(requestDto.getTradeType());
            payReqVO.setOpenid(requestDto.getOpenid());
            payReqVO.setAuthCode(requestDto.getAuthCode());
            payReqVO.setNotifyUrl(requestDto.getNotifyUrl());
            payReqVO.setSubMchId(requestDto.getSubMchId());
            payReqVO.setSubAppid(requestDto.getSubAppid());
            payReqVO.setSubOpenid(requestDto.getSubOpenid());
            
            // 调用下单接口
            Map<String, String> result = payProduct.placeOrder(payReqVO);
            
            log.info("微信支付下单成功，订单号：{}，结果：{}", requestDto.getOrderNo(), result);
            return Result.success(result);
            
        } catch (Exception e) {
            log.error("微信支付下单失败，订单号：{}，错误：{}", requestDto.getOrderNo(), e.getMessage(), e);
            return Result.error("支付下单失败：" + e.getMessage());
        }
    }

    /**
     * 查询订单
     */
    @PostMapping("/orderQuery")
    @Operation(summary = "查询微信支付订单", description = "查询微信支付订单状态")
    public Result<String> orderQuery(@Validated @RequestBody WxOrderQueryDto requestDto) {
        try {
            // 初始化支付工厂，类型选择微信支付V2版本
            PayProduct payProduct = payFactory.init(PayType.WX_V2);
            
            // 构建查询请求参数
            PayReqVO payReqVO = new PayReqVO();
            payReqVO.setOrderNo(requestDto.getOrderNo());
            payReqVO.setSubMchId(requestDto.getSubMchId());
            
            // 调用订单查询接口
            WxPayEnum wxPayEnum = payProduct.orderquery(payReqVO);
            
            log.info("微信支付订单查询成功，订单号：{}，状态：{}", requestDto.getOrderNo(), wxPayEnum.name());
            return Result.success(wxPayEnum.name());
            
        } catch (Exception e) {
            log.error("微信支付订单查询失败，订单号：{}，错误：{}", requestDto.getOrderNo(), e.getMessage(), e);
            return Result.error("订单查询失败：" + e.getMessage());
        }
    }

    /**
     * 关闭订单
     */
    @PostMapping("/closeOrder")
    @Operation(summary = "关闭微信支付订单", description = "关闭未支付的微信支付订单")
    public Result<Boolean> closeOrder(@Validated @RequestBody WxCloseOrderDto requestDto) {
        try {
            // 获取当前用户ID
            Long currentUserId = SecurityUtil.getCurrentUserId();
            if (currentUserId == null) {
                return Result.error("用户未登录");
            }
            
            // 1. 验证订单存在且属于当前用户
            Order order = orderMapper.selectByOrderNo(requestDto.getOrderNo());
            if (order == null) {
                log.warn("订单不存在，订单号：{}", requestDto.getOrderNo());
                return Result.error("订单不存在");
            }
            
            if (!order.getUserId().equals(currentUserId)) {
                log.warn("用户{}尝试关闭不属于自己的订单：{}", currentUserId, requestDto.getOrderNo());
                return Result.error("无权操作此订单");
            }
            
            // 2. 检查订单状态（只能关闭待支付的订单）
            if (order.getStatus() != 0) {
                String statusDesc = getOrderStatusDesc(order.getStatus());
                log.warn("订单状态不允许关闭，订单号：{}，当前状态：{}", requestDto.getOrderNo(), statusDesc);
                return Result.error("只能关闭待支付的订单，当前状态：" + statusDesc);
            }
            
            // 3. 调用微信关闭订单接口
            PayProduct payProduct = payFactory.init(PayType.WX_V2);
            PayReqVO payReqVO = new PayReqVO();
            payReqVO.setOrderNo(requestDto.getOrderNo());
            payReqVO.setSubMchId(requestDto.getSubMchId());
            
            Boolean wxResult = payProduct.closeorder(payReqVO);
            if (!wxResult) {
                log.error("微信支付接口关闭订单失败，订单号：{}", requestDto.getOrderNo());
                return Result.error("微信支付关闭订单失败");
            }
            
            // 4. 更新本地订单状态为已取消(状态2)
            int rows = orderMapper.updateOrderStatus(requestDto.getOrderNo(), 2, null, null);
            if (rows <= 0) {
                log.error("更新本地订单状态失败，订单号：{}", requestDto.getOrderNo());
                // 注意：这里微信侧已经关闭，但本地状态更新失败，需要告知用户
                return Result.error("订单已在微信侧关闭，但本地状态更新失败，请联系客服");
            }
            
            log.info("订单关闭成功，订单号：{}，用户：{}，取消原因：{}", 
                    requestDto.getOrderNo(), currentUserId, requestDto.getCancelReason());
            return Result.success(true);
            
        } catch (Exception e) {
            log.error("关闭订单时发生异常，订单号：{}，错误：{}", requestDto.getOrderNo(), e.getMessage(), e);
            return Result.error("关闭订单失败：" + e.getMessage());
        }
    }
    
    /**
     * 获取订单状态描述
     */
    private String getOrderStatusDesc(Integer status) {
        if (status == null) return "未知";
        switch (status) {
            case 0: return "待支付";
            case 1: return "已完成"; 
            case 2: return "已取消";
            case 3: return "支付失败";
            default: return "未知状态(" + status + ")";
        }
    }

    /**
     * 申请退款
     */
    @PostMapping("/refund")
    @Operation(summary = "申请微信支付退款", description = "申请微信支付订单退款")
    public Result<Boolean> refund(@Validated @RequestBody WxRefundRequestDto requestDto) {
        try {
            // 初始化支付工厂，类型选择微信支付V2版本
            PayProduct payProduct = payFactory.init(PayType.WX_V2);
            
            // 构建退款请求参数
            RefundReqVO refundReqVO = new RefundReqVO();
            refundReqVO.setOrderNo(requestDto.getOrderNo());
            refundReqVO.setRefundFee(requestDto.getRefundFee());
            refundReqVO.setSubMchId(requestDto.getSubMchId());
            
            // 调用退款申请接口
            Boolean result = payProduct.refund(refundReqVO);
            
            if (result) {
                log.info("微信支付退款申请成功，订单号：{}，退款金额：{}", requestDto.getOrderNo(), requestDto.getRefundFee());
                return Result.success(true);
            } else {
                log.warn("微信支付退款申请失败，订单号：{}", requestDto.getOrderNo());
                return Result.error("退款申请失败");
            }
            
        } catch (Exception e) {
            log.error("微信支付退款申请失败，订单号：{}，错误：{}", requestDto.getOrderNo(), e.getMessage(), e);
            return Result.error("退款申请失败：" + e.getMessage());
        }
    }

    /**
     * 查询退款订单
     */
    @PostMapping("/refundQuery")
    @Operation(summary = "查询微信支付退款订单", description = "查询微信支付退款订单状态")
    public Result<String> refundQuery(@Validated @RequestBody WxRefundRequestDto requestDto) {
        try {
            // 初始化支付工厂，类型选择微信支付V2版本
            PayProduct payProduct = payFactory.init(PayType.WX_V2);
            
            // 构建退款查询请求参数
            RefundReqVO refundReqVO = new RefundReqVO();
            refundReqVO.setOrderNo(requestDto.getOrderNo());
            refundReqVO.setSubMchId(requestDto.getSubMchId());
            
            // 调用查询退款订单接口
            WxRefundEnum wxRefundEnum = payProduct.refundquery(refundReqVO);
            
            log.info("微信支付退款订单查询成功，订单号：{}，状态：{}", requestDto.getOrderNo(), wxRefundEnum.name());
            return Result.success(wxRefundEnum.name());
            
        } catch (Exception e) {
            log.error("微信支付退款订单查询失败，订单号：{}，错误：{}", requestDto.getOrderNo(), e.getMessage(), e);
            return Result.error("退款订单查询失败：" + e.getMessage());
        }
    }

    /**
     * 支付回调
     */
    @RequestMapping("/callback")
    @Operation(summary = "微信支付回调", description = "处理微信支付异步回调")
    public String callback(HttpServletRequest request) {
        try {
            log.info("收到微信支付回调请求");
            
            // 使用适配器转换请求参数
            Map<String, String> requestMap = servletAdapter.convertRequestToMap(request);
            log.info("回调请求参数: {}", requestMap);
            
            // 验证签名
            boolean signValid = servletAdapter.verifyWxPayCallback(requestMap, mchKey);
            if (!signValid) {
                log.error("微信支付回调签名验证失败");
                return convertMapToXml(createFailResponse("签名验证失败"));
            }
            
            // 解析回调数据
            String returnCode = requestMap.get("return_code");
            String resultCode = requestMap.get("result_code");
            String orderNo = requestMap.get("out_trade_no");
            String transactionId = requestMap.get("transaction_id");
            String totalFee = requestMap.get("total_fee");
            
            log.info("微信支付回调解析: returnCode={}, resultCode={}, orderNo={}, transactionId={}, totalFee={}", 
                returnCode, resultCode, orderNo, transactionId, totalFee);
            
            // 处理支付结果
            if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
                // 支付成功，处理业务逻辑
                log.info("微信支付成功，订单号：{}，微信交易号：{}", orderNo, transactionId);
                
                // 验证订单号和金额
                if (!wxPayCallbackService.validateOrderNo(orderNo) || !wxPayCallbackService.validateAmount(totalFee)) {
                    log.error("回调参数验证失败，订单号：{}，金额：{}", orderNo, totalFee);
                    return convertMapToXml(createFailResponse("参数验证失败"));
                }
                
                // 调用回调服务处理业务逻辑
                try {
                    wxPayCallbackService.handlePaymentSuccess(orderNo, transactionId, totalFee);
                } catch (Exception e) {
                    log.error("处理支付成功回调业务逻辑时发生错误：{}", e.getMessage(), e);
                    // 即使业务逻辑处理失败，也要返回成功给微信，避免重复回调
                }
                
                // 返回成功响应
                return convertMapToXml(createSuccessResponse());
                
            } else if ("SUCCESS".equals(returnCode) && "FAIL".equals(resultCode)) {
                // 支付失败
                String errCode = requestMap.get("err_code");
                String errCodeDes = requestMap.get("err_code_des");
                log.warn("微信支付失败，订单号：{}，错误码：{}，错误描述：{}", orderNo, errCode, errCodeDes);
                
                // 调用回调服务处理支付失败逻辑
                try {
                    wxPayCallbackService.handlePaymentFailure(orderNo, errCode, errCodeDes);
                } catch (Exception e) {
                    log.error("处理支付失败回调业务逻辑时发生错误：{}", e.getMessage(), e);
                }
                
                return convertMapToXml(createSuccessResponse());
                
            } else {
                // 通信失败
                String returnMsg = requestMap.get("return_msg");
                log.error("微信支付通信失败，返回码：{}，返回信息：{}", returnCode, returnMsg);
                return convertMapToXml(createFailResponse(returnMsg));
            }
            
        } catch (Exception e) {
            log.error("处理微信支付回调时发生异常：{}", e.getMessage(), e);
            return convertMapToXml(createFailResponse("系统异常"));
        }
    }
    
    /**
     * 创建成功响应
     */
    private Map<String, String> createSuccessResponse() {
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("return_code", "SUCCESS");
        resultMap.put("return_msg", "OK");
        return resultMap;
    }
    
    /**
     * 创建失败响应
     */
    private Map<String, String> createFailResponse(String message) {
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("return_code", "FAIL");
        resultMap.put("return_msg", message != null ? message : "处理失败");
        return resultMap;
    }

    /**
     * 将Map转换为XML格式
     */
    private String convertMapToXml(Map<String, String> data) {
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        for (Map.Entry<String, String> entry : data.entrySet()) {
            sb.append("<").append(entry.getKey()).append(">");
            sb.append("<![CDATA[").append(entry.getValue()).append("]]>");
            sb.append("</").append(entry.getKey()).append(">");
        }
        sb.append("</xml>");
        return sb.toString();
    }
} 