package bitgetservice

import (
	"fmt"
	"go-admin/common/global"
	"go-admin/common/helper"
	"go-admin/config"
	"go-admin/models"
	"go-admin/pkg/utility"
	"strconv"
	"strings"

	"github.com/bytedance/sonic"
	log "github.com/go-admin-team/go-admin-core/logger"
)

// BitgetRestApi Bitget REST API服务
type BitgetRestApi struct {
	httpClient *helper.BitgetClient
}

// NewBitgetRestApi 创建新的Bitget REST API实例
func NewBitgetRestApi() *BitgetRestApi {
	// 从配置中获取代理设置
	proxyUrl := config.ExtConfig.ProxyUrl

	// 使用代理配置创建HTTP客户端
	httpClient, err := helper.NewBitgetClient("", "", "", proxyUrl)
	if err != nil {
		log.Error("创建Bitget HTTP客户端失败", err)
		// 如果代理创建失败，使用无代理的客户端
		httpClient, _ = helper.NewBitgetClient("", "", "", "")
	}

	return &BitgetRestApi{
		httpClient: httpClient,
	}
}

// NewBitgetSimpleClient 创建简单的Bitget客户端（兼容性函数）
func NewBitgetSimpleClient() *BitgetClient {
	// 从配置中获取代理设置
	proxyUrl := config.ExtConfig.ProxyUrl

	client, err := NewBitgetClient("", "", "", proxyUrl)
	if err != nil {
		log.Error("创建Bitget简单客户端失败", err)
		// 如果代理创建失败，使用无代理的客户端
		client, _ = NewBitgetClient("", "", "", "")
	}
	return client
}

// bitgetSymbolResponse 通用的符号响应结构体
type bitgetSymbolResponse struct {
	Code string `json:"code"`
	Msg  string `json:"msg"`
	Data []struct {
		Symbol            string `json:"symbol"`
		BaseCoin          string `json:"baseCoin"`
		QuoteCoin         string `json:"quoteCoin"`
		Status            string `json:"status"`
		MinTradeAmount    string `json:"minTradeAmount"`
		MaxTradeAmount    string `json:"maxTradeAmount"`
		TakerFeeRate      string `json:"takerFeeRate"`
		MakerFeeRate      string `json:"makerFeeRate"`
		PricePrecision    string `json:"pricePrecision"`
		QuantityPrecision string `json:"quantityPrecision"`
	} `json:"data"`
}

// getSymbolsFromAPI 通用的符号获取方法
// symbolType: "spot" 现货, "futures" 合约
func (api *BitgetRestApi) getSymbolsFromAPI(symbolType string) ([]BitgetSymbol, error) {
	var url string
	var errorPrefix string

	switch symbolType {
	case "spot":
		url = "/api/v2/spot/public/symbols"
		errorPrefix = "现货"
	case "futures":
		url = "/api/v2/mix/market/contracts?productType=USDT-FUTURES"
		errorPrefix = "合约"
	default:
		return nil, fmt.Errorf("不支持的符号类型: %s", symbolType)
	}

	// 发送API请求
	resp, _, err := api.httpClient.SendSpotRequestAuth(url, "GET", map[string]interface{}{})
	if err != nil {
		return nil, fmt.Errorf("获取bitget %s交易所信息失败: %v", errorPrefix, err)
	}

	// 解析响应数据
	var response bitgetSymbolResponse
	if err := sonic.Unmarshal(resp, &response); err != nil {
		return nil, fmt.Errorf("解析bitget %s交易所信息失败: %v", errorPrefix, err)
	}

	// 检查API响应状态
	if response.Code != "00000" {
		return nil, fmt.Errorf("bitget API错误: %s", response.Msg)
	}

	// 转换数据格式
	return api.convertToSymbols(response.Data), nil
}

