package service

import (
	"context"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"sim-server/app/main/api/internal/config"
	"sim-server/app/main/model"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/zeromicro/go-zero/core/logx"
)

// EasyPayService 易支付服务
type EasyPayService struct {
	config     config.EasyPayConfig
	client     *http.Client
	orderModel model.OrderModel // 订单模型，用于次数轮询模式查询用户订单数量
}

// getSelectedCID 获取当前应该使用的渠道ID
// ctx: 上下文，用于次数轮询模式时访问Redis
// userID: 用户ID，用于次数轮询模式时记录用户使用的渠道
func (e *EasyPayService) getSelectedCID(ctx context.Context, userID string) string {
	// 如果没有配置 CID，返回空字符串
	if len(e.config.CIDs) == 0 {
		return ""
	}

	// 如果只有一个渠道，直接返回
	if len(e.config.CIDs) == 1 {
		return e.config.CIDs[0]
	}

	// 根据轮询模式选择策略
	rotateMode := e.config.RotateMode
	if rotateMode == "" {
		rotateMode = "day" // 默认天数轮询
	}

	switch rotateMode {
	case "count":
		// 次数轮询模式：按用户订单次数轮询
		return e.selectCIDByCount(ctx, userID)
	case "day":
		// 天数轮询模式：按时间轮询
		return e.selectCIDByRotation()
	default:
		// 默认使用天数轮询
		logx.Infof("未知的轮询模式: %s，使用默认天数轮询", rotateMode)
		return e.selectCIDByRotation()
	}
}

// selectCIDByRotation 按时间轮询策略选择CID
func (e *EasyPayService) selectCIDByRotation() string {
	if len(e.config.CIDs) == 0 {
		return ""
	}

	// 如果只有一个，直接返回
	if len(e.config.CIDs) == 1 {
		return e.config.CIDs[0]
	}

	// 获取轮询天数，默认3天
	rotateDays := e.config.RotateDays
	if rotateDays <= 0 {
		rotateDays = 3
	}

	// 计算从某个基准日期（比如2020-01-01）开始的天数
	baseDate := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
	now := time.Now()
	daysSinceBase := int(now.Sub(baseDate).Hours() / 24)

	// 按轮询天数计算当前应该使用的索引
	rotationIndex := (daysSinceBase / rotateDays) % len(e.config.CIDs)

	selectedCID := e.config.CIDs[rotationIndex]
	logx.Infof("易支付渠道天数轮询选择: 总渠道数=%d, 轮询天数=%d, 当前索引=%d, 选择渠道=%s",
		len(e.config.CIDs), rotateDays, rotationIndex, selectedCID)

	return selectedCID
}

// selectCIDByCount 按次数轮询策略选择CID（针对用户）
func (e *EasyPayService) selectCIDByCount(ctx context.Context, userID string) string {
	if len(e.config.CIDs) == 0 {
		return ""
	}

	// 如果只有一个，直接返回
	if len(e.config.CIDs) == 1 {
		return e.config.CIDs[0]
	}

	// 如果没有用户ID，回退到天数轮询
	if userID == "" {
		logx.Infof("次数轮询模式但用户ID为空，回退到天数轮询")
		return e.selectCIDByRotation()
	}

	// 查询该用户的易支付订单数量
	orderCount := int64(0)
	if e.orderModel != nil {
		builder := e.orderModel.SelectBuilder().
			Where("user_id = ?", userID).
			Where("payment_platform = ?", "easypay_alipay")
		count, err := e.orderModel.FindCount(ctx, builder, "id")
		if err != nil {
			logx.Errorf("查询用户易支付订单数量失败: %v，使用索引0", err)
		} else {
			orderCount = count
		}
	}

	// 根据订单数量计算应该使用的渠道索引（订单数量从0开始，所以第0个订单用索引0，第1个订单用索引1，以此类推）
	channelIndex := int(orderCount) % len(e.config.CIDs)
	selectedCID := e.config.CIDs[channelIndex]

	logx.Infof("易支付渠道次数轮询选择: 用户ID=%s, 总渠道数=%d, 用户订单数=%d, 选择索引=%d, 选择渠道=%s",
		userID, len(e.config.CIDs), orderCount, channelIndex, selectedCID)

	return selectedCID
}

