package db

import (
	"gpt-load/internal/models"

	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
)

// TODO: 更新迁移，待多个版本后旧版本都升级差不多之后移除。
func V1_0_13_FixRequestLogs(db *gorm.DB) error {
	// 如果有key_id，就执行修复
	if !db.Migrator().HasColumn(&models.RequestLog{}, "key_id") {
		return nil
	}

	logrus.Info("Old schema detected. Starting data migration for request_logs...")

	if !db.Migrator().HasColumn(&models.RequestLog{}, "group_name") {
		logrus.Info("Adding 'group_name' column to request_logs table...")
		if err := db.Migrator().AddColumn(&models.RequestLog{}, "group_name"); err != nil {
			return err // Column addition is critical
		}
	}
	if !db.Migrator().HasColumn(&models.RequestLog{}, "key_value") {
		logrus.Info("Adding 'key_value' column to request_logs table...")
		if err := db.Migrator().AddColumn(&models.RequestLog{}, "key_value"); err != nil {
			return err // Column addition is critical
		}
	}

	type OldRequestLog struct {
		ID      string
		KeyID   uint `gorm:"column:key_id"`
		GroupID uint
	}

	batchSize := 1000
	for i := 0; ; i++ {
		logrus.Infof("Processing batch %d...", i+1)
		var oldLogs []OldRequestLog

		result := db.Model(&models.RequestLog{}).
			Select("id", "key_id", "group_id").
			Where("key_value IS NULL OR group_name IS NULL").
			Limit(batchSize).
			Find(&oldLogs)

		if result.Error != nil {
			logrus.WithError(result.Error).Error("Failed to fetch batch of logs. Skipping to next batch.")
			continue
		}

		if len(oldLogs) == 0 {
			logrus.Info("All batches processed.")
			break
		}

		keyIDMap := make(map[uint]bool)
		groupIDMap := make(map[uint]bool)
		for _, logEntry := range oldLogs {
			if logEntry.KeyID > 0 {
				keyIDMap[logEntry.KeyID] = true
			}
			if logEntry.GroupID > 0 {
				groupIDMap[logEntry.GroupID] = true
			}
		}

		var apiKeys []models.APIKey
		if len(keyIDMap) > 0 {
			var keyIDs []uint
			for id := range keyIDMap {
				keyIDs = append(keyIDs, id)
			}
			if err := db.Model(&models.APIKey{}).Where("id IN ?", keyIDs).Find(&apiKeys).Error; err != nil {
				logrus.WithError(err).Warn("Failed to fetch API keys for the current batch. Some logs may not be updated.")
			}
		}
		keyValueMapping := make(map[uint]string)
		for _, key := range apiKeys {
			keyValueMapping[key.ID] = key.KeyValue
		}

		var groups []models.Group
		if len(groupIDMap) > 0 {
			var groupIDs []uint
			for id := range groupIDMap {
				groupIDs = append(groupIDs, id)
			}
			if err := db.Model(&models.Group{}).Where("id IN ?", groupIDs).Find(&groups).Error; err != nil {
				logrus.WithError(err).Warn("Failed to fetch groups for the current batch. Some logs may not be updated.")
			}
		}
		groupNameMapping := make(map[uint]string)
		for _, group := range groups {
			groupNameMapping[group.ID] = group.Name
		}

		updateGroups := make(map[string]map[string][]string)

		for _, logEntry := range oldLogs {
			groupName, gExists := groupNameMapping[logEntry.GroupID]
			if !gExists {
				logrus.Warnf("Log ID %s: Could not find Group for group_id %d. Setting group_name to empty string.", logEntry.ID, logEntry.GroupID)
			}

			keyValue, kExists := keyValueMapping[logEntry.KeyID]
			if !kExists {
				logrus.Warnf("Log ID %s: Could not find APIKey for key_id %d. Setting key_value to empty string.", logEntry.ID, logEntry.KeyID)
			}

			if _, ok := updateGroups[groupName]; !ok {
				updateGroups[groupName] = make(map[string][]string)
			}
			updateGroups[groupName][keyValue] = append(updateGroups[groupName][keyValue], logEntry.ID)
		}

		for groupName, keyMap := range updateGroups {
			for keyValue, ids := range keyMap {
				updates := map[string]any{
					"group_name": groupName,
					"key_value":  keyValue,
				}
				if err := db.Model(&models.RequestLog{}).Where("id IN ?", ids).UpdateColumns(updates).Error; err != nil {
					logrus.WithError(err).Errorf("Failed to update a batch of log entries. Skipping this batch.")
				}
			}
		}
		logrus.Infof("Finished processing batch %d. Updated %d log entries.", i+1, len(oldLogs))
	}

	logrus.Info("Data migration complete. Dropping 'key_id' column from request_logs table...")
	if err := db.Migrator().DropColumn(&models.RequestLog{}, "key_id"); err != nil {
		logrus.WithError(err).Warn("Failed to drop 'key_id' column. This can be done manually.")
	}

	logrus.Info("Database migration finished!")
	return nil
}