// convertToSymbols 将API响应数据转换为BitgetSymbol切片
func (api *BitgetRestApi) convertToSymbols(data []struct {
	Symbol            string `json:"symbol"`
	BaseCoin          string `json:"baseCoin"`
	QuoteCoin         string `json:"quoteCoin"`
	Status            string `json:"status"`
	MinTradeAmount    string `json:"minTradeAmount"`
	MaxTradeAmount    string `json:"maxTradeAmount"`
	TakerFeeRate      string `json:"takerFeeRate"`
	MakerFeeRate      string `json:"makerFeeRate"`
	PricePrecision    string `json:"pricePrecision"`
	QuantityPrecision string `json:"quantityPrecision"`
}) []BitgetSymbol {
	symbols := make([]BitgetSymbol, 0, len(data))
	
	for _, item := range data {
		if item.Status == "online" {
			priceDigit, _ := strconv.Atoi(item.PricePrecision)
			quantileDigit, _ := strconv.Atoi(item.QuantityPrecision)

			symbol := BitgetSymbol{
				Symbol:        item.Symbol,
				BaseAsset:     item.BaseCoin,
				QuoteAsset:    item.QuoteCoin,
				Status:        item.Status,
				MinQty:        item.MinTradeAmount,
				MaxQty:        item.MaxTradeAmount,
				PriceDigit:    priceDigit,
				QuantityDigit: quantileDigit,
			}
			symbols = append(symbols, symbol)
		}
	}
	
	return symbols
}

// GetSpotSymbols 获取现货交易对信息
func (api *BitgetRestApi) GetSpotSymbols() ([]BitgetSymbol, error) {
	return api.getSymbolsFromAPI("spot")
}

// GetFutSymbols 获取合约交易对信息
func (api *BitgetRestApi) GetFutSymbols() ([]BitgetSymbol, error) {
	return api.getSymbolsFromAPI("futures")
}

// symbolConfig 符号配置结构体
type symbolConfig struct {
	symbolType        string
	quoteAssetSymbols []string
}

// buildTradeSetFromSymbols 通用的TradeSet构建方法
func buildTradeSetFromSymbols(symbols []BitgetSymbol, config symbolConfig) (map[string]models.TradeSet, []string) {
	tradeSets := make(map[string]models.TradeSet, len(symbols))
	deleteSymbols := make([]string, 0)

	for _, item := range symbols {
		if utility.ContainsStr(config.quoteAssetSymbols, item.QuoteAsset) && item.Status == "online" {
			tradeSet := models.TradeSet{
				Coin:        item.BaseAsset,
				Currency:    item.QuoteAsset,
				PriceDigit:  item.PriceDigit,
				AmountDigit: item.QuantityDigit,
				MinQty:      utility.StringAsFloat(item.MinQty),
			}
			tradeSets[item.Symbol] = tradeSet
		}
	}

	return tradeSets, deleteSymbols
}

// GetSpotSymbols 获取现货交易对并构建TradeSet映射
func GetSpotSymbols() (map[string]models.TradeSet, []string, error) {
	api := NewBitgetRestApi()
	symbols, err := api.GetSpotSymbols()
	if err != nil {
		log.Error("获取bitget规范信息失败", err)
		return make(map[string]models.TradeSet, 0), []string{}, err
	}

	config := symbolConfig{
		symbolType:        "spot",
		quoteAssetSymbols: []string{"USDT", "ETH", "BTC", "SOL", "BNB", "DOGE"},
	}

	tradeSets, deleteSymbols := buildTradeSetFromSymbols(symbols, config)
	return tradeSets, deleteSymbols, nil
}

// GetFutSymbols 获取合约交易对并构建TradeSet映射
func GetFutSymbols() (map[string]models.TradeSet, []string, error) {
	api := NewBitgetRestApi()
	symbols, err := api.GetFutSymbols()
	if err != nil {
		log.Error("获取bitget合约规范信息失败", err)
		return make(map[string]models.TradeSet, 0), []string{}, err
	}

	config := symbolConfig{
		symbolType:        "futures",
		quoteAssetSymbols: []string{"USDT"},
	}

	tradeSets, deleteSymbols := buildTradeSetFromSymbols(symbols, config)
	return tradeSets, deleteSymbols, nil
}