// NewEasyPayService 创建易支付服务实例
func NewEasyPayService(c config.Config, orderModel model.OrderModel) *EasyPayService {
	return &EasyPayService{
		config: c.EasyPay,
		client: &http.Client{
			Timeout: 30 * time.Second,
		},
		orderModel: orderModel,
	}
}

// EasyPayOrderResponse API接口支付响应
type EasyPayOrderResponse struct {
	Code    interface{} `json:"code"` // 可能是 int 或 string
	Msg     string      `json:"msg"`
	TradeNo string      `json:"trade_no,omitempty"`
	OId     string      `json:"O_id,omitempty"`
	PayUrl  string      `json:"payurl,omitempty"`
	Qrcode  string      `json:"qrcode,omitempty"`
	Img     string      `json:"img,omitempty"`
}

// GetCodeInt 获取 code 的 int 值
func (r *EasyPayOrderResponse) GetCodeInt() int {
	switch v := r.Code.(type) {
	case int:
		return v
	case float64:
		return int(v)
	case string:
		if v == "1" || v == "error" {
			if v == "1" {
				return 1
			}
			return 0
		}
		return 0
	default:
		return 0
	}
}

// EasyPayQueryResponse 查询订单响应
type EasyPayQueryResponse struct {
	Code       interface{} `json:"code"` // 可能是 int 或 string
	Msg        string      `json:"msg"`
	TradeNo    string      `json:"trade_no,omitempty"`
	OutTradeNo string      `json:"out_trade_no,omitempty"`
	Type       string      `json:"type,omitempty"`
	Pid        string      `json:"pid,omitempty"`
	Addtime    string      `json:"addtime,omitempty"`
	Endtime    string      `json:"endtime,omitempty"`
	Name       string      `json:"name,omitempty"`
	Money      string      `json:"money,omitempty"`
	Status     interface{} `json:"status,omitempty"` // 可能是 int 或 string
	Param      string      `json:"param,omitempty"`
	Buyer      string      `json:"buyer,omitempty"`
}

// GetCodeInt 获取 code 的 int 值
func (r *EasyPayQueryResponse) GetCodeInt() int {
	switch v := r.Code.(type) {
	case int:
		return v
	case float64:
		return int(v)
	case string:
		if v == "1" {
			return 1
		}
		return 0
	default:
		return 0
	}
}

// GetStatusInt 获取 status 的 int 值
func (r *EasyPayQueryResponse) GetStatusInt() int {
	switch v := r.Status.(type) {
	case int:
		return v
	case float64:
		return int(v)
	case string:
		if v == "1" {
			return 1
		}
		return 0
	default:
		return 0
	}
}

// EasyPayRefundResponse 退款响应
type EasyPayRefundResponse struct {
	Code interface{} `json:"code"` // 可能是 int 或 string
	Msg  string      `json:"msg"`
}

// GetCodeInt 获取 code 的 int 值
func (r *EasyPayRefundResponse) GetCodeInt() int {
	switch v := r.Code.(type) {
	case int:
		return v
	case float64:
		return int(v)
	case string:
		if v == "1" {
			return 1
		}
		return 0
	default:
		return 0
	}
}

// EasyPayNotification 支付回调通知
type EasyPayNotification struct {
	Pid         string
	Name        string
	Money       string
	OutTradeNo  string
	TradeNo     string
	Param       string
	TradeStatus string
	Type        string
	Sign        string
	SignType    string
}

