package model

import (
	"encoding/json"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/QuantumNous/new-api/common"
	"github.com/QuantumNous/new-api/constant"
	"github.com/QuantumNous/new-api/setting/ratio_setting"
	"github.com/QuantumNous/new-api/types"
)

type Pricing struct {
	ModelName              string                  `json:"model_name"`
	Description            string                  `json:"description,omitempty"`
	DocIntroduction        string                  `json:"doc_introduction,omitempty"`
	ApiDocs                string                  `json:"api_docs,omitempty"`
	Icon                   string                  `json:"icon,omitempty"`
	Tags                   string                  `json:"tags,omitempty"`
	VendorID               int                     `json:"vendor_id,omitempty"`
	QuotaType              int                     `json:"quota_type"`
	ModelRatio             float64                 `json:"model_ratio"`
	ModelPrice             float64                 `json:"model_price"`
	OwnerBy                string                  `json:"owner_by"`
	CompletionRatio        *float64                `json:"completion_ratio,omitempty"`
	CacheRatio             *float64                `json:"cache_ratio,omitempty"`
	CreateCacheRatio       *float64                `json:"create_cache_ratio,omitempty"`
	ImageRatio             *float64                `json:"image_ratio,omitempty"`
	AudioRatio             *float64                `json:"audio_ratio,omitempty"`
	AudioCompletionRatio   *float64                `json:"audio_completion_ratio,omitempty"`
	VideoRatio             *float64                `json:"video_ratio,omitempty"`
	VideoCompletionRatio   *float64                `json:"video_completion_ratio,omitempty"`
	VideoPrice             *float64                `json:"video_price,omitempty"`
	EnableGroup            []string                `json:"enable_groups"`
	SupportedEndpointTypes []constant.EndpointType `json:"supported_endpoint_types"`
	PricingVersion         string                  `json:"pricing_version,omitempty"`
}

