package com.gxwebsoft.payment.dto;

import com.gxwebsoft.payment.enums.PaymentChannel;
import com.gxwebsoft.payment.enums.PaymentType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Map;

/**
 * 统一支付请求DTO
 * 支持所有支付方式的统一请求格式
 *
 * @author 科技小王子
 * @since 2025-01-26
 */
@Data
@Schema(name = "统一支付请求", description = "支持所有支付方式的统一支付请求参数")
public class PaymentRequest {

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

    @Schema(description = "用户ID", required = true)
    @NotNull(message = "用户ID不能为空")
    @Positive(message = "用户ID必须为正数")
    private Integer userId;

    @Schema(description = "支付类型", required = true, example = "WECHAT_NATIVE")
    @NotNull(message = "支付类型不能为空")
    private PaymentType paymentType;

    @Schema(description = "支付渠道", example = "wechat_native")
    private PaymentChannel paymentChannel;

    @Schema(description = "支付金额", required = true, example = "0.01")
    @NotNull(message = "支付金额不能为空")
    @DecimalMin(value = "0.01", message = "支付金额必须大于0.01元")
    @DecimalMax(value = "999999.99", message = "支付金额不能超过999999.99元")
    @Digits(integer = 6, fraction = 2, message = "支付金额格式不正确，最多6位整数2位小数")
    private BigDecimal amount;

    @Schema(description = "订单号（可选，不提供则自动生成）")
    @Size(max = 32, message = "订单号不能超过32个字符")
    @Pattern(regexp = "^[a-zA-Z0-9_-]*$", message = "订单号只能包含字母、数字、下划线和横线")
    private String orderNo;

    @Schema(description = "订单标题", required = true)
    @NotBlank(message = "订单标题不能为空")
    @Size(max = 127, message = "订单标题不能超过127个字符")
    private String subject;

    @Schema(description = "订单描述")
    @Size(max = 500, message = "订单描述不能超过500个字符")
    private String description;

    @Schema(description = "商品ID")
    @Positive(message = "商品ID必须为正数")
    private Integer goodsId;

    @Schema(description = "购买数量", example = "1")
    @Min(value = 1, message = "购买数量必须大于0")
    @Max(value = 9999, message = "购买数量不能超过9999")
    private Integer quantity = 1;

    @Schema(description = "订单类型", example = "0")
    @Min(value = 0, message = "订单类型不能为负数")
    private Integer orderType = 0;

    @Schema(description = "客户端IP地址")
    private String clientIp;

    @Schema(description = "用户代理")
    private String userAgent;

    @Schema(description = "回调通知URL")
    private String notifyUrl;

    @Schema(description = "支付成功跳转URL")
    private String returnUrl;

    @Schema(description = "支付取消跳转URL")
    private String cancelUrl;

    @Schema(description = "订单超时时间（分钟）", example = "30")
    @Min(value = 1, message = "订单超时时间必须大于0分钟")
    @Max(value = 1440, message = "订单超时时间不能超过1440分钟（24小时）")
    private Integer timeoutMinutes = 30;

    @Schema(description = "买家备注")
    @Size(max = 500, message = "买家备注不能超过500个字符")
    private String buyerRemarks;

    @Schema(description = "商户备注")
    @Size(max = 500, message = "商户备注不能超过500个字符")
    private String merchantRemarks;

    @Schema(description = "收货地址ID")
    @Positive(message = "收货地址ID必须为正数")
    private Integer addressId;

    @Schema(description = "扩展参数")
    private Map<String, Object> extraParams;

    // 微信支付特有参数
    @Schema(description = "微信OpenID（JSAPI支付必填）")
    private String openId;

    @Schema(description = "微信UnionID")
    private String unionId;

    // 支付宝特有参数
    @Schema(description = "支付宝用户ID")
    private String alipayUserId;

    @Schema(description = "花呗分期数")
    private Integer hbFqNum;

    // 银联支付特有参数
    @Schema(description = "银行卡号")
    private String cardNo;

    @Schema(description = "银行代码")
    private String bankCode;

    /**
     * 获取有效的支付渠道
     */
    public PaymentChannel getEffectivePaymentChannel() {
        if (paymentChannel != null) {
            return paymentChannel;
        }
        return PaymentChannel.getDefaultByPaymentType(paymentType);
    }

    /**
     * 获取有效的订单描述
     */
    public String getEffectiveDescription() {
        if (description != null && !description.trim().isEmpty()) {
            return description.trim();
        }
        return subject;
    }

    /**
     * 获取格式化的金额字符串
     */
    public String getFormattedAmount() {
        if (amount == null) {
            return "0.00";
        }
        return String.format("%.2f", amount);
    }

    /**
     * 转换为分（微信支付API需要）
     */
    public Integer getAmountInCents() {
        if (amount == null) {
            return 0;
        }
        return amount.multiply(new BigDecimal(100)).intValue();
    }

    /**
     * 验证必要参数是否完整
     */
    public boolean isValid() {
        return tenantId != null && tenantId > 0
            && userId != null && userId > 0
            && paymentType != null
            && amount != null && amount.compareTo(BigDecimal.ZERO) > 0
            && subject != null && !subject.trim().isEmpty();
    }

    /**
     * 验证微信JSAPI支付参数
     */
    public boolean isValidForWechatJsapi() {
        return isValid() && paymentType.isWechatPay() && openId != null && !openId.trim().isEmpty();
    }

    /**
     * 验证支付宝支付参数
     */
    public boolean isValidForAlipay() {
        return isValid() && paymentType == PaymentType.ALIPAY;
    }

    /**
     * 获取订单超时时间（秒）
     */
    public long getTimeoutSeconds() {
        return timeoutMinutes * 60L;
    }

    @Override
    public String toString() {
        return String.format("PaymentRequest{tenantId=%d, userId=%d, paymentType=%s, amount=%s, orderNo='%s', subject='%s'}",
            tenantId, userId, paymentType, getFormattedAmount(), orderNo, subject);
    }
}
