package bootstrap

import (
	"baron-sso-backend/internal/domain"
	"fmt"
	"log/slog"

	"gorm.io/gorm"
)

// Run executes the application bootstrap logic (migrations, seeding, etc.)
func Run(db *gorm.DB) error {
	slog.Info("[Bootstrap] Starting application bootstrap...")

	// 1. Auto Migration
	if err := migrateSchemas(db); err != nil {
		return fmt.Errorf("migration failed: %w", err)
	}

	// 2. Seed Tenants
	if err := SeedTenants(db); err != nil {
		return fmt.Errorf("tenant seeding failed: %w", err)
	}

	// 3. Normalize staging seed/read-model data
	if err := CanonicalizeLegacyUserStatuses(db); err != nil {
		return fmt.Errorf("legacy user status canonicalization failed: %w", err)
	}
	if err := SanitizeLegacyUserMetadata(db); err != nil {
		return fmt.Errorf("legacy user metadata sanitize failed: %w", err)
	}

	slog.Info("[Bootstrap] User seed skipped (Kratos is SoT)")
	slog.Info("[Bootstrap] Bootstrap completed successfully.")
	return nil
}

func migrateSchemas(db *gorm.DB) error {
	slog.Info("[Bootstrap] Migrating database schemas...")
	if err := dropLegacyTenantDomainUniqueIndex(db); err != nil {
		return err
	}
	if err := dropLegacyUserCompanyColumns(db); err != nil {
		return err
	}

	// Add all domain models here
	return db.AutoMigrate(
		&domain.Tenant{},
		&domain.TenantDomain{},
		&domain.User{},
		&domain.UserLoginID{},
		&domain.UserProjectionState{},
		&domain.UserGroup{},
		&domain.ApiKey{},
		&domain.IdentityProviderConfig{},
		&domain.ClientSecret{},
		&domain.ClientConsent{},
		&domain.KetoOutbox{},
		&domain.RPUsageEvent{},
		&domain.WorksmobileOutbox{},
		&domain.WorksmobileResourceMapping{},
		&domain.SharedLink{},
		&domain.DeveloperRequest{},
		&domain.RPUserMetadata{},
		&domain.SystemSetting{},
	// &domain.RelyingParty{}, // Removed: SSOT is Hydra + Keto
	)
}

func CanonicalizeLegacyUserStatuses(db *gorm.DB) error {
	if db == nil || !db.Migrator().HasTable(&domain.User{}) {
		return nil
	}
	updates := map[string]string{
		"inactive":         domain.UserStatusPreboarding,
		"leave_of_absence": domain.UserStatusTemporaryLeave,
		"baron_only":       domain.UserStatusBaronGuest,
	}
	for legacy, canonical := range updates {
		if err := db.Model(&domain.User{}).
			Where("status = ?", legacy).
			Update("status", canonical).Error; err != nil {
			return fmt.Errorf("failed to canonicalize users.status %s to %s: %w", legacy, canonical, err)
		}
	}
	return nil
}

func dropLegacyUserCompanyColumns(db *gorm.DB) error {
	if !db.Migrator().HasTable(&domain.User{}) {
		return nil
	}
	for _, column := range []string{"company_code", "company_codes"} {
		if !db.Migrator().HasColumn(&domain.User{}, column) {
			continue
		}
		if err := db.Migrator().DropColumn(&domain.User{}, column); err != nil {
			return fmt.Errorf("failed to drop legacy users.%s column: %w", column, err)
		}
	}
	return nil
}

func dropLegacyTenantDomainUniqueIndex(db *gorm.DB) error {
	if !db.Migrator().HasTable(&domain.TenantDomain{}) {
		return nil
	}
	if !db.Migrator().HasIndex(&domain.TenantDomain{}, "idx_tenant_domains_domain") {
		return nil
	}
	if err := db.Migrator().DropIndex(&domain.TenantDomain{}, "idx_tenant_domains_domain"); err != nil {
		return fmt.Errorf("failed to drop legacy tenant domain unique index: %w", err)
	}
	return nil
}
