package payment

import (
	"encoding/json"
	"fmt"
	"strconv"

	"verification-platform-backend/internal/model"
)

type PaymentResult struct {
	OrderID        string
	TradeID        string
	PaymentURL     string
	ActualAmount   string
	Token          string
	ExpirationTime int
}

type PaymentService interface {
	CreateOrder(orderID string, amount float64, notifyURL, redirectURL, name string) (*PaymentResult, error)
	VerifyCallback(data interface{}) bool
}

func GetPaymentService(channel model.PaymentChannel, callbackBaseURL string) (PaymentService, error) {
	switch channel.Type {
	case "bepusdt":
		config, err := parseBEpusdtConfig(channel.Config)
		if err != nil {
			return nil, fmt.Errorf("parse bepusdt config: %w", err)
		}
		return NewBEpusdtAdapter(config, callbackBaseURL), nil
	default:
		return nil, fmt.Errorf("unsupported payment type: %s", channel.Type)
	}
}

func parseBEpusdtConfig(configStr string) (BEpusdtConfig, error) {
	var config BEpusdtConfig
	if err := json.Unmarshal([]byte(configStr), &config); err != nil {
		return config, fmt.Errorf("invalid config format: %w", err)
	}

	if config.ApiURL == "" {
		return config, fmt.Errorf("api_url is required")
	}
	if config.ApiToken == "" {
		return config, fmt.Errorf("api_token is required")
	}
	if config.TradeType == "" {
		config.TradeType = "usdt.trc20"
	}

	return config, nil
}

func interfaceToString(v interface{}) string {
	switch val := v.(type) {
	case string:
		return val
	case float64:
		return strconv.FormatFloat(val, 'f', -1, 64)
	case int:
		return strconv.Itoa(val)
	default:
		return fmt.Sprintf("%v", val)
	}
}

type BEpusdtAdapter struct {
	client          *BEpusdtClient
	callbackBaseURL string
}

func NewBEpusdtAdapter(config BEpusdtConfig, callbackBaseURL string) *BEpusdtAdapter {
	return &BEpusdtAdapter{
		client:          NewBEpusdtClient(config),
		callbackBaseURL: callbackBaseURL,
	}
}

func (a *BEpusdtAdapter) CreateOrder(orderID string, amount float64, notifyURL, redirectURL, name string) (*PaymentResult, error) {
	resp, err := a.client.CreateTransaction(orderID, amount, notifyURL, redirectURL, name)
	if err != nil {
		return nil, err
	}

	return &PaymentResult{
		OrderID:        resp.Data.OrderID,
		TradeID:        resp.Data.TradeID,
		PaymentURL:     resp.Data.PaymentURL,
		ActualAmount:   interfaceToString(resp.Data.ActualAmount),
		Token:          resp.Data.Token,
		ExpirationTime: resp.Data.ExpirationTime,
	}, nil
}

func (a *BEpusdtAdapter) VerifyCallback(data interface{}) bool {
	switch v := data.(type) {
	case CallbackData:
		return a.client.VerifyCallback(v)
	default:
		return false
	}
}
