package main

import (
	"flag"
	"log"
	"log/slog"
	"time"

	"git.mchus.pro/mchus/quoteforge/internal/appstate"
	"git.mchus.pro/mchus/quoteforge/internal/localdb"
	"git.mchus.pro/mchus/quoteforge/internal/models"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

func main() {
	defaultLocalDBPath, err := appstate.ResolveDBPath("")
	if err != nil {
		log.Fatalf("Failed to resolve default local SQLite path: %v", err)
	}
	localDBPath := flag.String("localdb", defaultLocalDBPath, "path to local SQLite database (default: user state dir or QFS_DB_PATH)")
	dryRun := flag.Bool("dry-run", false, "show what would be migrated without actually doing it")
	flag.Parse()

	log.Println("QuoteForge Configuration Migration Tool")
	log.Println("========================================")

	// Initialize local SQLite
	log.Printf("Opening local SQLite at %s...", *localDBPath)
	local, err := localdb.New(*localDBPath)
	if err != nil {
		log.Fatalf("Failed to initialize local database: %v", err)
	}
	log.Println("Local SQLite initialized")
	if !local.HasSettings() {
		log.Fatalf("SQLite connection settings are not configured. Run qfs setup first.")
	}

	settings, err := local.GetSettings()
	if err != nil {
		log.Fatalf("Failed to load SQLite connection settings: %v", err)
	}
	dsn, err := local.GetDSN()
	if err != nil {
		log.Fatalf("Failed to build DSN from SQLite settings: %v", err)
	}

	// Connect to MariaDB
	log.Printf("Connecting to MariaDB at %s:%d...", settings.Host, settings.Port)
	mariaDB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Silent),
	})
	if err != nil {
		log.Fatalf("Failed to connect to MariaDB: %v", err)
	}
	log.Println("Connected to MariaDB")

	// Count configurations in MariaDB
	var serverCount int64
	if err := mariaDB.Model(&models.Configuration{}).Count(&serverCount).Error; err != nil {
		log.Fatalf("Failed to count configurations: %v", err)
	}
	log.Printf("Found %d configurations in MariaDB", serverCount)

	if serverCount == 0 {
		log.Println("No configurations to migrate")
		return
	}

	// Get all configurations from MariaDB
	var configs []models.Configuration
	if err := mariaDB.Find(&configs).Error; err != nil {
		log.Fatalf("Failed to fetch configurations: %v", err)
	}

	// Check existing local configurations
	localCount := local.CountConfigurations()
	log.Printf("Found %d configurations in local SQLite", localCount)

	if *dryRun {
		log.Println("\n[DRY RUN] Would migrate the following configurations:")
		for _, c := range configs {
			userName := c.OwnerUsername
			if userName == "" {
				userName = "unknown"
			}
			log.Printf("  - %s (UUID: %s, User: %s, Items: %d)", c.Name, c.UUID, userName, len(c.Items))
		}
		log.Printf("\nTotal: %d configurations", len(configs))
		return
	}

	// Migrate configurations
	log.Println("\nMigrating configurations...")
	migrated := 0
	skipped := 0
	errors := 0

	for _, c := range configs {
		// Check if already exists
		existing, err := local.GetConfigurationByUUID(c.UUID)
		if err == nil && existing.ID > 0 {
			log.Printf("  SKIP: %s (already exists)", c.Name)
			skipped++
			continue
		}

		// Convert items
		localItems := make(localdb.LocalConfigItems, len(c.Items))
		for i, item := range c.Items {
			localItems[i] = localdb.LocalConfigItem{
				LotName:   item.LotName,
				Quantity:  item.Quantity,
				UnitPrice: item.UnitPrice,
			}
		}

		// Create local configuration
		now := time.Now()
		localConfig := &localdb.LocalConfiguration{
			UUID:             c.UUID,
			ServerID:         &c.ID,
			ProjectUUID:      c.ProjectUUID,
			Name:             c.Name,
			Items:            localItems,
			TotalPrice:       c.TotalPrice,
			CustomPrice:      c.CustomPrice,
			Notes:            c.Notes,
			IsTemplate:       c.IsTemplate,
			ServerCount:      c.ServerCount,
			CreatedAt:        c.CreatedAt,
			UpdatedAt:        now,
			SyncedAt:         &now,
			SyncStatus:       "synced",
			OriginalUserID:   derefUint(c.UserID),
			OriginalUsername: c.OwnerUsername,
		}

		if err := local.SaveConfiguration(localConfig); err != nil {
			log.Printf("  ERROR: %s - %v", c.Name, err)
			errors++
			continue
		}

		log.Printf("  OK: %s (%d items)", c.Name, len(c.Items))
		migrated++
	}

	log.Println("\n========================================")
	log.Printf("Migration complete!")
	log.Printf("  Migrated: %d", migrated)
	log.Printf("  Skipped:  %d", skipped)
	log.Printf("  Errors:   %d", errors)

	slog.Info("Done! You can now run the server with: go run ./cmd/qfs")
}

func derefUint(v *uint) uint {
	if v == nil {
		return 0
	}
	return *v
}
