package tinydatapay

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"
)

// Client TinyDataPay客户端
type Client struct {
	APIURL  string
	SafeKey string
	Debug   bool
}

// NewClient 创建客户端
func NewClient(apiURL, safeKey string) *Client {
	return &Client{
		APIURL:  strings.TrimRight(apiURL, "/"),
		SafeKey: safeKey,
		Debug:   false,
	}
}

// OrderRequest 创建订单请求
type OrderRequest struct {
	MerchantOrderID string `json:"merchant_order_id"` // 商户订单号
	Amount          string `json:"amount"`            // 金额
	Currency        string `json:"currency"`          // 货币类型
	ProductName     string `json:"product_name"`      // 商品名称
	NotifyURL       string `json:"notify_url"`        // 异步通知URL
	RedirectURL     string `json:"redirect_url"`      // 同步跳转URL
}

// OrderResponse 订单响应
type OrderResponse struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    struct {
		OrderNo    string `json:"order_no"`
		Amount     string `json:"amount"`
		PaymentURL string `json:"payment_url"`
	} `json:"data"`
}

// OrderStatusResponse 订单状态响应
type OrderStatusResponse struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    struct {
		OrderNo       string `json:"order_no"`
		Amount        string `json:"amount"`
		Status        string `json:"status"`
		PayType       string `json:"pay_type"`
		Confirmations int    `json:"confirmations,omitempty"`
	} `json:"data"`
}

// CallbackData 回调数据
type CallbackData struct {
	OrderNo         string `json:"order_no"`
	MerchantOrderID string `json:"merchant_order_id"`
	Amount          string `json:"amount"`
	Status          string `json:"status"`
	PayType         string `json:"pay_type"`
	Sign            string `json:"sign"`
}

// GenerateSign 生成MD5签名
func (c *Client) GenerateSign(params map[string]string) string {
	// 1. 过滤空值并排序
	keys := make([]string, 0, len(params))
	for k, v := range params {
		if k != "sign" && v != "" {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)

	// 2. 拼接参数
	var signStr strings.Builder
	for _, k := range keys {
		signStr.WriteString(k)
		signStr.WriteString("=")
		signStr.WriteString(params[k])
		signStr.WriteString("&")
	}
	signStr.WriteString("key=")
	signStr.WriteString(c.SafeKey)

	// 3. MD5加密并转大写
	hash := md5.Sum([]byte(signStr.String()))
	return strings.ToUpper(hex.EncodeToString(hash[:]))
}

// VerifySign 验证签名
func (c *Client) VerifySign(params map[string]string) bool {
	receivedSign, exists := params["sign"]
	if !exists {
		return false
	}

	expectedSign := c.GenerateSign(params)
	return receivedSign == expectedSign
}

// CreateOrder 创建订单
func (c *Client) CreateOrder(req *OrderRequest) (*OrderResponse, error) {
	// 构建参数
	params := map[string]string{
		"merchant_order_id": req.MerchantOrderID,
		"amount":            req.Amount,
		"currency":          req.Currency,
		"product_name":      req.ProductName,
	}

	if req.NotifyURL != "" {
		params["notify_url"] = req.NotifyURL
	}
	if req.RedirectURL != "" {
		params["redirect_url"] = req.RedirectURL
	}

	// 生成签名
	params["sign"] = c.GenerateSign(params)

	if c.Debug {
		fmt.Printf("[TinyDataPay] 创建订单: %+v\n", params)
	}

	// 发送请求
	jsonData, err := json.Marshal(params)
	if err != nil {
		return nil, fmt.Errorf("序列化失败: %w", err)
	}

	resp, err := http.Post(
		c.APIURL+"/api/v1/payment/create",
		"application/json",
		strings.NewReader(string(jsonData)),
	)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %w", err)
	}
	defer resp.Body.Close()

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

	var result OrderResponse
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, fmt.Errorf("解析响应失败: %w", err)
	}

	if result.Code != 0 {
		return nil, fmt.Errorf("创建订单失败: %s", result.Message)
	}

	return &result, nil
}

// QueryOrder 查询订单
func (c *Client) QueryOrder(orderNo string) (*OrderStatusResponse, error) {
	apiURL := fmt.Sprintf("%s/api/v1/payment/status?order_no=%s", c.APIURL, url.QueryEscape(orderNo))

	resp, err := http.Get(apiURL)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %w", err)
	}
	defer resp.Body.Close()

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

	var result OrderStatusResponse
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, fmt.Errorf("解析响应失败: %w", err)
	}

	if result.Code != 0 {
		return nil, fmt.Errorf("查询失败: %s", result.Message)
	}

	return &result, nil
}

// PollOrderStatus 轮询订单状态直到支付完成
func (c *Client) PollOrderStatus(orderNo string, timeout time.Duration, callback func(status string)) error {
	deadline := time.Now().Add(timeout)

	for time.Now().Before(deadline) {
		result, err := c.QueryOrder(orderNo)
		if err != nil {
			return err
		}

		status := result.Data.Status
		if callback != nil {
			callback(status)
		}

		// 检查状态
		if status == "paid" {
			return nil
		}

		if status == "expired" || status == "failed" {
			return fmt.Errorf("订单状态异常: %s", status)
		}

		// 等待3秒后继续查询
		time.Sleep(3 * time.Second)
	}

	return fmt.Errorf("查询超时")
}

// ParseCallback 解析回调数据（从URL参数或JSON）
func (c *Client) ParseCallback(r *http.Request) (*CallbackData, error) {
	params := make(map[string]string)

	// 优先尝试GET参数
	for key, values := range r.URL.Query() {
		if len(values) > 0 {
			params[key] = values[0]
		}
	}

	// 如果没有GET参数，尝试POST JSON
	if len(params) == 0 {
		var data CallbackData
		if err := json.NewDecoder(r.Body).Decode(&data); err == nil {
			params["order_no"] = data.OrderNo
			params["merchant_order_id"] = data.MerchantOrderID
			params["amount"] = data.Amount
			params["status"] = data.Status
			params["pay_type"] = data.PayType
			params["sign"] = data.Sign
		}
	}

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

	return &CallbackData{
		OrderNo:         params["order_no"],
		MerchantOrderID: params["merchant_order_id"],
		Amount:          params["amount"],
		Status:          params["status"],
		PayType:         params["pay_type"],
		Sign:            params["sign"],
	}, nil
}

// HandleCallback 处理回调（HTTP Handler）
func (c *Client) HandleCallback(handler func(*CallbackData) error) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		data, err := c.ParseCallback(r)
		if err != nil {
			if c.Debug {
				fmt.Printf("[TinyDataPay] 回调验证失败: %v\n", err)
			}
			w.Write([]byte("fail"))
			return
		}

		// 调用用户处理函数
		if err := handler(data); err != nil {
			if c.Debug {
				fmt.Printf("[TinyDataPay] 回调处理失败: %v\n", err)
			}
			w.Write([]byte("fail"))
			return
		}

		w.Write([]byte("success"))
	}
}
