package models

import (
	"log/slog"
	"strings"

	"gorm.io/gorm"
)

// AllModels returns all models for auto-migration
func AllModels() []interface{} {
	return []interface{}{
		&User{},
		&Category{},
		&LotMetadata{},
		&Project{},
		&Configuration{},
		&PriceOverride{},
		&PricingAlert{},
		&ComponentUsageStats{},
		&Pricelist{},
		&PricelistItem{},
	}
}

// Migrate runs auto-migration for all QuoteForge tables
// Handles MySQL constraint errors gracefully for existing tables
func Migrate(db *gorm.DB) error {
	for _, model := range AllModels() {
		if err := db.AutoMigrate(model); err != nil {
			// Skip known MySQL constraint errors for existing tables
			errStr := err.Error()
			if strings.Contains(errStr, "Can't DROP") ||
				strings.Contains(errStr, "Duplicate key name") ||
				strings.Contains(errStr, "check that it exists") {
				slog.Warn("migration warning (skipped)", "model", model, "error", errStr)
				continue
			}
			return err
		}
	}
	return nil
}

// SeedCategories inserts default categories if not exist
func SeedCategories(db *gorm.DB) error {
	for _, cat := range DefaultCategories {
		result := db.Where("code = ?", cat.Code).FirstOrCreate(&cat)
		if result.Error != nil {
			return result.Error
		}
	}
	return nil
}

// SeedAdminUser creates default admin user if not exists
// Default credentials: admin / admin123
func SeedAdminUser(db *gorm.DB, passwordHash string) error {
	var count int64
	db.Model(&User{}).Where("username = ?", "admin").Count(&count)
	if count > 0 {
		return nil
	}

	admin := &User{
		Username:     "admin",
		Email:        "admin@example.com",
		PasswordHash: passwordHash,
		Role:         RoleAdmin,
		IsActive:     true,
	}
	return db.Create(admin).Error
}

// EnsureDBUser creates or returns the user corresponding to the database connection username.
// This is used when RBAC is disabled - configurations are owned by the DB user.
// Returns the user ID that should be used for all operations.
func EnsureDBUser(db *gorm.DB, dbUsername string) (uint, error) {
	if dbUsername == "" {
		return 0, nil
	}

	var user User
	err := db.Where("username = ?", dbUsername).First(&user).Error
	if err == nil {
		return user.ID, nil
	}

	// User doesn't exist, create it
	user = User{
		Username:     dbUsername,
		Email:        dbUsername + "@db.local",
		PasswordHash: "-", // No password - this is a DB user, not an app user
		Role:         RoleAdmin,
		IsActive:     true,
	}

	if err := db.Create(&user).Error; err != nil {
		slog.Error("failed to create DB user", "username", dbUsername, "error", err)
		return 0, err
	}

	slog.Info("created DB user for configurations", "username", dbUsername, "user_id", user.ID)
	return user.ID, nil
}