// generateSign 生成MD5签名
func (e *EasyPayService) generateSign(params map[string]string) string {
	// 排除 sign、sign_type 和空值
	filteredParams := make(map[string]string)
	for k, v := range params {
		if k != "sign" && k != "sign_type" && v != "" {
			filteredParams[k] = v
		}
	}

	// 按参数名ASCII码从小到大排序
	keys := make([]string, 0, len(filteredParams))
	for k := range filteredParams {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// 拼接成URL键值对格式
	var parts []string
	for _, k := range keys {
		parts = append(parts, fmt.Sprintf("%s=%s", k, filteredParams[k]))
	}
	queryString := strings.Join(parts, "&")

	// 拼接商户密钥并MD5加密
	signString := queryString + e.config.PKEY
	hash := md5.Sum([]byte(signString))
	return fmt.Sprintf("%x", hash) // 转为小写
}

// verifySign 验证签名
func (e *EasyPayService) verifySign(params map[string]string, sign string) bool {
	calculatedSign := e.generateSign(params)
	return strings.EqualFold(calculatedSign, sign)
}

// CreateEasyPayH5Order 创建易支付H5订单（页面跳转方式）
func (e *EasyPayService) CreateEasyPayH5Order(ctx context.Context, amount float64, subject string, outTradeNo string, userID string) (string, error) {
	// 格式化金额，保留两位小数
	moneyStr := fmt.Sprintf("%.2f", amount)

	params := map[string]string{
		"name":         subject,
		"money":        moneyStr,
		"type":         "alipay",
		"out_trade_no": outTradeNo,
		"notify_url":   e.config.NotifyUrl,
		"pid":          e.config.PID,
		"return_url":   e.config.ReturnUrl,
		"sign_type":    "MD5",
	}
	// 获取并添加渠道ID
	if cid := e.getSelectedCID(ctx, userID); cid != "" {
		params["cid"] = cid
	}

	// 生成签名
	sign := e.generateSign(params)
	params["sign"] = sign

	// 构建支付URL
	baseURL := strings.TrimSuffix(e.config.ApiURL, "/")
	payURL := fmt.Sprintf("%s/submit.php", baseURL)

	// 构建查询字符串
	values := url.Values{}
	for k, v := range params {
		values.Set(k, v)
	}

	return fmt.Sprintf("%s?%s", payURL, values.Encode()), nil
}

// CreateEasyPayAppOrder 创建易支付APP订单（API方式）
func (e *EasyPayService) CreateEasyPayAppOrder(ctx context.Context, amount float64, subject string, outTradeNo string, clientIP string, userID string) (string, error) {
	// 格式化金额，保留两位小数
	moneyStr := fmt.Sprintf("%.2f", amount)

	params := map[string]string{
		"pid":          e.config.PID,
		"type":         "alipay",
		"out_trade_no": outTradeNo,
		"notify_url":   e.config.NotifyUrl,
		"name":         subject,
		"money":        moneyStr,
		"clientip":     clientIP,
		"device":       "pc",
		"sign_type":    "MD5",
	}
	// 获取并添加渠道ID
	if cid := e.getSelectedCID(ctx, userID); cid != "" {
		params["cid"] = cid
	}

	// 生成签名
	sign := e.generateSign(params)
	params["sign"] = sign

	// 构建请求URL
	baseURL := strings.TrimSuffix(e.config.ApiURL, "/")
	apiURL := fmt.Sprintf("%s/mapi.php", baseURL)

	// 构建form-data请求
	values := url.Values{}
	for k, v := range params {
		values.Set(k, v)
	}

	// 发送POST请求
	req, err := http.NewRequestWithContext(ctx, "POST", apiURL, strings.NewReader(values.Encode()))
	if err != nil {
		return "", fmt.Errorf("创建请求失败: %v", err)
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := e.client.Do(req)
	if err != nil {
		return "", fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取响应失败: %v", err)
	}

	var orderResp EasyPayOrderResponse
	if err := json.Unmarshal(body, &orderResp); err != nil {
		return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
	}

	if orderResp.GetCodeInt() != 1 {
		return "", fmt.Errorf("创建订单失败: %s", orderResp.Msg)
	}

	// 优先返回支付URL，如果没有则返回二维码
	if orderResp.PayUrl != "" {
		return orderResp.PayUrl, nil
	}
	if orderResp.Qrcode != "" {
		return orderResp.Qrcode, nil
	}
	if orderResp.Img != "" {
		return orderResp.Img, nil
	}

	return "", fmt.Errorf("未获取到支付链接")
}

// CreateEasyPayOrderResult 易支付订单创建结果
type CreateEasyPayOrderResult struct {
	PayURL string // 支付URL
	CID    string // 使用的渠道ID
}

// CreateEasyPayOrder 根据平台类型创建易支付订单
func (e *EasyPayService) CreateEasyPayOrder(ctx context.Context, amount float64, subject string, outTradeNo string, userID string) (*CreateEasyPayOrderResult, error) {
	// 获取选中的渠道ID
	selectedCID := e.getSelectedCID(ctx, userID)

	// 根据 ctx 中的 platform 判断平台
	platform, platformOk := ctx.Value("platform").(string)
	if !platformOk {
		return nil, fmt.Errorf("无效的支付平台")
	}

	var payURL string
	var err error
	switch platform {
	case model.PlatformApp:
		// APP平台使用API方式
		clientIP := ""
		if ip, ok := ctx.Value("client_ip").(string); ok {
			clientIP = ip
		}
		payURL, err = e.CreateEasyPayAppOrder(ctx, amount, subject, outTradeNo, clientIP, userID)
	case model.PlatformH5:
		// H5平台使用页面跳转方式
		payURL, err = e.CreateEasyPayH5Order(ctx, amount, subject, outTradeNo, userID)
	default:
		return nil, fmt.Errorf("不支持的支付平台: %s", platform)
	}

	if err != nil {
		return nil, err
	}

	return &CreateEasyPayOrderResult{
		PayURL: payURL,
		CID:    selectedCID,
	}, nil
}

// HandleEasyPayNotification 处理易支付回调通知
func (e *EasyPayService) HandleEasyPayNotification(r *http.Request) (*EasyPayNotification, error) {
	// 解析GET参数
	params := make(map[string]string)
	for k, v := range r.URL.Query() {
		if len(v) > 0 {
			params[k] = v[0]
		}
	}

	// 获取签名
	sign, ok := params["sign"]
	if !ok {
		return nil, fmt.Errorf("缺少签名参数")
	}

	// 验证签名
	if !e.verifySign(params, sign) {
		return nil, fmt.Errorf("签名验证失败")
	}

	// 构建通知对象
	notification := &EasyPayNotification{
		Pid:         params["pid"],
		Name:        params["name"],
		Money:       params["money"],
		OutTradeNo:  params["out_trade_no"],
		TradeNo:     params["trade_no"],
		Param:       params["param"],
		TradeStatus: params["trade_status"],
		Type:        params["type"],
		Sign:        sign,
		SignType:    params["sign_type"],
	}

	return notification, nil
}

// QueryOrderStatus 查询订单状态
func (e *EasyPayService) QueryOrderStatus(ctx context.Context, outTradeNo string) (*EasyPayQueryResponse, error) {
	// 构建查询URL
	baseURL := strings.TrimSuffix(e.config.ApiURL, "/")
	queryURL := fmt.Sprintf("%s/api.php?act=order&pid=%s&key=%s&out_trade_no=%s",
		baseURL, e.config.PID, e.config.PKEY, url.QueryEscape(outTradeNo))

	req, err := http.NewRequestWithContext(ctx, "GET", queryURL, nil)
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %v", err)
	}

	resp, err := e.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err)
	}

	var queryResp EasyPayQueryResponse
	if err := json.Unmarshal(body, &queryResp); err != nil {
		return nil, fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
	}

	if queryResp.GetCodeInt() != 1 {
		return nil, fmt.Errorf("查询订单失败: %s", queryResp.Msg)
	}

	return &queryResp, nil
}

