package trongrid

import (
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"hyapp/pkg/xerr"
	"hyapp/services/wallet-service/internal/config"
)

// Client 校验用户提交的 USDT-TRC20 tx_hash；它只读链上公开数据，不保存也不接触任何私钥。
type Client struct {
	httpClient      *http.Client
	apiBaseURL      string
	apiKey          string
	contractAddress string
}

// New 创建 TronGrid 兼容客户端；base_url 可以指向官方 TronGrid、自建节点代理或兼容网关。
func New(cfg config.TronGridConfig) *Client {
	timeout := cfg.HTTPTimeout
	if timeout <= 0 {
		timeout = 10 * time.Second
	}
	return &Client{
		httpClient:      &http.Client{Timeout: timeout},
		apiBaseURL:      strings.TrimRight(strings.TrimSpace(cfg.APIBaseURL), "/"),
		apiKey:          strings.TrimSpace(cfg.APIKey),
		contractAddress: strings.ToLower(strings.TrimSpace(cfg.USDTContractAddress)),
	}
}

// VerifyUSDTTransfer 校验 tx_hash 指向的 confirmed Transfer 是否把足额 USDT 打到平台共享地址。
func (c *Client) VerifyUSDTTransfer(ctx context.Context, txHash string, toAddress string, amountMinor int64) (string, error) {
	if c == nil || c.apiBaseURL == "" {
		return "", xerr.New(xerr.Unavailable, "tron grid client is not configured")
	}
	txHash = strings.TrimSpace(txHash)
	toAddress = strings.ToLower(strings.TrimSpace(toAddress))
	if txHash == "" || toAddress == "" || amountMinor <= 0 {
		return "", xerr.New(xerr.InvalidArgument, "usdt transfer verification request is incomplete")
	}
	// H5 商品金额以 USD cent 保存，USDT 使用 6 位小数；1 cent = 0.01 USDT = 10,000 atomic units。
	requiredAtomicAmount := amountMinor * 10_000
	events, rawJSON, err := c.listTransferEvents(ctx, txHash)
	if err != nil {
		return "", err
	}
	for _, event := range events {
		if !strings.EqualFold(event.EventName, "Transfer") {
			continue
		}
		if !c.contractMatches(event.ContractAddress) {
			continue
		}
		if strings.ToLower(strings.TrimSpace(event.Result.To)) != toAddress {
			continue
		}
		value, err := strconv.ParseInt(strings.TrimSpace(event.Result.Value), 10, 64)
		if err != nil || value < requiredAtomicAmount {
			continue
		}
		return rawJSON, nil
	}
	return rawJSON, xerr.New(xerr.Conflict, "usdt transfer is not confirmed or does not match order")
}

func (c *Client) listTransferEvents(ctx context.Context, txHash string) ([]transferEvent, string, error) {
	endpoint := c.apiBaseURL + "/v1/transactions/" + url.PathEscape(txHash) + "/events?event_name=Transfer&only_confirmed=true&limit=50"
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
	if err != nil {
		return nil, "", err
	}
	if c.apiKey != "" {
		req.Header.Set("TRON-PRO-API-KEY", c.apiKey)
	}
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, "", xerr.New(xerr.Unavailable, "tron grid request failed")
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(io.LimitReader(resp.Body, 2<<20))
	if err != nil {
		return nil, "", err
	}
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, string(body), xerr.New(xerr.Unavailable, "tron grid returned non-success")
	}
	var parsed struct {
		Data []transferEvent `json:"data"`
	}
	if err := json.Unmarshal(body, &parsed); err != nil {
		return nil, string(body), err
	}
	return parsed.Data, string(body), nil
}

func (c *Client) contractMatches(value string) bool {
	value = strings.ToLower(strings.TrimSpace(value))
	if value == "" || c.contractAddress == "" {
		return false
	}
	if value == c.contractAddress {
		return true
	}
	// TronGrid 的不同接口可能返回 base58 或 hex 合约地址；这里保留主网 USDT hex 兼容，避免官方返回格式差异导致误拒。
	return c.contractAddress == "tr7nhqjekqxgtci8q8zyk4pyl8otszgjlj6t" && value == "a614f803b6fd780986a42c78ec9c7f77e6ded13c"
}

type transferEvent struct {
	EventName       string `json:"event_name"`
	ContractAddress string `json:"contract_address"`
	Result          struct {
		To    string `json:"to"`
		Value string `json:"value"`
	} `json:"result"`
}
