package model

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/QuantumNous/new-api/common"
	"gorm.io/gorm"
)

// channelNoRoutePattern 与旧版三段式里 channel_no（c1、c2…）同形；route_slug 禁止使用该形态以免解析歧义。
var channelNoRoutePattern = regexp.MustCompile(`^c\d+$`)

// DefaultRouteSlugFromChannelID 返回渠道默认全局路由后缀（与 channels.id 一一对应）。
// 前缀 "u" 避免与旧 channel_no 段 c\d+ 混淆。
func DefaultRouteSlugFromChannelID(id int64) string {
	return "u" + EncodeBase62(id)
}

// IsValidRouteSlug 判断字符串是否可作为全局 route_slug：2～32 位 base62，且不能为 c+数字（旧 channel_no 形态）。
func IsValidRouteSlug(s string) bool {
	s = strings.TrimSpace(s)
	if len(s) < 2 || len(s) > 32 {
		return false
	}
	for _, c := range s {
		if !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
			return false
		}
	}
	if channelNoRoutePattern.MatchString(s) {
		return false
	}
	return true
}

// ResolveChannelIDByRouteSlugAndModel 按 route_slug 查找已启用渠道，并校验 models 列表包含 modelName。
// 未命中、已禁用或模型不在列表中时返回 0（供分发器静默降级为普通路由）。
func ResolveChannelIDByRouteSlugAndModel(slug, modelName string) int {
	slug = strings.TrimSpace(slug)
	if slug == "" || !IsValidRouteSlug(slug) {
		return 0
	}
	var ch Channel
	err := DB.Select("id", "models", "status").Where("route_slug = ?", slug).First(&ch).Error
	if err != nil {
		return 0
	}
	if ch.Status != common.ChannelStatusEnabled {
		return 0
	}
	if !ChannelModelsRawContains(ch.Models, modelName) {
		return 0
	}
	return ch.Id
}

// GetRouteSlugsByChannelIDs 批量返回 channel_id → route_slug（定价等场景）。
func GetRouteSlugsByChannelIDs(channelIDs []int) map[int]string {
	if len(channelIDs) == 0 {
		return nil
	}
	var rows []Channel
	if err := DB.Select("id", "route_slug").Where("id IN ?", channelIDs).Find(&rows).Error; err != nil {
		return nil
	}
	out := make(map[int]string, len(rows))
	for i := range rows {
		s := strings.TrimSpace(rows[i].RouteSlug)
		if s != "" {
			out[rows[i].Id] = s
		}
	}
	if len(out) == 0 {
		return nil
	}
	return out
}

// assignRouteSlugInTx 在事务内为新建渠道写入 route_slug（空则按 id 生成；非空则校验格式与唯一性）。
func assignRouteSlugInTx(tx *gorm.DB, channelID int, requested string) (assigned string, err error) {
	if channelID <= 0 {
		return "", nil
	}
	req := strings.TrimSpace(requested)
	slug := req
	if slug == "" {
		slug = DefaultRouteSlugFromChannelID(int64(channelID))
	} else if !IsValidRouteSlug(slug) {
		return "", fmt.Errorf("route_slug 无效")
	}
	var cnt int64
	if err := tx.Model(&Channel{}).Where("route_slug = ? AND id <> ?", slug, channelID).Count(&cnt).Error; err != nil {
		return "", err
	}
	if cnt > 0 {
		return "", fmt.Errorf("route_slug 已被占用")
	}
	if err := tx.Model(&Channel{}).Where("id = ?", channelID).Update("route_slug", slug).Error; err != nil {
		return "", err
	}
	return slug, nil
}

// BackfillChannelRouteSlugs 为缺少 route_slug 的渠道写入默认值（幂等）。
func BackfillChannelRouteSlugs() error {
	if DB == nil || DB.Migrator() == nil {
		return nil
	}
	if !DB.Migrator().HasColumn(&Channel{}, "route_slug") {
		return nil
	}
	var ids []int
	if err := DB.Model(&Channel{}).Where("route_slug IS NULL OR route_slug = ?", "").Pluck("id", &ids).Error; err != nil {
		return err
	}
	for _, id := range ids {
		slug := DefaultRouteSlugFromChannelID(int64(id))
		if err := DB.Model(&Channel{}).Where("id = ?", id).Update("route_slug", slug).Error; err != nil {
			return fmt.Errorf("backfill route_slug channel_id=%d: %w", id, err)
		}
	}
	return nil
}

// ensureRouteSlugLookupIndex 创建 route_slug 普通索引（非唯一：批量插入时须先落库再逐行赋值 slug，避免空串唯一冲突）。
func ensureRouteSlugLookupIndex() error {
	sql := "CREATE INDEX IF NOT EXISTS idx_channels_route_slug ON channels (route_slug)"
	if common.UsingMySQL {
		sql = "CREATE INDEX idx_channels_route_slug ON channels (route_slug)"
	}
	err := DB.Exec(sql).Error
	if err == nil {
		return nil
	}
	msg := strings.ToLower(err.Error())
	if strings.Contains(msg, "duplicate") || strings.Contains(msg, "already exists") || strings.Contains(msg, "exist") {
		return nil
	}
	return fmt.Errorf("ensure route_slug lookup index: %w", err)
}

// MigrateChannelRouteSlugAndDropLegacy 删除未上线的旧 route_index 表、补全 route_slug、建查询索引。
func MigrateChannelRouteSlugAndDropLegacy() error {
	if DB == nil || DB.Migrator() == nil {
		return nil
	}
	if DB.Migrator().HasTable("channel_model_route_indices") {
		if err := DB.Migrator().DropTable("channel_model_route_indices"); err != nil {
			return fmt.Errorf("drop channel_model_route_indices: %w", err)
		}
	}
	if err := BackfillChannelRouteSlugs(); err != nil {
		return err
	}
	return ensureRouteSlugLookupIndex()
}