// getTicker24hData 获取24小时行情数据的通用方法
func (api *BitgetRestApi) getTicker24hData(url, tickerType, description string, tradeSet *map[string]models.TradeSet) ([]string, error) {
	// 定义响应数据结构
	type tickerResponse struct {
		Code string `json:"code"`
		Msg  string `json:"msg"`
		Data []struct {
			Symbol    string `json:"symbol"`
			High24h   string `json:"high24h"`
			Low24h    string `json:"low24h"`
			Close     string `json:"lastPr"`
			Open      string `json:"open"`
			Volume24h string `json:"baseVolume"`   // 基础币成交量
			QuoteVol  string `json:"usdtVolume"`   // USDT成交量
			Change24h string `json:"changeUtc24h"` // UTC 24h涨跌幅
			Change    string `json:"change24h"`    // 24h涨跌幅
		} `json:"data"`
	}

	// 发送API请求
	resp, _, err := api.httpClient.SendSpotRequestAuth(url, "GET", map[string]interface{}{})
	if err != nil {
		return []string{}, fmt.Errorf("获取bitget %s 24h行情失败: %v", description, err)
	}

	// 解析响应数据
	var response tickerResponse
	if err := sonic.Unmarshal(resp, &response); err != nil {
		return []string{}, fmt.Errorf("解析bitget %s 24h行情失败: %v", description, err)
	}

	// 检查API响应状态
	if response.Code != "00000" {
		return []string{}, fmt.Errorf("bitget %s API错误: %s", description, response.Msg)
	}

	// 处理行情数据
	deleteSymbols := make([]string, 0)
	processedCount := 0
	errorCount := 0

	for _, item := range response.Data {
		// 构建缓存键
		key := fmt.Sprintf(tickerType, global.EXCHANGE_BITGET, item.Symbol)

		// 检查交易对是否存在
		symbol, exists := (*tradeSet)[item.Symbol]
		if !exists {
			// 清理不存在的交易对缓存
			if err := helper.DefaultRedis.DeleteString(key); err != nil {
				log.Warn("删除无效缓存失败: %s, error: %v", key, err)
			}
			continue
		}

		// 解析交易对获取coin和currency
		var coin, currency string
		if strings.HasSuffix(item.Symbol, symbol.Currency) {
			coin = strings.TrimSuffix(item.Symbol, symbol.Currency)
			currency = symbol.Currency
		} else {
			deleteSymbols = append(deleteSymbols, item.Symbol)
			continue
		}

		// 构建交易对数据
		symbol.Coin = coin
		symbol.Currency = currency
		symbol.OpenPrice = utility.StringAsFloat(item.Open)
		symbol.PriceChange = utility.StringAsFloat(item.Change)
		symbol.LowPrice = item.Low24h
		symbol.HighPrice = item.High24h
		symbol.Volume = item.Volume24h
		symbol.QuoteVolume = item.QuoteVol
		symbol.LastPrice = item.Close

		// 验证数据有效性
		if symbol.Coin == "" || symbol.Currency == "" ||
			utility.StringToFloat64(symbol.QuoteVolume) <= 0 ||
			symbol.LastPrice == "" || utility.StringToFloat64(symbol.LastPrice) <= 0 {
			if err := helper.DefaultRedis.DeleteString(key); err != nil {
				log.Warn("删除无效数据缓存失败: %s, error: %v", key, err)
			}
			deleteSymbols = append(deleteSymbols, item.Symbol)
			continue
		}

		// 缓存数据
		val, err := sonic.Marshal(symbol)
		if err != nil {
			log.Error("序列化交易对数据失败: %s, error: %v", item.Symbol, err)
			errorCount++
			continue
		}

		if err := helper.DefaultRedis.SetString(key, string(val)); err != nil {
			log.Error("缓存交易对失败: %s, error: %v", item.Symbol, err)
			errorCount++
			continue
		}

		processedCount++
	}

	log.Info("处理%s行情数据完成: 成功=%d, 错误=%d, 删除=%d",
		description, processedCount, errorCount, len(deleteSymbols))

	return deleteSymbols, nil
}

