package shop.alien.dining.controller;


import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import shop.alien.dining.service.StoreOrderService;
import shop.alien.dining.strategy.payment.PaymentStrategyFactory;
import shop.alien.entity.result.R;
import shop.alien.util.common.constant.PaymentEnum;

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

/**
 * @author lyx
 * @version 1.0
 * @date 2025/11/20 17:34
 */
@Slf4j
@Api(tags = {"2.5-支付接口"})
@CrossOrigin
@RestController
@RequestMapping("/payment")
@RequiredArgsConstructor
public class PaymentController {

    private final PaymentStrategyFactory paymentStrategyFactory;
    private final StoreOrderService storeOrderService;


    @ApiOperation("创建预支付订单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "price", value = "订单金额", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "subject", value = "订单标题", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "payType", value = "支付类型(alipay:支付宝, wechatPay:微信支付)", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "payer", value = "支付用户", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "storeId", value = "店铺ID，用于从 MySQL 获取该店铺支付配置(StorePaymentConfig)", required = true, paramType = "query", dataType = "Integer"),
            @ApiImplicitParam(name ="couponId", value = "优惠券Id"),
            @ApiImplicitParam(name = "payerId", value = "payerId"),
            @ApiImplicitParam(name = "serviceFee", value = "服务费"),
            @ApiImplicitParam(name = "discountAmount", value = "优惠金额"),
            @ApiImplicitParam(name = "payAmount", value = "支付金额")
    })
    @RequestMapping("/prePay")
    public R prePay(String price, String subject, String payType, String payer, String orderNo, Integer storeId,Integer couponId, Integer payerId,String serviceFee,String discountAmount,String payAmount) {
        log.info("PaymentController:prePay, price: {}, subject: {}, payType: {}, payer: {}, orderNo: {}, storeId: {},couponId:{},payerId: {},serviceFee: {},discountAmount: {},payAmount:{}", price, subject, payType, payer, orderNo, storeId,couponId,payerId,serviceFee,discountAmount,payAmount);
        try {
            return paymentStrategyFactory.getStrategy(payType).createPrePayOrder(price, subject, payer, orderNo, storeId, couponId,payerId,serviceFee,discountAmount,payAmount);
        } catch (Exception e) {
            log.info("createPrePayOrder, orderNo: {}, error: {}", orderNo, e.getMessage());
            return R.fail(e.getMessage());
        }
    }

    /**
     * 微信支付回调通知接口（符合微信支付 V3 规范）
     * 验签通过：返回 204 无包体；验签失败：返回 5XX + {"code":"FAIL","message":"失败"}
     * @param notifyData 回调 JSON 报文
     * @return 204 无 body 或 5XX + 失败报文
     */
    /**
     * 服务商模式小程序支付回调（与直连小程序回调分离，需在商户平台配置 notify_url 指向本地址）
     */
    @RequestMapping("/weChatPartnerMininNotify")
    public ResponseEntity<?> weChatPartnerMininNotify(@RequestBody String notifyData, HttpServletRequest request) throws Exception {
        log.info("[微信服务商小程序回调] 收到请求, Content-Length={}, Wechatpay-Serial={}",
                request.getContentLength(), request.getHeader("Wechatpay-Serial"));
        try {
            R result = paymentStrategyFactory.getStrategy(PaymentEnum.WECHAT_PAY_PARTNER_MININ_PROGRAM.getType()).handleNotify(notifyData, request);
            if (R.isSuccess(result)) {
                return ResponseEntity.noContent().build();
            }
            String message = result.getMsg() != null ? result.getMsg() : "失败";
            Map<String, String> failBody = new HashMap<>(2);
            failBody.put("code", "FAIL");
            failBody.put("message", message);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(failBody);
        } catch (Exception e) {
            log.error("[微信服务商小程序回调] 处理异常", e);
            String msg = e.getMessage() != null ? e.getMessage() : "失败";
            Map<String, String> failBody = new HashMap<>(2);
            failBody.put("code", "FAIL");
            failBody.put("message", msg);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(failBody);
        }
    }

    @RequestMapping("/weChatMininNotify")
    public ResponseEntity<?> notify(@RequestBody String notifyData, HttpServletRequest request) throws Exception {
        log.info("[微信支付回调] 收到回调请求, Content-Length={}, Wechatpay-Serial={}", request.getContentLength(), request.getHeader("Wechatpay-Serial"));
        try {
            R result = paymentStrategyFactory.getStrategy(PaymentEnum.WECHAT_PAY_MININ_PROGRAM.getType()).handleNotify(notifyData, request);
            if (R.isSuccess(result)) {
                // 文档要求：验签通过时 HTTP 200 或 204，无需返回应答报文
                return ResponseEntity.noContent().build();
            } else {
                // 文档要求：验签不通过时 4XX/5XX，并返回 {"code":"FAIL","message":"失败"}
                String message = result.getMsg() != null ? result.getMsg() : "失败";
                Map<String, String> failBody = new HashMap<>(2);
                failBody.put("code", "FAIL");
                failBody.put("message", message);
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(failBody);
            }
        } catch (Exception e) {
            log.error("[微信支付回调] 处理异常", e);
            String msg = e.getMessage() != null ? e.getMessage() : "失败";
            Map<String, String> failBody = new HashMap<>(2);
            failBody.put("code", "FAIL");
            failBody.put("message", msg);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(failBody);
        }
    }

    /**
     * 支付成功后重置餐桌与购物车（内部接口，供 alien-store 微信 APP 服务商回调等调用，与 {@link StoreOrderService#resetTableAfterPayment} 一致）
     */
    @PostMapping("/internal/resetTableAfterPayment")
    public R<Void> internalResetTableAfterPayment(
            @RequestParam("tableId") Integer tableId,
            @RequestParam(value = "menuType", required = false) Integer menuType) {
        log.info("[PaymentController] internalResetTableAfterPayment tableId={}, menuType={}", tableId, menuType);
        try {
            if (tableId == null) {
                return R.fail("tableId 不能为空");
            }
            storeOrderService.resetTableAfterPayment(tableId);
            return R.success("OK");
        } catch (Exception e) {
            log.error("[PaymentController] internalResetTableAfterPayment 失败 tableId={}", tableId, e);
            return R.fail(e.getMessage() != null ? e.getMessage() : "重置失败");
        }
    }

    /**
     * 查询订单状态
     * @param transactionId 交易订单号（微信支付订单号/商户订单号）
     * @param payType 支付类型
     * @param storeId 店铺ID，用于从 MySQL 获取该店铺支付配置
     * @return 订单状态信息
     */
    @RequestMapping("/searchOrderByOutTradeNoPath")
    public R searchOrderByOutTradeNoPath(String transactionId, String payType, Integer storeId) {
        log.info("PaymentController.searchOrderByOutTradeNoPath?transactionId={}, payType={}, storeId={}", transactionId, payType, storeId);
        try {
            return paymentStrategyFactory.getStrategy(payType).searchOrderByOutTradeNoPath(transactionId, storeId);
        } catch (Exception e) {
            return R.fail(e.getMessage());
        }
    }

    /**
     * 退款接口
     * @param params 退款参数（包含订单号、退款金额等）
     * @return 退款结果
     */
    @RequestMapping("/refunds")
    public R refunds(@RequestBody Map<String, String> params) {
        log.info("PaymentController.refunds?params={}", params);
        try {
            return R.data(paymentStrategyFactory.getStrategy(params.get("payType")).handleRefund(params));
        } catch (Exception e) {
            return R.fail(e.getMessage());
        }
    }
}