// Refund 申请退款
func (e *EasyPayService) Refund(ctx context.Context, outTradeNo string, refundAmount float64) error {
	// 格式化金额，保留两位小数
	moneyStr := fmt.Sprintf("%.2f", refundAmount)

	params := map[string]string{
		"pid":          e.config.PID,
		"key":          e.config.PKEY,
		"out_trade_no": outTradeNo,
		"money":        moneyStr,
	}

	// 构建请求URL
	baseURL := strings.TrimSuffix(e.config.ApiURL, "/")
	refundURL := fmt.Sprintf("%s/api.php?act=refund", baseURL)

	// 构建form-data请求
	values := url.Values{}
	for k, v := range params {
		values.Set(k, v)
	}

	// 发送POST请求
	req, err := http.NewRequestWithContext(ctx, "POST", refundURL, strings.NewReader(values.Encode()))
	if err != nil {
		return fmt.Errorf("创建请求失败: %v", err)
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := e.client.Do(req)
	if err != nil {
		return fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("读取响应失败: %v", err)
	}

	var refundResp EasyPayRefundResponse
	if err := json.Unmarshal(body, &refundResp); err != nil {
		return fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
	}

	if refundResp.GetCodeInt() != 1 {
		return fmt.Errorf("退款失败: %s", refundResp.Msg)
	}

	logx.Infof("易支付退款成功，订单号: %s, 退款金额: %s", outTradeNo, moneyStr)
	return nil
}

// IsPaymentSuccess 判断支付是否成功
func (e *EasyPayService) IsPaymentSuccess(notification *EasyPayNotification) bool {
	return notification.TradeStatus == "TRADE_SUCCESS"
}
