package com.gxwebsoft.payment.controller;

import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.payment.constants.PaymentConstants;
import com.gxwebsoft.payment.dto.PaymentRequest;
import com.gxwebsoft.payment.dto.PaymentResponse;
import com.gxwebsoft.payment.dto.PaymentStatusUpdateRequest;
import com.gxwebsoft.payment.dto.PaymentWithOrderRequest;
import com.gxwebsoft.payment.enums.PaymentType;
import com.gxwebsoft.payment.exception.PaymentException;
import com.gxwebsoft.payment.service.PaymentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * 统一支付控制器
 * 提供所有支付方式的统一入口
 *
 * @author 科技小王子
 * @since 2025-01-26
 */
@Slf4j
@Validated
@Tag(name = "统一支付接口", description = "支持所有支付方式的统一支付接口")
@RestController("unifiedPaymentController")
@RequestMapping("/api/payment")
public class PaymentController extends BaseController {

    @Resource(name = "unifiedPaymentServiceImpl")
    private PaymentService paymentService;

    @Operation(summary = "创建支付订单", description = "支持微信、支付宝、银联等多种支付方式")
    @PostMapping("/create")
    public ApiResult<?> createPayment(@Valid @RequestBody PaymentRequest request) {
        log.info("收到支付请求: {}", request);
        final User loginUser = getLoginUser();

        if(loginUser == null){
            return fail("请先登录");
        }

        request.setUserId(loginUser.getUserId());
        if(request.getTenantId() ==  null){
            request.setTenantId(loginUser.getTenantId());
        }
        try {
            PaymentResponse response = paymentService.createPayment(request);
            return this.<PaymentResponse>success("支付订单创建成功", response);

        } catch (PaymentException e) {
            log.error("支付订单创建失败: {}", e.getMessage());
            return fail(e.getMessage());
        } catch (Exception e) {
            log.error("支付订单创建系统错误: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "创建支付订单（包含订单信息）", description = "统一支付模块：创建订单并发起支付")
    @PostMapping("/create-with-order")
    public ApiResult<?> createPaymentWithOrder(@Valid @RequestBody PaymentWithOrderRequest request) {
        log.info("收到支付与订单创建请求: {}", request);
        final User loginUser = getLoginUser();

        if(loginUser == null){
            return fail("请先登录");
        }

        // 设置用户信息
        if(request.getTenantId() == null){
            request.setTenantId(loginUser.getTenantId());
        }

        try {
            PaymentResponse response = paymentService.createPaymentWithOrder(request, loginUser);
            return this.<PaymentResponse>success("订单创建并发起支付成功", response);
        } catch (PaymentException e) {
            log.error("创建支付订单失败: {}", e.getMessage());
            return fail(e.getMessage());
        } catch (Exception e) {
            log.error("创建支付订单系统错误: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "查询支付状态", description = "查询指定订单的支付状态")
    @GetMapping("/query")
    public ApiResult<?> queryPayment(
            @Parameter(description = "订单号", required = true)
            @RequestParam @NotBlank(message = "订单号不能为空") String orderNo,

            @Parameter(description = "支付类型", required = true)
            @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,

            @Parameter(description = "租户ID", required = true)
            @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {

        log.info("查询支付状态: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId);

        // 参数验证
        if (orderNo == null || orderNo.trim().isEmpty()) {
            return fail("订单号不能为空");
        }
        if (paymentType == null) {
            return fail("支付类型不能为空");
        }
        if (tenantId == null || tenantId <= 0) {
            return fail("租户ID不能为空且必须为正数");
        }

        try {
            PaymentResponse response = paymentService.queryPayment(orderNo, paymentType, tenantId);
            return this.<PaymentResponse>success("支付状态查询成功", response);

        } catch (PaymentException e) {
            log.error("支付状态查询失败: {}", e.getMessage());
            return fail(e.getMessage());
        } catch (Exception e) {
            log.error("支付状态查询系统错误: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "申请退款", description = "申请订单退款")
    @PostMapping("/refund")
    public ApiResult<?> refund(
            @Parameter(description = "订单号", required = true)
            @RequestParam @NotBlank(message = "订单号不能为空") String orderNo,

            @Parameter(description = "退款单号", required = true)
            @RequestParam @NotBlank(message = "退款单号不能为空") String refundNo,

            @Parameter(description = "支付类型", required = true)
            @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,

            @Parameter(description = "订单总金额", required = true)
            @RequestParam @NotNull(message = "订单总金额不能为空") @Positive(message = "订单总金额必须大于0") BigDecimal totalAmount,

            @Parameter(description = "退款金额", required = true)
            @RequestParam @NotNull(message = "退款金额不能为空") @Positive(message = "退款金额必须大于0") BigDecimal refundAmount,

            @Parameter(description = "退款原因")
            @RequestParam(required = false) String reason,

            @Parameter(description = "租户ID", required = true)
            @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {

        log.info("申请退款: orderNo={}, refundNo={}, paymentType={}, totalAmount={}, refundAmount={}, tenantId={}",
            orderNo, refundNo, paymentType, totalAmount, refundAmount, tenantId);

        try {
            PaymentResponse response = paymentService.refund(orderNo, refundNo, paymentType,
                totalAmount, refundAmount, reason, tenantId);
            return this.<PaymentResponse>success("退款申请成功", response);

        } catch (PaymentException e) {
            log.error("退款申请失败: {}", e.getMessage());
            return fail(e.getMessage());
        } catch (Exception e) {
            log.error("退款申请系统错误: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "查询退款状态", description = "查询指定退款单的状态")
    @GetMapping("/refund/query")
    public ApiResult<?> queryRefund(
            @Parameter(description = "退款单号", required = true)
            @RequestParam @NotBlank(message = "退款单号不能为空") String refundNo,

            @Parameter(description = "支付类型", required = true)
            @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,

            @Parameter(description = "租户ID", required = true)
            @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {

        log.info("查询退款状态: refundNo={}, paymentType={}, tenantId={}", refundNo, paymentType, tenantId);

        try {
            PaymentResponse response = paymentService.queryRefund(refundNo, paymentType, tenantId);
            return this.<PaymentResponse>success("退款状态查询成功", response);

        } catch (PaymentException e) {
            log.error("退款状态查询失败: {}", e.getMessage());
            return fail(e.getMessage());
        } catch (Exception e) {
            log.error("退款状态查询系统错误: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "关闭订单", description = "关闭未支付的订单")
    @PostMapping("/close")
    public ApiResult<?> closeOrder(
            @Parameter(description = "订单号", required = true)
            @RequestParam @NotBlank(message = "订单号不能为空") String orderNo,

            @Parameter(description = "支付类型", required = true)
            @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,

            @Parameter(description = "租户ID", required = true)
            @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {

        log.info("关闭订单: orderNo={}, paymentType={}, tenantId={}", orderNo, paymentType, tenantId);

        try {
            boolean result = paymentService.closeOrder(orderNo, paymentType, tenantId);
            return success(result ? "订单关闭成功" : "订单关闭失败", result);

        } catch (PaymentException e) {
            log.error("订单关闭失败: {}", e.getMessage());
            return fail(e.getMessage());
        } catch (Exception e) {
            log.error("订单关闭系统错误: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "获取支持的支付类型", description = "获取系统支持的所有支付类型列表")
    @GetMapping("/types")
    public ApiResult<?> getSupportedPaymentTypes() {
        try {
            List<PaymentType> paymentTypes = paymentService.getSupportedPaymentTypes();
            return this.<List<PaymentType>>success("获取支付类型成功", paymentTypes);
        } catch (Exception e) {
            log.error("获取支付类型失败: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "获取支付策略信息", description = "获取指定支付类型的策略信息")
    @GetMapping("/strategy/{paymentType}")
    public ApiResult<?> getPaymentStrategyInfo(
            @Parameter(description = "支付类型", required = true)
            @PathVariable @NotNull(message = "支付类型不能为空") PaymentType paymentType) {

        try {
            Map<String, Object> strategyInfo = paymentService.getPaymentStrategyInfo(paymentType);
            if (strategyInfo == null) {
                return fail("不支持的支付类型: " + paymentType);
            }
            return success("获取策略信息成功", strategyInfo);
        } catch (Exception e) {
            log.error("获取策略信息失败: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "获取所有支付策略信息", description = "获取系统所有支付策略的详细信息")
    @GetMapping("/strategies")
    public ApiResult<?> getAllPaymentStrategyInfo() {
        try {
            List<Map<String, Object>> strategiesInfo = paymentService.getAllPaymentStrategyInfo();
            return this.<List<Map<String, Object>>>success("获取所有策略信息成功", strategiesInfo);
        } catch (Exception e) {
            log.error("获取所有策略信息失败: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "检查支付类型支持情况", description = "检查指定支付类型的功能支持情况")
    @GetMapping("/support/{paymentType}")
    public ApiResult<?> checkPaymentTypeSupport(
            @Parameter(description = "支付类型", required = true)
            @PathVariable @NotNull(message = "支付类型不能为空") PaymentType paymentType) {

        try {
            Map<String, Boolean> support = Map.of(
                "supported", paymentService.isPaymentTypeSupported(paymentType),
                "refundSupported", paymentService.isRefundSupported(paymentType),
                "querySupported", paymentService.isQuerySupported(paymentType),
                "closeSupported", paymentService.isCloseSupported(paymentType),
                "notifyNeeded", paymentService.isNotifyNeeded(paymentType)
            );
            return this.<Map<String, Boolean>>success("检查支持情况成功", support);
        } catch (Exception e) {
            log.error("检查支持情况失败: {}", e.getMessage(), e);
            return fail(PaymentConstants.ErrorMessage.SYSTEM_ERROR);
        }
    }

    @Operation(summary = "手动更新支付状态", description = "用于手动同步支付状态，通常用于异常情况处理")
    @PutMapping("/update-status")
    public ApiResult<?> updatePaymentStatus(@Valid @RequestBody PaymentStatusUpdateRequest request) {
        log.info("收到支付状态更新请求: {}", request);

        try {
            // 查询并更新支付状态
            PaymentResponse response = paymentService.queryPayment(
                request.getOrderNo(),
                PaymentType.WECHAT_NATIVE,
                request.getTenantId()
            );

            return this.<PaymentResponse>success("支付状态更新成功", response);
        } catch (Exception e) {
            log.error("更新支付状态失败: {}", e.getMessage(), e);
            return fail("更新支付状态失败: " + e.getMessage());
        }
    }

    @Operation(summary = "检查支付配置", description = "检查指定租户的支付配置是否完整")
    @GetMapping("/config/check")
    public ApiResult<?> checkPaymentConfig(
            @Parameter(description = "租户ID", required = true)
            @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {

        log.info("检查支付配置，租户ID: {}", tenantId);

        try {
            Map<String, Object> configStatus = paymentService.checkPaymentConfig(tenantId);
            return this.<Map<String, Object>>success("配置检查完成", configStatus);
        } catch (Exception e) {
            log.error("检查支付配置失败: {}", e.getMessage(), e);
            return fail("检查支付配置失败: " + e.getMessage());
        }
    }

    @Operation(summary = "查询用户最近的支付订单", description = "当orderNo缺失时，查询用户最近创建的支付订单")
    @GetMapping("/query-recent")
    public ApiResult<?> queryRecentPayment(
            @Parameter(description = "支付类型", required = true)
            @RequestParam @NotNull(message = "支付类型不能为空") PaymentType paymentType,

            @Parameter(description = "租户ID", required = true)
            @RequestParam @NotNull(message = "租户ID不能为空") @Positive(message = "租户ID必须为正数") Integer tenantId) {

        log.info("查询用户最近支付订单: paymentType={}, tenantId={}", paymentType, tenantId);

        final User loginUser = getLoginUser();
        if(loginUser == null){
            return fail("请先登录");
        }

        try {
            // 这里需要实现查询用户最近订单的逻辑
            // 可以通过用户ID和租户ID查询最近创建的订单
            return fail("此功能需要实现查询用户最近订单的业务逻辑");

        } catch (Exception e) {
            log.error("查询用户最近支付订单失败: {}", e.getMessage(), e);
            return fail("查询失败: " + e.getMessage());
        }
    }
}