type PricingVendor struct {
	ID          int    `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Icon        string `json:"icon,omitempty"`
}

// PricingSupplierItem 定价 data 中的供应商摘要。
type PricingSupplierItem struct {
	SupplierID     int    `json:"supplier_id"`
	SupplierAlias  string `json:"supplier_alias"`
	CompanyLogoURL string `json:"company_logo_url"`
	SupplierType   string `json:"supplier_type"`
}

// PricingChannelItem 某模型在各渠道上的定价摘要。
type PricingChannelItem struct {
	ChannelID             int    `json:"channel_id"`
	SupplierApplicationID int    `json:"supplier_application_id"`
	ChannelNo             string `json:"channel_no"`
	SupplierAlias         string `json:"supplier_alias"`
	CompanyLogoURL        string `json:"company_logo_url"`
	SupplierType          string `json:"supplier_type"`
	// RouteSlug 渠道全局路由后缀，与模型名组合为 {model}/{route_slug} 强制路由至该渠道（整渠道下各模型共用）。
	RouteSlug string `json:"route_slug,omitempty"`
	// TestResponseTimeMs 渠道最近可展示的单测耗时（毫秒）；0 代表未测试或测试失败，接口将省略该字段。
	TestResponseTimeMs   int     `json:"test_response_time_ms,omitempty"`
	ModelPrice           float64 `json:"model_price"`
	ModelRatio           float64 `json:"model_ratio"`
	CompletionRatio      float64 `json:"completion_ratio"`
	CacheRatio           float64 `json:"cache_ratio"`
	CreateCacheRatio     float64 `json:"create_cache_ratio"`
	ModelTierRatio       any     `json:"model_tier_ratio,omitempty"`
	CompletionTierRatio  any     `json:"completion_tier_ratio,omitempty"`
	CacheTierRatio       any     `json:"cache_tier_ratio,omitempty"`
	CreateCacheTierRatio any     `json:"create_cache_tier_ratio,omitempty"`
	PriceDiscountPercent float64 `json:"price_discount_percent"` // 成本折扣率（百分数，100=不打折）
	MarkupDiscountRate   float64 `json:"markup_discount_rate"`   // 加价折扣率（百分数，0=不加价）
	QuotaType            int     `json:"quota_type"`

	// OptionModelRatio 等：仅 Option「渠道模型定价」显式配置（不做供应商/全局回退），供首页成本价展示。
	OptionModelRatio       *float64 `json:"option_model_ratio,omitempty"`
	OptionCompletionRatio  *float64 `json:"option_completion_ratio,omitempty"`
	OptionCacheRatio       *float64 `json:"option_cache_ratio,omitempty"`
	OptionCreateCacheRatio *float64 `json:"option_create_cache_ratio,omitempty"`
	OptionModelPrice       *float64 `json:"option_model_price,omitempty"`
	OptionImageRatio       *float64 `json:"option_image_ratio,omitempty"`
	OptionImagePrice       *float64 `json:"option_image_price,omitempty"`
	OptionAudioRatio       *float64 `json:"option_audio_ratio,omitempty"`
	OptionAudioCompletionRatio *float64 `json:"option_audio_completion_ratio,omitempty"`
	OptionVideoRatio           *float64 `json:"option_video_ratio,omitempty"`
	OptionVideoCompletionRatio *float64 `json:"option_video_completion_ratio,omitempty"`
	OptionVideoPrice           *float64 `json:"option_video_price,omitempty"`

	// 热门排序相关字段
	SortWeight         float64 `json:"sort_weight"`           // 渠道权重
	ManualBaseReqCount int64   `json:"manual_base_req_count"` // 手动设置调用基数
	AutoReqCount       int64   `json:"auto_req_count"`        // 自动统计调用次数
	FinalReqCount      int64   `json:"final_req_count"`       // 最终调用次数 (= manual + auto)
	ChannelHeatScore   float64 `json:"channel_heat_score"`    // 渠道热度得分 (= final * weight)
}

// PricingAPIItem 在 Pricing 基础上扩展渠道维度统计字段（定价接口 data 元素类型）。
type PricingAPIItem struct {
	Pricing
	SupplierList      []PricingSupplierItem     `json:"supplier_list"`
	ChannelList       []PricingChannelItem      `json:"channel_list"`
	VideoFlatClipHint *VideoFlatClipPricingHint `json:"video_flat_clip_hint,omitempty"`
	ImagePerImageHint *ImagePerImagePricingHint `json:"image_per_image_hint,omitempty"`
}

func resolveChannelPricingTriple(channelID int, supplierApplicationID int, modelName string) (mp, mr, cr float64) {
	cr = ResolveSupplierScopedCompletionRatio(channelID, supplierApplicationID, modelName)
	// 优先级：供应商渠道表 > 供应商全局表 > Option 渠道 > 平台全局 > 旧 SupplierOption
	if v, ok := ResolveSupplierScopedFixedModelPrice(channelID, supplierApplicationID, modelName); ok {
		return v, 0, cr
	}
	mr, _, _ = ResolveSupplierScopedModelRatio(channelID, supplierApplicationID, modelName)
	return 0, mr, cr
}

func resolveChannelCachePair(channelID int, supplierApplicationID int, modelName string) (cacheRatio, createCacheRatio float64) {
	return ResolveSupplierScopedCacheRatios(channelID, supplierApplicationID, modelName)
}

// fillOptionChannelPricingFields 填充仅来自 Option 渠道模型定价的字段（与运营设置-渠道模型定价一致）。
func fillOptionChannelPricingFields(item *PricingChannelItem, channelID int, modelName string) {
	if v, ok := ratio_setting.GetChannelModelRatio(channelID, modelName); ok {
		vv := v
		item.OptionModelRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelCompletionRatio(channelID, modelName); ok {
		vv := v
		item.OptionCompletionRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelCacheRatio(channelID, modelName); ok {
		vv := v
		item.OptionCacheRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelCreateCacheRatio(channelID, modelName); ok {
		vv := v
		item.OptionCreateCacheRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelModelPrice(channelID, modelName); ok {
		vv := v
		item.OptionModelPrice = &vv
	}
	if v, ok := ratio_setting.GetChannelImageRatio(channelID, modelName); ok {
		vv := v
		item.OptionImageRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelImagePrice(channelID, modelName); ok {
		vv := v
		item.OptionImagePrice = &vv
	}
	if v, ok := ratio_setting.GetChannelAudioRatio(channelID, modelName); ok {
		vv := v
		item.OptionAudioRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelAudioCompletionRatio(channelID, modelName); ok {
		vv := v
		item.OptionAudioCompletionRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelVideoRatio(channelID, modelName); ok {
		vv := v
		item.OptionVideoRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelVideoCompletionRatio(channelID, modelName); ok {
		vv := v
		item.OptionVideoCompletionRatio = &vv
	}
	if v, ok := ratio_setting.GetChannelVideoPrice(channelID, modelName); ok {
		vv := v
		item.OptionVideoPrice = &vv
	}
}

func pricingSupplierAliasFromMeta(supplierApplicationID int, alias *string) string {
	if supplierApplicationID == 0 {
		return "P0"
	}
	if alias != nil {
		s := strings.TrimSpace(*alias)
		if s == "0" {
			return "P0"
		}
		if s != "" {
			return s
		}
	}
	return SupplierApplicationAutoAlias(supplierApplicationID)
}

// BuildPricingAPIItems 为定价接口组装带渠道统计的 data 列表。
// 渠道项价格为：基础定价（resolveChannelPricingTriple）× 渠道专属折扣；用户/分组倍率由前端用 group_ratio 再乘（与 calculateModelPrice 一致）。
//
// includeUntestedChannelPricingRows 为 false 时保持原行为：要求有有效单测耗时，且在渠道已有成功单测时要求本模型单测可匹配。
// 为 true 时不过滤上述单测门禁，供 /api/price_sync 等需完整渠道定价（含未单测模型×渠道）的场景。
func BuildPricingAPIItems(filtered []Pricing, visibleChannelIDs map[int]struct{}, metas []ChannelPricingMeta, includeUntestedChannelPricingRows bool) []PricingAPIItem {
	testSuccessByChannel, err := LoadChannelPricingTestSuccessIndex()
	if err != nil {
		common.SysLog(fmt.Sprintf("LoadChannelPricingTestSuccessIndex error: %v", err))
		testSuccessByChannel = nil
	}
	visibleIDs := make([]int, 0, len(visibleChannelIDs))
	for id := range visibleChannelIDs {
		visibleIDs = append(visibleIDs, id)
	}

	// 一次性批量加载可见渠道的 route_slug，避免 N+1 查询
	channelSlugMap := GetRouteSlugsByChannelIDs(visibleIDs)

	// 按“模型 × 渠道”打平返回：每条 data 仅包含 1 个 channel_list 与 1 个 supplier_list。
	// 这样在前端可直接按渠道维度渲染，不再需要先展开聚合模型行。
	out := make([]PricingAPIItem, 0, len(filtered))
	for _, p := range filtered {
		var chItems []PricingChannelItem

		modelName := p.ModelName
		// 为当前模型预加载各可见渠道的测试耗时：手动覆盖耗时优先，否则使用最近一次成功测试耗时。
		testResponseTimeByChannel := make(map[int]int)
		if len(visibleIDs) > 0 {
			rows, err := GetModelTestResultsByModelNameAndChannelIDs(modelName, visibleIDs)
			if err != nil {
				common.SysLog(fmt.Sprintf("GetModelTestResultsByModelNameAndChannelIDs error: model=%s err=%v", modelName, err))
			} else {
				for i := range rows {
					r := rows[i]
					if r.ChannelId <= 0 {
						continue
					}
					if r.ManualDisplayResponseTime > 0 {
						testResponseTimeByChannel[r.ChannelId] = r.ManualDisplayResponseTime
						continue
					}
					if r.LastTestSuccess && r.LastResponseTime > 0 {
						testResponseTimeByChannel[r.ChannelId] = r.LastResponseTime
					}
				}
			}
		}
		for _, row := range metas {
			if row.ChannelID <= 0 {
				continue
			}
			if _, ok := visibleChannelIDs[row.ChannelID]; !ok {
				continue
			}
			if !ChannelModelsRawContains(row.Models, modelName) {
				continue
			}
			// 单测门禁：仅当该渠道在库中已有「至少一条」成功单测记录时，才要求本模型也有成功记录。
			// 否则新渠道/供应商从未跑过单测时 names 为空，旧逻辑会对所有模型 continue，导致供应商只见自有渠道时 data 全空。
			if !includeUntestedChannelPricingRows && testSuccessByChannel != nil {
				namesOK := testSuccessByChannel[row.ChannelID]
				if len(namesOK) > 0 && !ChannelPricingRowMatchesLastTestSuccess(testSuccessByChannel, row.ChannelID, modelName) {
					continue
				}
			}
			testMs := testResponseTimeByChannel[row.ChannelID]
			// 打平后按渠道逐条返回：若该渠道无有效单测耗时（0=未测/失败），整条模型-渠道数据不展示（定价页）；price_sync 等场景传入 includeUntestedChannelPricingRows 以保留。
			if !includeUntestedChannelPricingRows && testMs <= 0 {
				continue
			}
			baseMp, baseMr, cr := resolveChannelPricingTriple(row.ChannelID, row.SupplierApplicationID, modelName)
			chCache, chCreate := resolveChannelCachePair(row.ChannelID, row.SupplierApplicationID, modelName)
			modelTierRatio, hasModelTierRatio := ratio_setting.ResolveModelTierRatio(row.ChannelID, modelName)
			completionTierRatio, hasCompletionTierRatio := ratio_setting.ResolveCompletionTierRatio(row.ChannelID, modelName)
			cacheTierRatio, hasCacheTierRatio := ratio_setting.ResolveCacheTierRatio(row.ChannelID, modelName)
			createCacheTierRatio, hasCreateCacheTierRatio := ratio_setting.ResolveCreateCacheTierRatio(row.ChannelID, modelName)
			alias := pricingSupplierAliasFromMeta(row.SupplierApplicationID, row.SupplierAlias)
			d := 100.0
			if row.PriceDiscountPercent != nil {
				d = *row.PriceDiscountPercent
			}
			markupRate := 0.0
			if row.MarkupDiscountRate != nil {
				markupRate = *row.MarkupDiscountRate
			}
			// 新公式：前端接收原始倍率（baseMp/baseMr），由前端按公式显式乘以成本折扣率；
			// price_discount_percent 和 markup_discount_rate 一并下发供前端计算。
			routeSlug := ""
			if channelSlugMap != nil {
				routeSlug = channelSlugMap[row.ChannelID]
			}
			chItem := PricingChannelItem{
				ChannelID:             row.ChannelID,
				SupplierApplicationID: row.SupplierApplicationID,
				ChannelNo:             row.ChannelNo,
				SupplierAlias:         alias,
				CompanyLogoURL:        strings.TrimSpace(row.CompanyLogoURL),
				SupplierType:          strings.TrimSpace(row.SupplierType),
				RouteSlug:             routeSlug,
				TestResponseTimeMs:    testMs,
				ModelPrice:            baseMp,
				ModelRatio:            baseMr,
				CompletionRatio:       cr,
				CacheRatio:            chCache,
				CreateCacheRatio:      chCreate,
				PriceDiscountPercent:  d,
				MarkupDiscountRate:    markupRate,
				QuotaType: func() int {
					if baseMp > 0 {
						return 1
					} else {
						return 0
					}
				}(),
			}
			if hasModelTierRatio {
				chItem.ModelTierRatio = modelTierRatio
			}
			if hasCompletionTierRatio {
				chItem.CompletionTierRatio = completionTierRatio
			}
			if hasCacheTierRatio {
				chItem.CacheTierRatio = cacheTierRatio
			}
			if hasCreateCacheTierRatio {
				chItem.CreateCacheTierRatio = createCacheTierRatio
			}
			fillOptionChannelPricingFields(&chItem, row.ChannelID, modelName)
			chItems = append(chItems, chItem)
		}

		if len(chItems) == 0 {
			continue
		}

		sort.Slice(chItems, func(i, j int) bool {
			var ai, aj float64
			if p.QuotaType == 1 {
				ai, aj = chItems[i].ModelPrice, chItems[j].ModelPrice
			} else {
				ai, aj = chItems[i].ModelRatio, chItems[j].ModelRatio
			}
			if ai != aj {
				return ai < aj
			}
			return chItems[i].ChannelID < chItems[j].ChannelID
		})

		for _, ch := range chItems {
			item := PricingAPIItem{Pricing: p}
			item.ChannelList = []PricingChannelItem{ch}
			item.SupplierList = []PricingSupplierItem{
				{
					SupplierID:     ch.SupplierApplicationID,
					SupplierAlias:  ch.SupplierAlias,
					CompanyLogoURL: ch.CompanyLogoURL,
					SupplierType:   ch.SupplierType,
				},
			}
			item.VideoFlatClipHint = BuildVideoFlatClipHint(ch.ChannelID, modelName, ch.PriceDiscountPercent, ch.MarkupDiscountRate)
			item.ImagePerImageHint = BuildImagePerImageHint(ch.ChannelID, modelName, ch.PriceDiscountPercent, ch.MarkupDiscountRate)
			out = append(out, item)
		}
	}
	return out
}

var (
	pricingMap           []Pricing
	vendorsList          []PricingVendor
	supportedEndpointMap map[string]common.EndpointInfo
	lastGetPricingTime   time.Time
	updatePricingLock    sync.Mutex

	// 缓存映射：模型名 -> 启用分组 / 计费类型
	modelEnableGroups     = make(map[string][]string)
	modelQuotaTypeMap     = make(map[string]int)
	modelEnableGroupsLock = sync.RWMutex{}
)

var (
	modelSupportEndpointTypes = make(map[string][]constant.EndpointType)
	modelSupportEndpointsLock = sync.RWMutex{}
)

func GetPricing() []Pricing {
	if time.Since(lastGetPricingTime) > time.Minute*1 || len(pricingMap) == 0 {
		updatePricingLock.Lock()
		defer updatePricingLock.Unlock()
		// Double check after acquiring the lock
		if time.Since(lastGetPricingTime) > time.Minute*1 || len(pricingMap) == 0 {
			modelSupportEndpointsLock.Lock()
			defer modelSupportEndpointsLock.Unlock()
			updatePricing()
		}
	}
	return pricingMap
}

// GetVendors 返回当前定价接口使用到的供应商信息
func GetVendors() []PricingVendor {
	if time.Since(lastGetPricingTime) > time.Minute*1 || len(pricingMap) == 0 {
		// 保证先刷新一次
		GetPricing()
	}
	return vendorsList
}

func GetModelSupportEndpointTypes(model string) []constant.EndpointType {
	if model == "" {
		return make([]constant.EndpointType, 0)
	}
	modelSupportEndpointsLock.RLock()
	defer modelSupportEndpointsLock.RUnlock()
	if endpoints, ok := modelSupportEndpointTypes[model]; ok {
		return endpoints
	}
	return make([]constant.EndpointType, 0)
}

func updatePricing() {
	//modelRatios := common.GetModelRatios()
	enableAbilities, err := GetAllEnableAbilityWithChannels()
	if err != nil {
		common.SysLog(fmt.Sprintf("GetAllEnableAbilityWithChannels error: %v", err))
		return
	}
	// 预加载模型元数据与供应商一次，避免循环查询
	var allMeta []Model
	_ = DB.Find(&allMeta).Error
	metaMap := make(map[string]*Model)
	prefixList := make([]*Model, 0)
	suffixList := make([]*Model, 0)
	containsList := make([]*Model, 0)
	for i := range allMeta {
		m := &allMeta[i]
		if m.NameRule == NameRuleExact {
			metaMap[m.ModelName] = m
		} else {
			switch m.NameRule {
			case NameRulePrefix:
				prefixList = append(prefixList, m)
			case NameRuleSuffix:
				suffixList = append(suffixList, m)
			case NameRuleContains:
				containsList = append(containsList, m)
			}
		}
	}

	// 将非精确规则模型匹配到 metaMap
	for _, m := range prefixList {
		for _, pricingModel := range enableAbilities {
			if strings.HasPrefix(pricingModel.Model, m.ModelName) {
				if _, exists := metaMap[pricingModel.Model]; !exists {
					metaMap[pricingModel.Model] = m
				}
			}
		}
	}
	for _, m := range suffixList {
		for _, pricingModel := range enableAbilities {
			if strings.HasSuffix(pricingModel.Model, m.ModelName) {
				if _, exists := metaMap[pricingModel.Model]; !exists {
					metaMap[pricingModel.Model] = m
				}
			}
		}
	}
	for _, m := range containsList {
		for _, pricingModel := range enableAbilities {
			if strings.Contains(pricingModel.Model, m.ModelName) {
				if _, exists := metaMap[pricingModel.Model]; !exists {
					metaMap[pricingModel.Model] = m
				}
			}
		}
	}

	// 预加载供应商
	var vendors []Vendor
	_ = DB.Find(&vendors).Error
	vendorMap := make(map[int]*Vendor)
	for i := range vendors {
		vendorMap[vendors[i].Id] = &vendors[i]
	}

	// 初始化默认供应商映射
	initDefaultVendorMapping(metaMap, vendorMap, enableAbilities)

	// 构建对前端友好的供应商列表
	vendorsList = make([]PricingVendor, 0, len(vendorMap))
	for _, v := range vendorMap {
		vendorsList = append(vendorsList, PricingVendor{
			ID:          v.Id,
			Name:        v.Name,
			Description: v.Description,
			Icon:        v.Icon,
		})
	}

	modelGroupsMap := make(map[string]*types.Set[string])

	for _, ability := range enableAbilities {
		groups, ok := modelGroupsMap[ability.Model]
		if !ok {
			groups = types.NewSet[string]()
			modelGroupsMap[ability.Model] = groups
		}
		groups.Add(ability.Group)
	}

	//这里使用切片而不是Set，因为一个模型可能支持多个端点类型，并且第一个端点是优先使用端点
	modelSupportEndpointsStr := make(map[string][]string)

	// 先根据已有能力填充原生端点
	for _, ability := range enableAbilities {
		endpoints := modelSupportEndpointsStr[ability.Model]
		channelTypes := common.GetEndpointTypesByChannelType(ability.ChannelType, ability.Model)
		for _, channelType := range channelTypes {
			if !common.StringsContains(endpoints, string(channelType)) {
				endpoints = append(endpoints, string(channelType))
			}
		}
		modelSupportEndpointsStr[ability.Model] = endpoints
	}

	// 再补充模型自定义端点：若配置有效则替换默认端点，不做合并
	for modelName, meta := range metaMap {
		if strings.TrimSpace(meta.Endpoints) == "" {
			continue
		}
		var raw map[string]interface{}
		if err := json.Unmarshal([]byte(meta.Endpoints), &raw); err == nil {
			endpoints := make([]string, 0, len(raw))
			for k, v := range raw {
				switch v.(type) {
				case string, map[string]interface{}:
					if !common.StringsContains(endpoints, k) {
						endpoints = append(endpoints, k)
					}
				}
			}
			if len(endpoints) > 0 {
				modelSupportEndpointsStr[modelName] = endpoints
			}
		}
	}

	modelSupportEndpointTypes = make(map[string][]constant.EndpointType)
	for model, endpoints := range modelSupportEndpointsStr {
		supportedEndpoints := make([]constant.EndpointType, 0)
		for _, endpointStr := range endpoints {
			endpointType := constant.EndpointType(endpointStr)
			supportedEndpoints = append(supportedEndpoints, endpointType)
		}
		modelSupportEndpointTypes[model] = supportedEndpoints
	}

	// 构建全局 supportedEndpointMap（默认 + 自定义覆盖）
	supportedEndpointMap = make(map[string]common.EndpointInfo)
	// 1. 默认端点
	for _, endpoints := range modelSupportEndpointTypes {
		for _, et := range endpoints {
			if info, ok := common.GetDefaultEndpointInfo(et); ok {
				if _, exists := supportedEndpointMap[string(et)]; !exists {
					supportedEndpointMap[string(et)] = info
				}
			}
		}
	}
	// 2. 自定义端点（models 表）覆盖默认
	for _, meta := range metaMap {
		if strings.TrimSpace(meta.Endpoints) == "" {
			continue
		}
		var raw map[string]interface{}
		if err := json.Unmarshal([]byte(meta.Endpoints), &raw); err == nil {
			for k, v := range raw {
				switch val := v.(type) {
				case string:
					supportedEndpointMap[k] = common.EndpointInfo{Path: val, Method: "POST"}
				case map[string]interface{}:
					ep := common.EndpointInfo{Method: "POST"}
					if p, ok := val["path"].(string); ok {
						ep.Path = p
					}
					if m, ok := val["method"].(string); ok {
						ep.Method = strings.ToUpper(m)
					}
					supportedEndpointMap[k] = ep
				default:
					// ignore unsupported types
				}
			}
		}
	}

	pricingMap = make([]Pricing, 0)
	for model, groups := range modelGroupsMap {
		pricing := Pricing{
			ModelName:              model,
			EnableGroup:            groups.Items(),
			SupportedEndpointTypes: modelSupportEndpointTypes[model],
		}

		// 补充模型元数据（描述、标签、供应商、状态）
		if meta, ok := metaMap[model]; ok {
			// 若模型被禁用(status!=1)，则直接跳过，不返回给前端
			if meta.Status != 1 {
				continue
			}
			pricing.Description = meta.Description
			pricing.DocIntroduction = meta.DocIntroduction
			pricing.ApiDocs = meta.ApiDocs
			pricing.Icon = meta.Icon
			pricing.Tags = meta.Tags
			pricing.VendorID = meta.VendorID
		}
		modelPrice, findPrice := ratio_setting.GetModelPrice(model, false)
		if findPrice {
			pricing.ModelPrice = modelPrice
			pricing.QuotaType = 1
		} else {
			modelRatio, _, _ := ratio_setting.GetModelRatio(model)
			pricing.ModelRatio = modelRatio
			// 仅当模型有显式配置的输出倍率时才返回，否则前端不展示输出价格
			if ratio_setting.ContainsCompletionRatio(model) {
				cr := ratio_setting.GetCompletionRatio(model)
				pricing.CompletionRatio = &cr
			}
			pricing.QuotaType = 0
		}
		if cacheRatio, ok := ratio_setting.GetCacheRatio(model); ok {
			pricing.CacheRatio = &cacheRatio
		}
		if createCacheRatio, ok := ratio_setting.GetCreateCacheRatio(model); ok {
			pricing.CreateCacheRatio = &createCacheRatio
		}
		if imageRatio, ok := ratio_setting.GetImageRatio(model); ok {
			pricing.ImageRatio = &imageRatio
		}
		if ratio_setting.ContainsAudioRatio(model) {
			audioRatio := ratio_setting.GetAudioRatio(model)
			pricing.AudioRatio = &audioRatio
		}
		if ratio_setting.ContainsAudioCompletionRatio(model) {
			audioCompletionRatio := ratio_setting.GetAudioCompletionRatio(model)
			pricing.AudioCompletionRatio = &audioCompletionRatio
		}
		if ratio_setting.ContainsVideoRatio(model) {
			videoRatio := ratio_setting.GetVideoRatio(model)
			pricing.VideoRatio = &videoRatio
		}
		if ratio_setting.ContainsVideoCompletionRatio(model) {
			videoCompletionRatio := ratio_setting.GetVideoCompletionRatio(model)
			pricing.VideoCompletionRatio = &videoCompletionRatio
		}
		if ratio_setting.ContainsVideoPrice(model) {
			videoPrice, _ := ratio_setting.GetVideoPrice(model)
			pricing.VideoPrice = &videoPrice
		}
		pricingMap = append(pricingMap, pricing)
	}

	// 防止大更新后数据不通用
	if len(pricingMap) > 0 {
		pricingMap[0].PricingVersion = "5a90f2b86c08bd983a9a2e6d66c255f4eaef9c4bc934386d2b6ae84ef0ff1f1f"
	}

	// 刷新缓存映射，供高并发快速查询
	modelEnableGroupsLock.Lock()
	modelEnableGroups = make(map[string][]string)
	modelQuotaTypeMap = make(map[string]int)
	for _, p := range pricingMap {
		modelEnableGroups[p.ModelName] = p.EnableGroup
		modelQuotaTypeMap[p.ModelName] = p.QuotaType
	}
	modelEnableGroupsLock.Unlock()

	lastGetPricingTime = time.Now()
}

// GetSupportedEndpointMap 返回全局端点到路径的映射
func GetSupportedEndpointMap() map[string]common.EndpointInfo {
	return supportedEndpointMap
}

// ModelRequestStats 模型请求统计数据
type ModelRequestStats struct {
	ModelName       string `gorm:"column:model_name"`
	RequestCount7d  int64  `gorm:"column:req_count_7d"`
	RequestCount30d int64  `gorm:"column:req_count_30d"`
}

// ChannelModelRequestStats 渠道-模型组合的请求统计数据
type ChannelModelRequestStats struct {
	ChannelID       int    `gorm:"column:channel_id"`
	ModelName       string `gorm:"column:model_name"`
	RequestCount7d  int64  `gorm:"column:req_count_7d"`
	RequestCount30d int64  `gorm:"column:req_count_30d"`
}

// HeatStatPeriod 热度统计周期，可选值: "7d" | "30d" | "all"
const (
	HeatStatPeriod7d  = "7d"
	HeatStatPeriod30d = "30d"
	HeatStatPeriodAll = "all"
)

// GetModelRequestStatsByPeriod 查询各模型的请求统计数据，period 为 "7d"/"30d"/"all"
func GetModelRequestStatsByPeriod(period string) ([]ModelRequestStats, error) {
	now := time.Now()
	var startTime int64
	switch period {
	case HeatStatPeriod30d:
		startTime = now.AddDate(0, 0, -30).Unix()
	case HeatStatPeriodAll:
		startTime = 0
	default: // "7d"
		startTime = now.AddDate(0, 0, -7).Unix()
	}

	var stats []ModelRequestStats
	var err error
	if startTime == 0 {
		err = DB.Raw(`
			SELECT model_name,
			       COUNT(*) as req_count_7d,
			       COUNT(*) as req_count_30d
			FROM logs
			WHERE type = ?
			  AND model_name != ''
			GROUP BY model_name
		`, LogTypeConsume).Scan(&stats).Error
	} else {
		err = DB.Raw(`
			SELECT model_name,
			       COUNT(*) as req_count_7d,
			       COUNT(*) as req_count_30d
			FROM logs
			WHERE type = ?
			  AND model_name != ''
			  AND created_at >= ?
			GROUP BY model_name
		`, LogTypeConsume, startTime).Scan(&stats).Error
	}
	return stats, err
}

// GetModelRequestStats 查询各模型的请求统计数据（7天和30天）
func GetModelRequestStats() ([]ModelRequestStats, error) {
	return GetModelRequestStatsByPeriod(HeatStatPeriod7d)
}

// GetChannelModelRequestStatsByPeriod 查询各渠道-模型组合的请求统计数据，period 为 "7d"/"30d"/"all"
func GetChannelModelRequestStatsByPeriod(channelIDs []int, period string) ([]ChannelModelRequestStats, error) {
	if len(channelIDs) == 0 {
		return []ChannelModelRequestStats{}, nil
	}

	now := time.Now()
	var startTime int64
	switch period {
	case HeatStatPeriod30d:
		startTime = now.AddDate(0, 0, -30).Unix()
	case HeatStatPeriodAll:
		startTime = 0
	default: // "7d"
		startTime = now.AddDate(0, 0, -7).Unix()
	}

	var stats []ChannelModelRequestStats
	var err error
	if startTime == 0 {
		err = DB.Raw(`
			SELECT channel_id,
			       model_name,
			       COUNT(*) as req_count_7d,
			       COUNT(*) as req_count_30d
			FROM logs
			WHERE type = ?
			  AND model_name != ''
			  AND channel_id IN ?
			GROUP BY channel_id, model_name
		`, LogTypeConsume, channelIDs).Scan(&stats).Error
	} else {
		err = DB.Raw(`
			SELECT channel_id,
			       model_name,
			       COUNT(*) as req_count_7d,
			       COUNT(*) as req_count_30d
			FROM logs
			WHERE type = ?
			  AND model_name != ''
			  AND channel_id IN ?
			  AND created_at >= ?
			GROUP BY channel_id, model_name
		`, LogTypeConsume, channelIDs, startTime).Scan(&stats).Error
	}
	return stats, err
}

// GetChannelModelRequestStats 查询各渠道-模型组合的请求统计数据
func GetChannelModelRequestStats(channelIDs []int) ([]ChannelModelRequestStats, error) {
	return GetChannelModelRequestStatsByPeriod(channelIDs, HeatStatPeriod7d)
}