// GetSpotTicker24h 获取现货24小时行情变更并缓存
func (api *BitgetRestApi) GetSpotTicker24h(tradeSet *map[string]models.TradeSet) ([]string, error) {
	return api.getTicker24hData("/api/v2/spot/market/tickers", global.TICKER_SPOT, "现货", tradeSet)
}

// GetFutTicker24h 获取U本位合约24小时行情变更并缓存
func (api *BitgetRestApi) GetFutTicker24h(tradeSet *map[string]models.TradeSet) ([]string, error) {
	return api.getTicker24hData("/api/v2/mix/market/tickers?productType=USDT-FUTURES", global.TICKER_FUTURES, "U本位合约", tradeSet)
}

// BitgetSymbol Bitget交易对信息
type BitgetSymbol struct {
	Symbol        string `json:"symbol"`
	BaseCoin      string `json:"baseCoin"`
	QuoteCoin     string `json:"quoteCoin"`
	BaseAsset     string `json:"baseAsset"`
	QuoteAsset    string `json:"quoteAsset"`
	Status        string `json:"status"`
	MinQty        string `json:"minQty"`
	MaxQty        string `json:"maxQty"`
	PriceDigit    int    `json:"priceDigit"`
	QuantityDigit int    `json:"quantityDigit"`
}

// GetAndReloadSymbols 获取并重新加载交易对信息
// symbolType 1-现货 2-合约
func GetAndReloadSymbols(data *map[string]models.TradeSet, symbolType int) error {
	var tradeSets map[string]models.TradeSet
	var err error

	switch symbolType {
	case 1:
		tradeSets, _, err = GetSpotSymbols()
	case 2:
		tradeSets, _, err = GetFutSymbols()
	default:
		return fmt.Errorf("无效的symbolType: %d", symbolType)
	}

	if err != nil {
		return err
	}

	*data = tradeSets
	return nil
}

// InitSymbolsTicker24h 初始化24小时行情数据
// symbolType 1-现货 2-合约
func InitSymbolsTicker24h(data *map[string]models.TradeSet, symbolType int) ([]string, error) {
	api := NewBitgetRestApi()

	switch symbolType {
	case 1:
		return api.GetSpotTicker24h(data)
	case 2:
		return api.GetFutTicker24h(data)
	default:
		return []string{}, fmt.Errorf("无效的symbolType: %d", symbolType)
	}
}

// GetSpotTicker24 获取单个交易对24h行情
func (api *BitgetRestApi) GetSpotTicker24(symbol string, data *models.Ticker24, tradeSet *models.TradeSet) error {
	key := fmt.Sprintf(global.TICKER_SPOT, global.EXCHANGE_BITGET, symbol)
	val, err := helper.DefaultRedis.GetString(key)

	if err != nil {
		return err
	}

	err = sonic.Unmarshal([]byte(val), tradeSet)
	if err != nil {
		return err
	}

	if tradeSet.Coin != "" {
		data.HighPrice = tradeSet.HighPrice
		data.ChangePercent = fmt.Sprintf("%g", tradeSet.PriceChange)
		data.LastPrice = tradeSet.LastPrice
		data.LowPrice = tradeSet.LowPrice
		data.OpenPrice = fmt.Sprintf("%g", tradeSet.OpenPrice)
		data.QuoteVolume = tradeSet.QuoteVolume
		data.Volume = tradeSet.Volume
	}

	return nil
}
