package main

import (
	"context"
	"fmt"
	"os"
	"strconv"

	"time"

	"git.leaktechnologies.dev/stu/Goondex/internal/db"
	"git.leaktechnologies.dev/stu/Goondex/internal/config"
	"git.leaktechnologies.dev/stu/Goondex/internal/model"
	"git.leaktechnologies.dev/stu/Goondex/internal/scraper/adultemp"
	"git.leaktechnologies.dev/stu/Goondex/internal/scraper/merger"
	"git.leaktechnologies.dev/stu/Goondex/internal/scraper/tpdb"
	"git.leaktechnologies.dev/stu/Goondex/internal/sync"
	"git.leaktechnologies.dev/stu/Goondex/internal/web"
	"github.com/spf13/cobra"
)

const tpdbAPIKeyEnvVar = "TPDB_API_KEY"
const tpdbEnabled = true

var (
	dbPath  string
	rootCmd = &cobra.Command{
		Use:   "goondex",
		Short: "Goondex - Fast, local-first media indexer",
		Long:  `Goondex is a fast, local-first media indexer for adult content that ingests metadata from external sources.`,
	}
)

func init() {
	rootCmd.PersistentFlags().StringVar(&dbPath, "db", "./goondex.db", "Path to SQLite database")

	// Add subcommands
	rootCmd.AddCommand(performerSearchCmd)
	rootCmd.AddCommand(performerGetCmd)
	rootCmd.AddCommand(performerUpdateCmd)
	rootCmd.AddCommand(studioSearchCmd)
	rootCmd.AddCommand(studioGetCmd)
	rootCmd.AddCommand(sceneSearchCmd)
	rootCmd.AddCommand(sceneGetCmd)
	rootCmd.AddCommand(importCmd)
	rootCmd.AddCommand(syncCmd)
	rootCmd.AddCommand(adultempCmd)
	rootCmd.AddCommand(webCmd)
	rootCmd.AddCommand(enrichCmd)
	rootCmd.AddCommand(versionCmd)
	performerSearchCmd.Flags().Bool("show-bio", false, "Show performer bio in search results")
	performerGetCmd.Flags().Bool("show-bio", false, "Show performer bio")
	webCmd.Flags().String("addr", "localhost:8788", "Address to listen on")

	// Sync command flags
	syncCmd.PersistentFlags().Bool("force", false, "Force sync even if rate limit not met")
	syncCmd.PersistentFlags().Duration("interval", 1*time.Hour, "Minimum interval between syncs (default 1h, recommended 24h)")
}

// Import command with subcommands
var importCmd = &cobra.Command{
	Use:   "import",
	Short: "Import data (Adult Empire available; TPDB disabled)",
	Long:  `Adult Empire import commands are available. TPDB bulk import commands are temporarily disabled while we focus on Adult Empire data.`,
}

var importAllCmd = &cobra.Command{
	Use:   "all",
	Short: "Import all TPDB performers, studios, and scenes",
	Long: `Run the performer, studio, and scene bulk imports sequentially to ingest the entire TPDB catalog.

Use the per-entity pagination flags to resume or limit parts of the import.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		performerStart, _ := cmd.Flags().GetInt("performer-start-page")
		performerMax, _ := cmd.Flags().GetInt("performer-max-pages")
		studioStart, _ := cmd.Flags().GetInt("studio-start-page")
		studioMax, _ := cmd.Flags().GetInt("studio-max-pages")
		sceneStart, _ := cmd.Flags().GetInt("scene-start-page")
		sceneMax, _ := cmd.Flags().GetInt("scene-max-pages")

		// Propagate flag values to the existing per-entity commands
		if err := importAllPerformersCmd.Flags().Set("start-page", strconv.Itoa(performerStart)); err != nil {
			return fmt.Errorf("failed to set performer start page: %w", err)
		}
		if err := importAllPerformersCmd.Flags().Set("max-pages", strconv.Itoa(performerMax)); err != nil {
			return fmt.Errorf("failed to set performer max pages: %w", err)
		}
		if err := importAllStudiosCmd.Flags().Set("start-page", strconv.Itoa(studioStart)); err != nil {
			return fmt.Errorf("failed to set studio start page: %w", err)
		}
		if err := importAllStudiosCmd.Flags().Set("max-pages", strconv.Itoa(studioMax)); err != nil {
			return fmt.Errorf("failed to set studio max pages: %w", err)
		}
		if err := importAllScenesCmd.Flags().Set("start-page", strconv.Itoa(sceneStart)); err != nil {
			return fmt.Errorf("failed to set scene start page: %w", err)
		}
		if err := importAllScenesCmd.Flags().Set("max-pages", strconv.Itoa(sceneMax)); err != nil {
			return fmt.Errorf("failed to set scene max pages: %w", err)
		}

		fmt.Println("╔═══════════════════════════════════════════════════════════════╗")
		fmt.Println("║              TPDB BULK IMPORT - ALL ENTITIES                  ║")
		fmt.Println("╚═══════════════════════════════════════════════════════════════╝")

		fmt.Println("\n➡ Importing performers...")
		if err := importAllPerformersCmd.RunE(importAllPerformersCmd, []string{}); err != nil {
			return fmt.Errorf("performer import failed: %w", err)
		}

		fmt.Println("\n➡ Importing studios...")
		if err := importAllStudiosCmd.RunE(importAllStudiosCmd, []string{}); err != nil {
			return fmt.Errorf("studio import failed: %w", err)
		}

		fmt.Println("\n➡ Importing scenes...")
		if err := importAllScenesCmd.RunE(importAllScenesCmd, []string{}); err != nil {
			return fmt.Errorf("scene import failed: %w", err)
		}

		fmt.Println("\n✓ Completed TPDB bulk import for performers, studios, and scenes")
		return nil
	},
}

func init() {
	importCmd.AddCommand(importPerformerCmd)
	importCmd.AddCommand(importAllPerformersCmd)
	importCmd.AddCommand(importStudioCmd)
	importCmd.AddCommand(importAllStudiosCmd)
	importCmd.AddCommand(importSceneCmd)
	importCmd.AddCommand(importAllScenesCmd)
	importCmd.AddCommand(importMovieCmd)
	importCmd.AddCommand(importAllCmd)

	// Flags for bulk import
	importAllPerformersCmd.Flags().Int("start-page", 1, "Page to start from (for resuming)")
	importAllPerformersCmd.Flags().Int("max-pages", 0, "Maximum pages to import (0 = all)")
	importAllStudiosCmd.Flags().Int("start-page", 1, "Page to start from (for resuming)")
	importAllStudiosCmd.Flags().Int("max-pages", 0, "Maximum pages to import (0 = all)")
	importAllScenesCmd.Flags().Int("start-page", 1, "Page to start from (for resuming)")
	importAllScenesCmd.Flags().Int("max-pages", 0, "Maximum pages to import (0 = all)")
	importAllCmd.Flags().Int("performer-start-page", 1, "Performer import start page (for resuming)")
	importAllCmd.Flags().Int("performer-max-pages", 0, "Maximum performer pages to import (0 = all)")
	importAllCmd.Flags().Int("studio-start-page", 1, "Studio import start page (for resuming)")
	importAllCmd.Flags().Int("studio-max-pages", 0, "Maximum studio pages to import (0 = all)")
	importAllCmd.Flags().Int("scene-start-page", 1, "Scene import start page (for resuming)")
	importAllCmd.Flags().Int("scene-max-pages", 0, "Maximum scene pages to import (0 = all)")

	// Movie import flags
	importMovieCmd.Flags().String("source", "adultemp", "Source to import from (adultemp)")
}

// Sync command with subcommands
var syncCmd = &cobra.Command{
	Use:   "sync",
	Short: "Sync and update existing data (TPDB disabled for now)",
	Long: `TPDB-based sync is temporarily disabled while we prioritize Adult Empire as the main source.

Existing sync commands are left in place for when TPDB is re-enabled, but they will currently return a disabled message.`,
}

func init() {
	syncCmd.AddCommand(syncAllCmd)
	syncCmd.AddCommand(syncPerformersCmd)
	syncCmd.AddCommand(syncStudiosCmd)
	syncCmd.AddCommand(syncScenesCmd)
	syncCmd.AddCommand(syncStatusCmd)
}

var syncAllCmd = &cobra.Command{
	Use:   "all",
	Short: "Sync all entities (performers, studios, scenes)",
	RunE: func(cmd *cobra.Command, args []string) error {
		force, _ := cmd.Flags().GetBool("force")
		interval, _ := cmd.Flags().GetDuration("interval")

		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
		service := sync.NewService(database, scraper)

		opts := sync.SyncOptions{
			Force:       force,
			MinInterval: interval,
		}

		fmt.Printf("Starting sync with %s minimum interval...\n", interval)
		if force {
			fmt.Println("⚠ Force mode enabled - ignoring rate limits")
		}
		fmt.Println()

		results, err := service.SyncAll(context.Background(), opts)
		if err != nil {
			return err
		}

		// Display results
		for _, r := range results {
			fmt.Printf("═══ %s ═══\n", r.EntityType)
			if r.ErrorMessage != "" {
				fmt.Printf("⚠ %s\n", r.ErrorMessage)
			} else {
				fmt.Printf("✓ Updated: %d\n", r.Updated)
				if r.Failed > 0 {
					fmt.Printf("✗ Failed: %d\n", r.Failed)
				}
				if r.Skipped > 0 {
					fmt.Printf("- Skipped: %d\n", r.Skipped)
				}
				fmt.Printf("⏱ Duration: %s\n", r.Duration.Round(time.Second))
			}
			fmt.Println()
		}

		return nil
	},
}

var syncPerformersCmd = &cobra.Command{
	Use:   "performers",
	Short: "Sync performers only",
	RunE: func(cmd *cobra.Command, args []string) error {
		force, _ := cmd.Flags().GetBool("force")
		interval, _ := cmd.Flags().GetDuration("interval")

		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
		service := sync.NewService(database, scraper)

		opts := sync.SyncOptions{
			Force:       force,
			MinInterval: interval,
		}

		fmt.Printf("Syncing performers...\n")
		result, err := service.SyncPerformers(context.Background(), opts)
		if err != nil {
			return err
		}

		if result.ErrorMessage != "" {
			fmt.Printf("⚠ %s\n", result.ErrorMessage)
		} else {
			fmt.Printf("✓ Updated: %d\n", result.Updated)
			if result.Failed > 0 {
				fmt.Printf("✗ Failed: %d\n", result.Failed)
			}
			if result.Skipped > 0 {
				fmt.Printf("- Skipped: %d\n", result.Skipped)
			}
			fmt.Printf("⏱ Duration: %s\n", result.Duration.Round(time.Second))
		}

		return nil
	},
}

var syncStudiosCmd = &cobra.Command{
	Use:   "studios",
	Short: "Sync studios only",
	RunE: func(cmd *cobra.Command, args []string) error {
		force, _ := cmd.Flags().GetBool("force")
		interval, _ := cmd.Flags().GetDuration("interval")

		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
		service := sync.NewService(database, scraper)

		opts := sync.SyncOptions{
			Force:       force,
			MinInterval: interval,
		}

		fmt.Printf("Syncing studios...\n")
		result, err := service.SyncStudios(context.Background(), opts)
		if err != nil {
			return err
		}

		if result.ErrorMessage != "" {
			fmt.Printf("⚠ %s\n", result.ErrorMessage)
		} else {
			fmt.Printf("✓ Updated: %d\n", result.Updated)
			if result.Failed > 0 {
				fmt.Printf("✗ Failed: %d\n", result.Failed)
			}
			if result.Skipped > 0 {
				fmt.Printf("- Skipped: %d\n", result.Skipped)
			}
			fmt.Printf("⏱ Duration: %s\n", result.Duration.Round(time.Second))
		}

		return nil
	},
}

var syncScenesCmd = &cobra.Command{
	Use:   "scenes",
	Short: "Sync scenes only",
	RunE: func(cmd *cobra.Command, args []string) error {
		force, _ := cmd.Flags().GetBool("force")
		interval, _ := cmd.Flags().GetDuration("interval")

		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
		service := sync.NewService(database, scraper)

		opts := sync.SyncOptions{
			Force:       force,
			MinInterval: interval,
		}

		fmt.Printf("Syncing scenes...\n")
		result, err := service.SyncScenes(context.Background(), opts)
		if err != nil {
			return err
		}

		if result.ErrorMessage != "" {
			fmt.Printf("⚠ %s\n", result.ErrorMessage)
		} else {
			fmt.Printf("✓ Updated: %d\n", result.Updated)
			if result.Failed > 0 {
				fmt.Printf("✗ Failed: %d\n", result.Failed)
			}
			if result.Skipped > 0 {
				fmt.Printf("- Skipped: %d\n", result.Skipped)
			}
			fmt.Printf("⏱ Duration: %s\n", result.Duration.Round(time.Second))
		}

		return nil
	},
}

var syncStatusCmd = &cobra.Command{
	Use:   "status",
	Short: "View sync status and last sync times",
	RunE: func(cmd *cobra.Command, args []string) error {
		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		scraper := tpdb.NewScraper("https://api.theporndb.net", "")
		service := sync.NewService(database, scraper)

		statuses, err := service.GetSyncStatus()
		if err != nil {
			return err
		}

		if len(statuses) == 0 {
			fmt.Println("No sync history found.")
			fmt.Println("\nRun 'goondex sync all' to perform your first sync.")
			return nil
		}

		fmt.Println("Sync Status:")
		fmt.Println()

		for _, s := range statuses {
			fmt.Printf("═══ %s ═══\n", s.EntityType)
			fmt.Printf("Status: %s\n", s.Status)
			fmt.Printf("Last Sync: %s\n", s.LastSyncAt.Format("2006-01-02 15:04:05"))
			fmt.Printf("Updated: %d\n", s.RecordsUpdated)
			if s.RecordsFailed > 0 {
				fmt.Printf("Failed: %d\n", s.RecordsFailed)
			}
			if s.ErrorMessage != "" {
				fmt.Printf("Error: %s\n", s.ErrorMessage)
			}

			// Calculate time since last sync
			timeSince := time.Since(s.LastSyncAt)
			fmt.Printf("Time since last sync: %s\n", formatDuration(timeSince))

			fmt.Println()
		}

		return nil
	},
}

func formatDuration(d time.Duration) string {
	if d < time.Minute {
		return fmt.Sprintf("%d seconds", int(d.Seconds()))
	}
	if d < time.Hour {
		return fmt.Sprintf("%d minutes", int(d.Minutes()))
	}
	if d < 24*time.Hour {
		return fmt.Sprintf("%d hours", int(d.Hours()))
	}
	return fmt.Sprintf("%d days", int(d.Hours()/24))
}

func getTPDBAPIKey() (string, error) {
	if !tpdbEnabled {
		return "", fmt.Errorf("TPDB integration is disabled. Use Adult Empire commands (e.g., 'goondex adultemp search-performer' and 'goondex adultemp scrape-performer <url>') to import data instead.")
	}

	apiKey := config.GetAPIKeys().TPDBAPIKey
	if apiKey == "" {
		return "", fmt.Errorf("%s environment variable is not set.\n%s", tpdbAPIKeyEnvVar, apiKeySetupInstructions())
	}
	return apiKey, nil
}

func apiKeySetupInstructions() string {
	return fmt.Sprintf("Set it by running:\n\n  export %s=\"your-api-key\"", tpdbAPIKeyEnvVar)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}

func getDB() (*db.DB, error) {
	database, err := db.Open(dbPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open database: %w", err)
	}
	return database, nil
}

var webCmd = &cobra.Command{
	Use:   "web",
	Short: "Start the web UI server",
	Long:  `Start a web server that provides a visual interface for browsing your Goondex database.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		addr, _ := cmd.Flags().GetString("addr")

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		server, err := web.NewServer(database, addr, dbPath)
		if err != nil {
			return fmt.Errorf("failed to create web server: %w", err)
		}

		return server.Start()
	},
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print version information",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Goondex v0.1.0-dev5")
		fmt.Println("Features:")
		fmt.Println("  • Adult Empire scraper (scenes & performers)")
		fmt.Println("  • TPDB commands temporarily disabled (Adult Empire-only mode)")
		fmt.Println("  • Multi-source data merging (when TPDB is re-enabled)")
		fmt.Println("  • Grid-based web UI with GX components")
		fmt.Println("  • Performer/studio/scene management")
	},
}

var performerSearchCmd = &cobra.Command{
	Use:   "performer-search [query]",
	Short: "Search for performers (imports from Adult Empire if missing locally)",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		query := args[0]
		showBio, _ := cmd.Flags().GetBool("show-bio")

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		store := db.NewPerformerStore(database)
		performers, err := store.Search(query)
		if err != nil {
			return fmt.Errorf("search failed: %w", err)
		}

		// If no local results, pull the top Adult Empire match
		if len(performers) == 0 {
			fmt.Printf("No local results found. Searching Adult Empire for '%s'...\n", query)

			scraper, err := adultemp.NewScraper()
			if err != nil {
				return fmt.Errorf("failed to create Adult Empire scraper: %w", err)
			}

			results, err := scraper.SearchPerformersByName(context.Background(), query)
			if err != nil {
				fmt.Printf("⚠ Adult Empire search failed: %v\n", err)
				return nil
			}

			if len(results) == 0 {
				fmt.Println("No performers found on Adult Empire either.")
				return nil
			}

			fmt.Printf("Found %d performer(s) on Adult Empire. Importing the top match...\n\n", len(results))

			// Import only the top result to avoid wrong matches; use search-performer for manual selection
			top := results[0]
			performerData, err := scraper.ScrapePerformerByURL(context.Background(), top.URL)
			if err != nil {
				fmt.Printf("⚠ Failed to fetch Adult Empire details: %v\n", err)
				return nil
			}

			performer := scraper.ConvertPerformerToModel(performerData)
			if err := store.Create(performer); err != nil {
				fmt.Printf("⚠ Failed to import %s: %v\n", performer.Name, err)
			} else {
				fmt.Printf("✓ Imported %s from Adult Empire\n", performer.Name)
			}

			// Search again to get the imported performer with their ID
			performers, err = store.Search(query)
			if err != nil {
				return fmt.Errorf("search failed after import: %w", err)
			}

			if len(performers) == 0 {
				fmt.Println("No performers matched locally even after Adult Empire import.")
				return nil
			}

			if len(results) > 1 {
				fmt.Println("Tip: run 'goondex adultemp search-performer \"<name>\"' to pick a different match.")
			}

			imported := 1
			fmt.Printf("\n✓ Imported %d performer(s)\n\n", imported)
		}

		fmt.Printf("Found %d performer(s):\n\n", len(performers))
		for _, p := range performers {
			fmt.Printf("═══════════════════════════════════════════════════\n")
			fmt.Printf("Name: %s\n", p.Name)
			if p.Aliases != "" {
				fmt.Printf("Aliases: %s\n", p.Aliases)
			}
			fmt.Printf("\n")

			// IDs
			fmt.Printf("Local ID: %d\n", p.ID)
			if p.Source != "" {
				fmt.Printf("Source: %s\n", p.Source)
				fmt.Printf("UUID: %s\n", p.SourceID)
				if p.SourceNumericID > 0 {
					fmt.Printf("TPDB ID: %d\n", p.SourceNumericID)
				}
			}
			fmt.Printf("\n")

			// Stats
			sceneCount, err := store.GetSceneCount(p.ID)
			if err != nil {
				fmt.Printf("⚠ Failed to get scene count: %v\n", err)
			} else {
				fmt.Printf("Scenes: %d\n", sceneCount)
			}
			fmt.Printf("\n")

			// Personal info
			if p.Gender != "" {
				fmt.Printf("Gender: %s\n", p.Gender)
			}
			if p.Birthday != "" {
				fmt.Printf("Birthday: %s\n", p.Birthday)
			}
			if p.Astrology != "" {
				fmt.Printf("Astrology: %s\n", p.Astrology)
			}
			if p.DateOfDeath != "" {
				fmt.Printf("Date of Death: %s\n", p.DateOfDeath)
			}
			if p.Career != "" {
				fmt.Printf("Career: %s\n", p.Career)
			}
			if p.Birthplace != "" {
				fmt.Printf("Birthplace: %s\n", p.Birthplace)
			}
			if p.Ethnicity != "" {
				fmt.Printf("Ethnicity: %s\n", p.Ethnicity)
			}
			if p.Nationality != "" {
				fmt.Printf("Nationality: %s\n", p.Nationality)
			}
			fmt.Printf("\n")

			// Physical attributes
			if p.CupSize != "" {
				fmt.Printf("Cup Size: %s\n", p.CupSize)
			}
			if p.HairColor != "" {
				fmt.Printf("Hair Colour: %s\n", p.HairColor)
			}
			if p.EyeColor != "" {
				fmt.Printf("Eye Colour: %s\n", p.EyeColor)
			}
			if p.Height > 0 {
				feet := float64(p.Height) / 30.48
				inches := (float64(p.Height) / 2.54) - (feet * 12)
				fmt.Printf("Height: %dcm (%.0f'%.0f\")\n", p.Height, feet, inches)
			}
			if p.Weight > 0 {
				lbs := float64(p.Weight) * 2.20462
				fmt.Printf("Weight: %dkg (%.0flb)\n", p.Weight, lbs)
			}
			if p.Measurements != "" {
				fmt.Printf("Measurements: %s\n", p.Measurements)
			}
			if p.TattooDescription != "" {
				fmt.Printf("Tattoos: %s\n", p.TattooDescription)
			}
			if p.PiercingDescription != "" {
				fmt.Printf("Piercings: %s\n", p.PiercingDescription)
			}
			if p.BoobJob != "" {
				fmt.Printf("Fake Boobs: %s\n", p.BoobJob)
			}
			fmt.Printf("\n")

			// Bio
			if showBio && p.Bio != "" {
				fmt.Printf("Bio:\n%s\n\n", p.Bio)
			}

			// Media
			if p.ImageURL != "" {
				fmt.Printf("Image: %s\n", p.ImageURL)
			}
			if p.PosterURL != "" {
				fmt.Printf("Poster: %s\n", p.PosterURL)
			}

			fmt.Printf("═══════════════════════════════════════════════════\n\n")
		}

		return nil
	},
}

var performerUpdateCmd = &cobra.Command{
	Use:   "performer-update [id]",
	Short: "Update/refresh performer data from TPDB and Adult Empire",
	Long:  `Update an existing performer with the latest data from TPDB and optionally merge with Adult Empire data.`,
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		// Parse ID
		var performerID int64
		if _, err := fmt.Sscanf(args[0], "%d", &performerID); err != nil {
			return fmt.Errorf("invalid performer ID: %s", args[0])
		}

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		performerStore := db.NewPerformerStore(database)

		// Get existing performer
		performer, err := performerStore.GetByID(performerID)
		if err != nil {
			return fmt.Errorf("performer not found: %w", err)
		}

		fmt.Printf("Updating performer: %s (ID: %d)\n", performer.Name, performer.ID)

		// Update from TPDB if available
		if performer.Source == "tpdb" && performer.SourceID != "" {
			apiKey, err := getTPDBAPIKey()
			if err != nil {
				fmt.Printf("⚠ %s\n", err)
			} else {
				fmt.Println("📥 Fetching latest data from TPDB...")
				scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)

				updatedPerformer, err := scraper.GetPerformerByID(context.Background(), performer.SourceID)
				if err != nil {
					fmt.Printf("⚠ Failed to fetch from TPDB: %v\n", err)
				} else {
					// Preserve local ID
					updatedPerformer.ID = performer.ID

					if err := performerStore.Update(updatedPerformer); err != nil {
						fmt.Printf("⚠ Failed to update: %v\n", err)
					} else {
						fmt.Println("✓ Updated from TPDB")
						performer = updatedPerformer
					}
				}
			}
		}

		// Optionally search Adult Empire for additional data
		fmt.Printf("\n🔍 Searching Adult Empire for '%s'...\n", performer.Name)

		adultempScraper, err := adultemp.NewScraper()
		if err != nil {
			fmt.Printf("⚠ Failed to create Adult Empire scraper: %v\n", err)
			return nil
		}

		results, err := adultempScraper.SearchPerformersByName(context.Background(), performer.Name)
		if err != nil {
			fmt.Printf("⚠ Adult Empire search failed: %v\n", err)
			return nil
		}

		if len(results) == 0 {
			fmt.Println("No matches found on Adult Empire")
			return nil
		}

		fmt.Printf("\nFound %d potential match(es) on Adult Empire:\n", len(results))
		for i, result := range results {
			fmt.Printf("%d. %s - %s\n", i+1, result.Title, result.URL)
		}

		fmt.Println("\n✓ Performer data refreshed successfully")
		fmt.Println("Note: Use 'adultemp scrape-performer <url>' to import specific Adult Empire data")

		return nil
	},
}

var performerGetCmd = &cobra.Command{
	Use:   "performer-get [id]",
	Short: "Get detailed information about a performer by ID",
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		// Parse ID
		var performerID int64
		if _, err := fmt.Sscanf(args[0], "%d", &performerID); err != nil {
			return fmt.Errorf("invalid performer ID: %s", args[0])
		}

		showBio, _ := cmd.Flags().GetBool("show-bio")

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		store := db.NewPerformerStore(database)

		// Get performer
		performer, err := store.GetByID(performerID)
		if err != nil {
			return fmt.Errorf("performer not found: %w", err)
		}

		// Get scene count
		sceneCount, err := store.GetSceneCount(performerID)
		if err != nil {
			fmt.Printf("⚠ Failed to get scene count: %v\n", err)
			sceneCount = 0
		}

		// Display performer information (reusing the format from performer-search)
		fmt.Printf("═══════════════════════════════════════════════════\n")
		fmt.Printf("Name: %s\n", performer.Name)
		if performer.Aliases != "" {
			fmt.Printf("Aliases: %s\n", performer.Aliases)
		}
		fmt.Printf("\n")

		// IDs
		fmt.Printf("Local ID: %d\n", performer.ID)
		if performer.Source != "" {
			fmt.Printf("Source: %s\n", performer.Source)
			fmt.Printf("UUID: %s\n", performer.SourceID)
			if performer.SourceNumericID > 0 {
				fmt.Printf("TPDB ID: %d\n", performer.SourceNumericID)
			}
		}
		fmt.Printf("\n")

		// Stats
		fmt.Printf("Scenes: %d\n", sceneCount)
		fmt.Printf("\n")

		// Personal info
		if performer.Gender != "" {
			fmt.Printf("Gender: %s\n", performer.Gender)
		}
		if performer.Birthday != "" {
			fmt.Printf("Birthday: %s\n", performer.Birthday)
		}
		if performer.Astrology != "" {
			fmt.Printf("Astrology: %s\n", performer.Astrology)
		}
		if performer.DateOfDeath != "" {
			fmt.Printf("Date of Death: %s\n", performer.DateOfDeath)
		}
		if performer.Career != "" {
			fmt.Printf("Career: %s\n", performer.Career)
		}
		if performer.Birthplace != "" {
			fmt.Printf("Birthplace: %s\n", performer.Birthplace)
		}
		if performer.Ethnicity != "" {
			fmt.Printf("Ethnicity: %s\n", performer.Ethnicity)
		}
		if performer.Nationality != "" {
			fmt.Printf("Nationality: %s\n", performer.Nationality)
		}
		fmt.Printf("\n")

		// Physical attributes
		if performer.CupSize != "" {
			fmt.Printf("Cup Size: %s\n", performer.CupSize)
		}
		if performer.HairColor != "" {
			fmt.Printf("Hair Colour: %s\n", performer.HairColor)
		}
		if performer.EyeColor != "" {
			fmt.Printf("Eye Colour: %s\n", performer.EyeColor)
		}
		if performer.Height > 0 {
			feet := float64(performer.Height) / 30.48
			inches := (float64(performer.Height) / 2.54) - (feet * 12)
			fmt.Printf("Height: %dcm (%.0f'%.0f\")\n", performer.Height, feet, inches)
		}
		if performer.Weight > 0 {
			lbs := float64(performer.Weight) * 2.20462
			fmt.Printf("Weight: %dkg (%.0flb)\n", performer.Weight, lbs)
		}
		if performer.Measurements != "" {
			fmt.Printf("Measurements: %s\n", performer.Measurements)
		}
		if performer.TattooDescription != "" {
			fmt.Printf("Tattoos: %s\n", performer.TattooDescription)
		}
		if performer.PiercingDescription != "" {
			fmt.Printf("Piercings: %s\n", performer.PiercingDescription)
		}
		if performer.BoobJob != "" {
			fmt.Printf("Fake Boobs: %s\n", performer.BoobJob)
		}
		fmt.Printf("\n")

		// Bio
		if showBio && performer.Bio != "" {
			fmt.Printf("Bio:\n%s\n\n", performer.Bio)
		}

		// Media
		if performer.ImageURL != "" {
			fmt.Printf("Image: %s\n", performer.ImageURL)
		}
		if performer.PosterURL != "" {
			fmt.Printf("Poster: %s\n", performer.PosterURL)
		}

		// Timestamps
		fmt.Printf("\n")
		fmt.Printf("Created: %s\n", performer.CreatedAt.Format("2006-01-02 15:04:05"))
		fmt.Printf("Updated: %s\n", performer.UpdatedAt.Format("2006-01-02 15:04:05"))

		fmt.Printf("═══════════════════════════════════════════════════\n\n")

		return nil
	},
}

var studioSearchCmd = &cobra.Command{
	Use:   "studio-search [query]",
	Short: "Search for studios (local database only; TPDB disabled)",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		query := args[0]

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		store := db.NewStudioStore(database)
		studios, err := store.Search(query)
		if err != nil {
			return fmt.Errorf("search failed: %w", err)
		}

		fmt.Printf("Found %d studio(s):\n\n", len(studios))
		for _, s := range studios {
			fmt.Printf("ID: %d\n", s.ID)
			fmt.Printf("Name: %s\n", s.Name)
			if s.Description != "" {
				fmt.Printf("Description: %s\n", s.Description)
			}
			if s.Source != "" {
				fmt.Printf("Source: %s (ID: %s)\n", s.Source, s.SourceID)
			}
			fmt.Println("---")
		}

		return nil
	},
}

var studioGetCmd = &cobra.Command{
	Use:   "studio-get [id]",
	Short: "Get detailed information about a studio by ID",
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		// Parse ID
		var studioID int64
		if _, err := fmt.Sscanf(args[0], "%d", &studioID); err != nil {
			return fmt.Errorf("invalid studio ID: %s", args[0])
		}

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		store := db.NewStudioStore(database)

		// Get studio
		studio, err := store.GetByID(studioID)
		if err != nil {
			return fmt.Errorf("studio not found: %w", err)
		}

		// Get scene count
		sceneCount, err := store.GetSceneCount(studioID)
		if err != nil {
			fmt.Printf("⚠ Failed to get scene count: %v\n", err)
			sceneCount = 0
		}

		// Display studio information
		fmt.Printf("═══════════════════════════════════════════════════\n")
		fmt.Printf("Studio Details\n")
		fmt.Printf("═══════════════════════════════════════════════════\n\n")

		fmt.Printf("ID: %d\n", studio.ID)
		fmt.Printf("Name: %s\n", studio.Name)

		if studio.Description != "" {
			fmt.Printf("\nDescription:\n%s\n", studio.Description)
		}

		fmt.Printf("\n")
		fmt.Printf("Scenes: %d\n", sceneCount)

		// Parent studio
		if studio.ParentID != nil && *studio.ParentID > 0 {
			parentStudio, err := store.GetByID(*studio.ParentID)
			if err == nil {
				fmt.Printf("Parent Studio: %s (ID: %d)\n", parentStudio.Name, parentStudio.ID)
			} else {
				fmt.Printf("Parent Studio ID: %d\n", *studio.ParentID)
			}
		}

		// Source information
		if studio.Source != "" {
			fmt.Printf("\n")
			fmt.Printf("Source: %s\n", studio.Source)
			fmt.Printf("Source ID: %s\n", studio.SourceID)
		}

		// Media
		if studio.ImageURL != "" {
			fmt.Printf("\n")
			fmt.Printf("Image: %s\n", studio.ImageURL)
		}
		if studio.ImagePath != "" {
			fmt.Printf("Image Path: %s\n", studio.ImagePath)
		}

		// Timestamps
		fmt.Printf("\n")
		fmt.Printf("Created: %s\n", studio.CreatedAt.Format("2006-01-02 15:04:05"))
		fmt.Printf("Updated: %s\n", studio.UpdatedAt.Format("2006-01-02 15:04:05"))

		fmt.Printf("\n═══════════════════════════════════════════════════\n")

		return nil
	},
}

var sceneSearchCmd = &cobra.Command{
	Use:   "scene-search [query]",
	Short: "Search for scenes (local database only; TPDB disabled)",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		query := args[0]

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		store := db.NewSceneStore(database)
		scenes, err := store.Search(query)
		if err != nil {
			return fmt.Errorf("search failed: %w", err)
		}

		fmt.Printf("Found %d scene(s):\n\n", len(scenes))
		for _, sc := range scenes {
			fmt.Printf("ID: %d\n", sc.ID)
			fmt.Printf("Title: %s\n", sc.Title)
			if sc.Code != "" {
				fmt.Printf("Code: %s\n", sc.Code)
			}
			if sc.Date != "" {
				fmt.Printf("Date: %s\n", sc.Date)
			}
			if sc.Description != "" {
				fmt.Printf("Description: %s\n", sc.Description)
			}
			if sc.Source != "" {
				fmt.Printf("Source: %s (ID: %s)\n", sc.Source, sc.SourceID)
			}
			fmt.Println("---")
		}

		return nil
	},
}

var sceneGetCmd = &cobra.Command{
	Use:   "scene-get [id]",
	Short: "Get detailed information about a scene by ID",
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		// Parse ID
		var sceneID int64
		if _, err := fmt.Sscanf(args[0], "%d", &sceneID); err != nil {
			return fmt.Errorf("invalid scene ID: %s", args[0])
		}

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		sceneStore := db.NewSceneStore(database)
		studioStore := db.NewStudioStore(database)

		// Get scene
		scene, err := sceneStore.GetByID(sceneID)
		if err != nil {
			return fmt.Errorf("scene not found: %w", err)
		}

		// Get performers
		performers, err := sceneStore.GetPerformers(sceneID)
		if err != nil {
			fmt.Printf("⚠ Failed to get performers: %v\n", err)
		}

		// Get tags
		tags, err := sceneStore.GetTags(sceneID)
		if err != nil {
			fmt.Printf("⚠ Failed to get tags: %v\n", err)
		}

		// Get studio if present
		var studio *model.Studio
		if scene.StudioID != nil && *scene.StudioID > 0 {
			studio, err = studioStore.GetByID(*scene.StudioID)
			if err != nil {
				fmt.Printf("⚠ Failed to get studio: %v\n", err)
			}
		}

		// Display scene information
		fmt.Printf("═══════════════════════════════════════════════════\n")
		fmt.Printf("Scene Details\n")
		fmt.Printf("═══════════════════════════════════════════════════\n\n")

		fmt.Printf("ID: %d\n", scene.ID)
		fmt.Printf("Title: %s\n", scene.Title)

		if scene.Code != "" {
			fmt.Printf("Code: %s\n", scene.Code)
		}

		if scene.Date != "" {
			fmt.Printf("Date: %s\n", scene.Date)
		}

		if scene.Director != "" {
			fmt.Printf("Director: %s\n", scene.Director)
		}

		fmt.Printf("\n")

		// Studio
		if studio != nil {
			fmt.Printf("Studio: %s (ID: %d)\n", studio.Name, studio.ID)
		}

		// Performers
		if len(performers) > 0 {
			fmt.Printf("\nPerformers (%d):\n", len(performers))
			for _, p := range performers {
				fmt.Printf("  - %s (ID: %d)\n", p.Name, p.ID)
			}
		}

		// Tags
		if len(tags) > 0 {
			fmt.Printf("\nTags (%d):\n", len(tags))
			for _, t := range tags {
				fmt.Printf("  - %s\n", t.Name)
			}
		}

		// Description
		if scene.Description != "" {
			fmt.Printf("\nDescription:\n%s\n", scene.Description)
		}

		// Source information
		if scene.Source != "" {
			fmt.Printf("\n")
			fmt.Printf("Source: %s\n", scene.Source)
			fmt.Printf("Source ID: %s\n", scene.SourceID)
		}

		// Media
		if scene.URL != "" {
			fmt.Printf("\nURL: %s\n", scene.URL)
		}
		if scene.ImageURL != "" {
			fmt.Printf("Image: %s\n", scene.ImageURL)
		}
		if scene.ImagePath != "" {
			fmt.Printf("Image Path: %s\n", scene.ImagePath)
		}

		// Timestamps
		fmt.Printf("\n")
		fmt.Printf("Created: %s\n", scene.CreatedAt.Format("2006-01-02 15:04:05"))
		fmt.Printf("Updated: %s\n", scene.UpdatedAt.Format("2006-01-02 15:04:05"))

		fmt.Printf("\n═══════════════════════════════════════════════════\n")

		return nil
	},
}

var importAllPerformersCmd = &cobra.Command{
	Use:   "all-performers",
	Short: "Import ALL performers from TPDB (paginated)",
	Long:  `Import all 10,000+ performers from ThePornDB by paginating through all pages. This may take a while.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		startPage, _ := cmd.Flags().GetInt("start-page")
		maxPages, _ := cmd.Flags().GetInt("max-pages")

		// Get API key from environment
		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		// Create TPDB scraper
		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)

		// Open database
		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		performerStore := db.NewPerformerStore(database)

		fmt.Println("╔═══════════════════════════════════════════════════════════════╗")
		fmt.Println("║        TPDB BULK PERFORMER IMPORT                             ║")
		fmt.Println("╚═══════════════════════════════════════════════════════════════╝")
		fmt.Println()

		totalImported := 0
		totalFailed := 0
		totalSkipped := 0
		currentPage := startPage

		for {
			fmt.Printf("📥 Fetching page %d...\n", currentPage)

			performers, meta, err := scraper.ListPerformers(context.Background(), currentPage)
			if err != nil {
				fmt.Printf("⚠ Failed to fetch page %d: %v\n", currentPage, err)
				totalFailed++
				currentPage++
				continue
			}

			if meta == nil {
				fmt.Println("⚠ No metadata returned")
				break
			}

			fmt.Printf("   Page %d/%d | Total: %d performers | Per page: %d\n",
				meta.CurrentPage, meta.LastPage, meta.Total, meta.PerPage)

			// Import performers from this page
			pageImported := 0
			pageFailed := 0
			pageSkipped := 0

			for _, p := range performers {
				// Check if already exists
				existing, _ := performerStore.GetBySourceID("tpdb", p.SourceID)
				if existing != nil {
					pageSkipped++
					totalSkipped++
					continue
				}

				if err := performerStore.Create(&p); err != nil {
					fmt.Printf("   ⚠ Failed to import %s: %v\n", p.Name, err)
					pageFailed++
					totalFailed++
					continue
				}
				pageImported++
				totalImported++
			}

			fmt.Printf("   ✓ Imported: %d | ⚠ Failed: %d | ⊘ Skipped: %d\n\n",
				pageImported, pageFailed, pageSkipped)

			// Check if we should stop
			if maxPages > 0 && (currentPage-startPage+1) >= maxPages {
				fmt.Printf("⏹ Reached maximum pages limit (%d)\n", maxPages)
				break
			}

			if currentPage >= meta.LastPage {
				fmt.Println("✓ Reached last page")
				break
			}

			currentPage++

			// Small delay to be nice to the API
			time.Sleep(500 * time.Millisecond)
		}

		fmt.Println()
		fmt.Println("╔═══════════════════════════════════════════════════════════════╗")
		fmt.Println("║                    IMPORT COMPLETE                            ║")
		fmt.Println("╚═══════════════════════════════════════════════════════════════╝")
		fmt.Printf("✓ Total Imported: %d\n", totalImported)
		fmt.Printf("⚠ Total Failed: %d\n", totalFailed)
		fmt.Printf("⊘ Total Skipped (already exist): %d\n", totalSkipped)
		fmt.Printf("\n💡 Tip: Run 'sqlite3 goondex.db \"SELECT COUNT(*) FROM performers\"' to check total count\n")

		return nil
	},
}

var importAllStudiosCmd = &cobra.Command{
	Use:   "all-studios",
	Short: "Import ALL studios from TPDB (paginated)",
	Long:  `Import all 60,000+ studios from ThePornDB by paginating through all pages. This may take a while.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		startPage, _ := cmd.Flags().GetInt("start-page")
		maxPages, _ := cmd.Flags().GetInt("max-pages")

		// Get API key from environment
		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		// Create TPDB scraper
		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)

		// Get database
		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		studioStore := db.NewStudioStore(database)

		fmt.Println("╔═══════════════════════════════════════════════════════════════╗")
		fmt.Println("║          TPDB BULK STUDIO IMPORT - ALL PAGES                  ║")
		fmt.Println("╚═══════════════════════════════════════════════════════════════╝")
		fmt.Printf("Starting from page: %d\n", startPage)
		if maxPages > 0 {
			fmt.Printf("Max pages: %d\n", maxPages)
		} else {
			fmt.Println("Max pages: ALL (no limit)")
		}
		fmt.Println()

		totalImported := 0
		totalFailed := 0
		totalSkipped := 0
		currentPage := startPage

		for {
			fmt.Printf("📥 Fetching page %d...\n", currentPage)

			studios, meta, err := scraper.ListStudios(context.Background(), currentPage)
			if err != nil {
				fmt.Printf("⚠ Failed to fetch page %d: %v\n", currentPage, err)
				totalFailed++
				currentPage++
				continue
			}

			if meta == nil {
				fmt.Println("⚠ No metadata returned")
				break
			}

			fmt.Printf("   Page %d/%d | Total: %d studios | Per page: %d\n",
				meta.CurrentPage, meta.LastPage, meta.Total, meta.PerPage)

			// Import studios from this page
			pageImported := 0
			pageFailed := 0
			pageSkipped := 0

			for _, st := range studios {
				// Check if already exists
				existing, _ := studioStore.GetBySourceID("tpdb", st.SourceID)
				if existing != nil {
					pageSkipped++
					totalSkipped++
					continue
				}

				if err := studioStore.Create(&st); err != nil {
					fmt.Printf("   ⚠ Failed to import %s: %v\n", st.Name, err)
					pageFailed++
					totalFailed++
					continue
				}
				pageImported++
				totalImported++
			}

			fmt.Printf("   ✓ Imported: %d | ⚠ Failed: %d | ⊘ Skipped: %d\n\n",
				pageImported, pageFailed, pageSkipped)

			// Check if we should stop
			if maxPages > 0 && (currentPage-startPage+1) >= maxPages {
				fmt.Printf("⏹ Reached maximum pages limit (%d)\n", maxPages)
				break
			}

			if currentPage >= meta.LastPage {
				fmt.Println("✓ Reached last page")
				break
			}

			currentPage++

			// Small delay to be nice to the API
			time.Sleep(500 * time.Millisecond)
		}

		fmt.Println()
		fmt.Println("╔═══════════════════════════════════════════════════════════════╗")
		fmt.Println("║                    IMPORT COMPLETE                            ║")
		fmt.Println("╚═══════════════════════════════════════════════════════════════╝")
		fmt.Printf("✓ Total Imported: %d\n", totalImported)
		fmt.Printf("⚠ Total Failed: %d\n", totalFailed)
		fmt.Printf("⊘ Total Skipped (already exist): %d\n", totalSkipped)
		fmt.Printf("\n💡 Tip: Run 'sqlite3 goondex.db \"SELECT COUNT(*) FROM studios\"' to check total count\n")

		return nil
	},
}

var importAllScenesCmd = &cobra.Command{
	Use:   "all-scenes",
	Short: "Import ALL scenes from TPDB (paginated)",
	Long:  `Import all scenes from ThePornDB by paginating through all pages. This may take a while.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		startPage, _ := cmd.Flags().GetInt("start-page")
		maxPages, _ := cmd.Flags().GetInt("max-pages")

		// Get API key from environment
		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		// Create TPDB scraper
		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)

		// Get database
		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		sceneStore := db.NewSceneStore(database)
		performerStore := db.NewPerformerStore(database)
		studioStore := db.NewStudioStore(database)
		tagStore := db.NewTagStore(database)

		fmt.Println("╔═══════════════════════════════════════════════════════════════╗")
		fmt.Println("║          TPDB BULK SCENE IMPORT - ALL PAGES                   ║")
		fmt.Println("╚═══════════════════════════════════════════════════════════════╝")
		fmt.Printf("Starting from page: %d\n", startPage)
		if maxPages > 0 {
			fmt.Printf("Max pages: %d\n", maxPages)
		} else {
			fmt.Println("Max pages: ALL (no limit)")
		}
		fmt.Println()

		totalImported := 0
		totalFailed := 0
		totalSkipped := 0
		currentPage := startPage

		for {
			fmt.Printf("📥 Fetching page %d...\n", currentPage)

			scenes, meta, err := scraper.ListScenes(context.Background(), currentPage)
			if err != nil {
				fmt.Printf("⚠ Failed to fetch page %d: %v\n", currentPage, err)
				totalFailed++
				currentPage++
				continue
			}

			if meta == nil {
				fmt.Println("⚠ No metadata returned")
				break
			}

			fmt.Printf("   Page %d/%d | Total: %d scenes | Per page: %d\n",
				meta.CurrentPage, meta.LastPage, meta.Total, meta.PerPage)

			// Import scenes from this page
			pageImported := 0
			pageFailed := 0
			pageSkipped := 0

			for _, sc := range scenes {
				// Check if already exists
				existing, _ := sceneStore.GetBySourceID("tpdb", sc.SourceID)
				if existing != nil {
					pageSkipped++
					totalSkipped++
					continue
				}

				// Import studio if not exists
				if sc.Studio != nil {
					existingStudio, _ := studioStore.GetBySourceID(sc.Studio.Source, sc.Studio.SourceID)
					if existingStudio != nil {
						sc.StudioID = &existingStudio.ID
					} else {
						if err := studioStore.Create(sc.Studio); err == nil {
							sc.StudioID = &sc.Studio.ID
						}
					}
				}

				// Create scene
				if err := sceneStore.Create(&sc); err != nil {
					fmt.Printf("   ⚠ Failed to import %s: %v\n", sc.Title, err)
					pageFailed++
					totalFailed++
					continue
				}

				// Import performers and link them
				for _, p := range sc.Performers {
					existingPerformer, _ := performerStore.GetBySourceID(p.Source, p.SourceID)
					if existingPerformer != nil {
						sceneStore.AddPerformer(sc.ID, existingPerformer.ID)
					} else {
						if err := performerStore.Create(&p); err == nil {
							sceneStore.AddPerformer(sc.ID, p.ID)
						}
					}
				}

				// Import tags and link them
				for _, t := range sc.Tags {
					existingTag, _ := tagStore.GetByName(t.Name)
					if existingTag != nil {
						sceneStore.AddTag(sc.ID, existingTag.ID)
					} else {
						if err := tagStore.Create(&t); err == nil {
							sceneStore.AddTag(sc.ID, t.ID)
						}
					}
				}

				pageImported++
				totalImported++
			}

			fmt.Printf("   ✓ Imported: %d | ⚠ Failed: %d | ⊘ Skipped: %d\n\n",
				pageImported, pageFailed, pageSkipped)

			// Check if we should stop
			if maxPages > 0 && (currentPage-startPage+1) >= maxPages {
				fmt.Printf("⏹ Reached maximum pages limit (%d)\n", maxPages)
				break
			}

			if currentPage >= meta.LastPage {
				fmt.Println("✓ Reached last page")
				break
			}

			currentPage++

			// Small delay to be nice to the API
			time.Sleep(500 * time.Millisecond)
		}

		fmt.Println()
		fmt.Println("╔═══════════════════════════════════════════════════════════════╗")
		fmt.Println("║                    IMPORT COMPLETE                            ║")
		fmt.Println("╚═══════════════════════════════════════════════════════════════╝")
		fmt.Printf("✓ Total Imported: %d\n", totalImported)
		fmt.Printf("⚠ Total Failed: %d\n", totalFailed)
		fmt.Printf("⊘ Total Skipped (already exist): %d\n", totalSkipped)
		fmt.Printf("\n💡 Tip: Run 'sqlite3 goondex.db \"SELECT COUNT(*) FROM scenes\"' to check total count\n")

		return nil
	},
}

var importPerformerCmd = &cobra.Command{
	Use:   "performer [query]",
	Short: "Search TPDB for performers and import them to local database",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		query := args[0]

		// Get API key from environment
		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		// Create TPDB scraper
		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)

		// Search TPDB
		fmt.Printf("Searching TPDB for performers matching '%s'...\n", query)
		performers, err := scraper.SearchPerformers(context.Background(), query)
		if err != nil {
			return fmt.Errorf("failed to search TPDB: %w", err)
		}

		if len(performers) == 0 {
			fmt.Println("No performers found on TPDB")
			return nil
		}

		fmt.Printf("Found %d performer(s) on TPDB\n\n", len(performers))

		// Open database
		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		store := db.NewPerformerStore(database)

		// Import each performer
		imported := 0
		for _, p := range performers {
			fmt.Printf("Importing: %s (TPDB ID: %s)\n", p.Name, p.SourceID)
			if err := store.Create(&p); err != nil {
				fmt.Printf("  ⚠ Warning: Failed to import: %v\n", err)
				continue
			}
			fmt.Printf("  ✓ Imported with local ID: %d\n", p.ID)
			imported++
		}

		fmt.Printf("\n✓ Successfully imported %d/%d performers\n", imported, len(performers))
		return nil
	},
}

var importStudioCmd = &cobra.Command{
	Use:   "studio [query]",
	Short: "Search TPDB for studios and import them to local database",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		query := args[0]

		// Get API key from environment
		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		// Create TPDB scraper
		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)

		// Search TPDB
		fmt.Printf("Searching TPDB for studios matching '%s'...\n", query)
		studios, err := scraper.SearchStudios(context.Background(), query)
		if err != nil {
			return fmt.Errorf("failed to search TPDB: %w", err)
		}

		if len(studios) == 0 {
			fmt.Println("No studios found on TPDB")
			return nil
		}

		fmt.Printf("Found %d studio(s) on TPDB\n\n", len(studios))

		// Open database
		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		store := db.NewStudioStore(database)

		// Import each studio
		imported := 0
		for _, s := range studios {
			fmt.Printf("Importing: %s (TPDB ID: %s)\n", s.Name, s.SourceID)
			if err := store.Create(&s); err != nil {
				fmt.Printf("  ⚠ Warning: Failed to import: %v\n", err)
				continue
			}
			fmt.Printf("  ✓ Imported with local ID: %d\n", s.ID)
			imported++
		}

		fmt.Printf("\n✓ Successfully imported %d/%d studios\n", imported, len(studios))
		return nil
	},
}

// Adult Empire command with subcommands
var adultempCmd = &cobra.Command{
	Use:   "adultemp",
	Short: "Scrape data from Adult Empire",
	Long:  `Search and scrape performers, scenes, and metadata from Adult Empire (adultdvdempire.com).`,
}

func init() {
	adultempCmd.AddCommand(adultempSearchSceneCmd)
	adultempCmd.AddCommand(adultempSearchPerformerCmd)
	adultempCmd.AddCommand(adultempSearchMovieCmd)
	adultempCmd.AddCommand(adultempScrapeSceneCmd)
	adultempCmd.AddCommand(adultempScrapePerformerCmd)
	adultempCmd.AddCommand(adultempScrapeMovieCmd)
	adultempCmd.AddCommand(adultempMergePerformerCmd)
	adultempCmd.PersistentFlags().String("etoken", "", "Adult Empire authentication token (etoken cookie)")
}

var adultempSearchSceneCmd = &cobra.Command{
	Use:   "search-scene [query]",
	Short: "Search for scenes on Adult Empire",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		query := args[0]

		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		// Set auth token if provided
		if flag := cmd.Flag("etoken"); flag != nil {
			if etoken := flag.Value.String(); etoken != "" {
				if err := scraper.SetAuthToken(etoken); err != nil {
					return fmt.Errorf("failed to set auth token: %w", err)
				}
			}
		}

		fmt.Printf("Searching Adult Empire for scenes matching '%s'...\n\n", query)

		results, err := scraper.SearchScenesByName(context.Background(), query)
		if err != nil {
			return fmt.Errorf("search failed: %w", err)
		}

		if len(results) == 0 {
			fmt.Println("No scenes found on Adult Empire")
			return nil
		}

		fmt.Printf("Found %d scene(s):\n\n", len(results))
		for i, result := range results {
			fmt.Printf("%d. %s\n", i+1, result.Title)
			fmt.Printf("   URL: %s\n", result.URL)
			if result.Image != "" {
				fmt.Printf("   Image: %s\n", result.Image)
			}
			fmt.Println()
		}

		return nil
	},
}

var adultempSearchPerformerCmd = &cobra.Command{
	Use:   "search-performer [name]",
	Short: "Search for performers on Adult Empire",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		name := args[0]

		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		// Set auth token if provided
		if flag := cmd.Flag("etoken"); flag != nil {
			if etoken := flag.Value.String(); etoken != "" {
				if err := scraper.SetAuthToken(etoken); err != nil {
					return fmt.Errorf("failed to set auth token: %w", err)
				}
			}
		}

		fmt.Printf("Searching Adult Empire for performers matching '%s'...\n\n", name)

		results, err := scraper.SearchPerformersByName(context.Background(), name)
		if err != nil {
			return fmt.Errorf("search failed: %w", err)
		}

		if len(results) == 0 {
			fmt.Println("No performers found on Adult Empire")
			return nil
		}

		fmt.Printf("Found %d performer(s):\n\n", len(results))
		for i, result := range results {
			fmt.Printf("%d. %s\n", i+1, result.Title)
			fmt.Printf("   URL: %s\n", result.URL)
			if result.Image != "" {
				fmt.Printf("   Image: %s\n", result.Image)
			}
			fmt.Println()
		}

		return nil
	},
}

var adultempScrapeSceneCmd = &cobra.Command{
	Use:   "scrape-scene [url]",
	Short: "Scrape a scene from Adult Empire by URL and import to database",
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		url := args[0]

		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		// Set auth token if provided
		if flag := cmd.Flag("etoken"); flag != nil {
			if etoken := flag.Value.String(); etoken != "" {
				if err := scraper.SetAuthToken(etoken); err != nil {
					return fmt.Errorf("failed to set auth token: %w", err)
				}
			}
		}

		fmt.Printf("Scraping scene from %s...\n", url)

		sceneData, err := scraper.ScrapeSceneByURL(context.Background(), url)
		if err != nil {
			return fmt.Errorf("scrape failed: %w", err)
		}

		// Display scraped data
		fmt.Printf("\n✓ Scraped scene data:\n")
		fmt.Printf("═══════════════════════════════════════════════════\n")
		fmt.Printf("Title: %s\n", sceneData.Title)
		if sceneData.Date != "" {
			fmt.Printf("Date: %s\n", sceneData.Date)
		}
		if sceneData.Studio != "" {
			fmt.Printf("Studio: %s\n", sceneData.Studio)
		}
		if sceneData.Director != "" {
			fmt.Printf("Director: %s\n", sceneData.Director)
		}
		if sceneData.Code != "" {
			fmt.Printf("Code: %s\n", sceneData.Code)
		}
		if len(sceneData.Performers) > 0 {
			fmt.Printf("Performers: %s\n", sceneData.Performers)
		}
		if len(sceneData.Tags) > 0 {
			fmt.Printf("Tags: %s\n", sceneData.Tags)
		}
		if sceneData.Description != "" {
			fmt.Printf("\nDescription:\n%s\n", sceneData.Description)
		}
		fmt.Printf("═══════════════════════════════════════════════════\n\n")

		// Convert to model and save to database
		scene := scraper.ConvertSceneToModel(sceneData)

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		sceneStore := db.NewSceneStore(database)

		// Import studio if present
		if sceneData.Studio != "" {
			studioStore := db.NewStudioStore(database)
			studios, _ := studioStore.Search(sceneData.Studio)
			if len(studios) > 0 {
				scene.StudioID = &studios[0].ID
			} else {
				// Create new studio
				newStudio := &model.Studio{
					Name:   sceneData.Studio,
					Source: "adultemp",
				}
				if err := studioStore.Create(newStudio); err == nil {
					scene.StudioID = &newStudio.ID
				}
			}
		}

		if err := sceneStore.Create(scene); err != nil {
			return fmt.Errorf("failed to save scene: %w", err)
		}

		fmt.Printf("✓ Scene imported to database with ID: %d\n", scene.ID)
		return nil
	},
}

var adultempScrapePerformerCmd = &cobra.Command{
	Use:   "scrape-performer [url]",
	Short: "Scrape a performer from Adult Empire by URL and import to database",
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		url := args[0]

		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		// Set auth token if provided
		if flag := cmd.Flag("etoken"); flag != nil {
			if etoken := flag.Value.String(); etoken != "" {
				if err := scraper.SetAuthToken(etoken); err != nil {
					return fmt.Errorf("failed to set auth token: %w", err)
				}
			}
		}

		fmt.Printf("Scraping performer from %s...\n", url)

		performerData, err := scraper.ScrapePerformerByURL(context.Background(), url)
		if err != nil {
			return fmt.Errorf("scrape failed: %w", err)
		}

		// Display scraped data
		fmt.Printf("\n✓ Scraped performer data:\n")
		fmt.Printf("═══════════════════════════════════════════════════\n")
		fmt.Printf("Name: %s\n", performerData.Name)
		if len(performerData.Aliases) > 0 {
			fmt.Printf("Aliases: %v\n", performerData.Aliases)
		}
		if performerData.Birthdate != "" {
			fmt.Printf("Birthday: %s\n", performerData.Birthdate)
		}
		if performerData.Ethnicity != "" {
			fmt.Printf("Ethnicity: %s\n", performerData.Ethnicity)
		}
		if performerData.Country != "" {
			fmt.Printf("Country: %s\n", performerData.Country)
		}
		if performerData.Height != "" {
			fmt.Printf("Height: %s\n", performerData.Height)
		}
		if performerData.HairColor != "" {
			fmt.Printf("Hair Color: %s\n", performerData.HairColor)
		}
		if performerData.EyeColor != "" {
			fmt.Printf("Eye Color: %s\n", performerData.EyeColor)
		}
		if performerData.Measurements != "" {
			fmt.Printf("Measurements: %s\n", performerData.Measurements)
		}
		if performerData.Biography != "" {
			fmt.Printf("\nBio:\n%s\n", performerData.Biography)
		}
		fmt.Printf("═══════════════════════════════════════════════════\n\n")

		// Convert to model and save to database
		performer := scraper.ConvertPerformerToModel(performerData)

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		performerStore := db.NewPerformerStore(database)
		if err := performerStore.Create(performer); err != nil {
			return fmt.Errorf("failed to save performer: %w", err)
		}

		fmt.Printf("✓ Performer imported to database with ID: %d\n", performer.ID)
		return nil
	},
}

var adultempSearchMovieCmd = &cobra.Command{
	Use:   "search-movie [query]",
	Short: "Search for movies on Adult Empire",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		query := args[0]

		fmt.Println("🔍 Searching Adult Empire for movies...")
		fmt.Printf("Query: \"%s\"\n\n", query)

		fmt.Println("⚠️  Movie search is not yet implemented.")
		fmt.Println()
		fmt.Println("For now, please:")
		fmt.Println("1. Go to https://www.adultdvdempire.com")
		fmt.Printf("2. Search for: \"%s\"\n", query)
		fmt.Println("3. Copy the URL of the movie you want")
		fmt.Println("4. Import it with: ./goondex adultemp scrape-movie [url]")

		return nil
	},
}

var adultempScrapeMovieCmd = &cobra.Command{
	Use:   "scrape-movie [url]",
	Short: "Scrape and import a movie from Adult Empire by URL",
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		movieURL := args[0]

		fmt.Println("📥 Scraping movie from Adult Empire...")
		fmt.Printf("URL: %s\n\n", movieURL)

		fmt.Println("⚠️  Movie scraping is not yet fully implemented.")
		fmt.Println()
		fmt.Println("The movie database schema is ready, but the Adult Empire")
		fmt.Println("movie scraper needs to be completed.")
		fmt.Println()
		fmt.Println("📌 What's ready:")
		fmt.Println("   • Movie database table and schema")
		fmt.Println("   • Movie web UI for browsing")
		fmt.Println("   • Movie-Scene relationships")
		fmt.Println()
		fmt.Println("📌 What's needed:")
		fmt.Println("   • Adult Empire HTML parser for movies")
		fmt.Println("   • Movie data extraction (title, cast, scenes, etc.)")
		fmt.Println()
		fmt.Println("💡 This feature is planned for the next release.")

		return nil
	},
}

var adultempMergePerformerCmd = &cobra.Command{
	Use:   "merge-performer [id] [adultemp-url]",
	Short: "Merge Adult Empire data into an existing performer",
	Long:  `Fetch performer data from Adult Empire and intelligently merge it with existing TPDB data.`,
	Args:  cobra.ExactArgs(2),
	RunE: func(cmd *cobra.Command, args []string) error {
		// Parse ID
		var performerID int64
		if _, err := fmt.Sscanf(args[0], "%d", &performerID); err != nil {
			return fmt.Errorf("invalid performer ID: %s", args[0])
		}

		adultempURL := args[1]

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		performerStore := db.NewPerformerStore(database)

		// Get existing performer
		performer, err := performerStore.GetByID(performerID)
		if err != nil {
			return fmt.Errorf("performer not found: %w", err)
		}

		fmt.Printf("Merging Adult Empire data into: %s (ID: %d)\n", performer.Name, performer.ID)

		// Scrape Adult Empire data
		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		// Set auth token if provided
		if flag := cmd.Flag("etoken"); flag != nil {
			if etoken := flag.Value.String(); etoken != "" {
				if err := scraper.SetAuthToken(etoken); err != nil {
					return fmt.Errorf("failed to set auth token: %w", err)
				}
			}
		}

		fmt.Printf("Scraping Adult Empire data from: %s\n", adultempURL)

		adultempData, err := scraper.ScrapePerformerByURL(context.Background(), adultempURL)
		if err != nil {
			return fmt.Errorf("failed to scrape Adult Empire: %w", err)
		}

		// Check if names match
		if !merger.ShouldMerge(performer.Name, adultempData.Name) {
			fmt.Printf("\n⚠ Warning: Names don't match closely:\n")
			fmt.Printf("  Database: %s\n", performer.Name)
			fmt.Printf("  Adult Empire: %s\n", adultempData.Name)
			fmt.Printf("\nProceed anyway? This may merge data for different performers.\n")
			fmt.Printf("Type 'yes' to continue: ")

			var response string
			fmt.Scanln(&response)
			if response != "yes" {
				fmt.Println("Merge cancelled.")
				return nil
			}
		}

		// Merge the data
		fmt.Println("\n🔄 Merging data...")
		mergedPerformer := merger.MergePerformerData(performer, adultempData)

		// Update the database
		if err := performerStore.Update(mergedPerformer); err != nil {
			return fmt.Errorf("failed to update performer: %w", err)
		}

		fmt.Println("✓ Successfully merged Adult Empire data!")
		fmt.Printf("\nUpdated fields:\n")
		if mergedPerformer.Birthday != performer.Birthday && mergedPerformer.Birthday != "" {
			fmt.Printf("  - Birthday: %s\n", mergedPerformer.Birthday)
		}
		if mergedPerformer.Ethnicity != performer.Ethnicity && mergedPerformer.Ethnicity != "" {
			fmt.Printf("  - Ethnicity: %s\n", mergedPerformer.Ethnicity)
		}
		if mergedPerformer.Country != performer.Country && mergedPerformer.Country != "" {
			fmt.Printf("  - Country: %s\n", mergedPerformer.Country)
		}
		if mergedPerformer.Height != performer.Height && mergedPerformer.Height > 0 {
			fmt.Printf("  - Height: %d cm\n", mergedPerformer.Height)
		}
		if mergedPerformer.HairColor != performer.HairColor && mergedPerformer.HairColor != "" {
			fmt.Printf("  - Hair Color: %s\n", mergedPerformer.HairColor)
		}
		if mergedPerformer.EyeColor != performer.EyeColor && mergedPerformer.EyeColor != "" {
			fmt.Printf("  - Eye Color: %s\n", mergedPerformer.EyeColor)
		}
		if mergedPerformer.Aliases != performer.Aliases && mergedPerformer.Aliases != "" {
			fmt.Printf("  - Aliases: %s\n", mergedPerformer.Aliases)
		}

		return nil
	},
}

var importSceneCmd = &cobra.Command{
	Use:   "scene [query]",
	Short: "Search TPDB for scenes and import them to local database",
	Args:  cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		query := args[0]

		// Get API key from environment
		apiKey, err := getTPDBAPIKey()
		if err != nil {
			return err
		}

		// Create TPDB scraper
		scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)

		// Search TPDB
		fmt.Printf("Searching TPDB for scenes matching '%s'...\n", query)
		scenes, err := scraper.SearchScenes(context.Background(), query)
		if err != nil {
			return fmt.Errorf("failed to search TPDB: %w", err)
		}

		if len(scenes) == 0 {
			fmt.Println("No scenes found on TPDB")
			return nil
		}

		fmt.Printf("Found %d scene(s) on TPDB\n\n", len(scenes))

		// Open database
		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		sceneStore := db.NewSceneStore(database)
		performerStore := db.NewPerformerStore(database)
		studioStore := db.NewStudioStore(database)
		tagStore := db.NewTagStore(database)

		// Import each scene
		imported := 0
		for _, sc := range scenes {
			fmt.Printf("Importing: %s (TPDB ID: %s)\n", sc.Title, sc.SourceID)

			// Import studio if present
			if sc.Studio != nil {
				if err := studioStore.Create(sc.Studio); err != nil {
					// Studio might already exist, try to fetch it
					studios, _ := studioStore.Search(sc.Studio.Name)
					if len(studios) > 0 {
						sc.StudioID = &studios[0].ID
					}
				} else {
					sc.StudioID = &sc.Studio.ID
				}
			}

			// Create scene
			if err := sceneStore.Create(&sc); err != nil {
				fmt.Printf("  ⚠ Warning: Failed to import scene: %v\n", err)
				continue
			}

			// Import and link performers
			for _, p := range sc.Performers {
				if err := performerStore.Create(&p); err != nil {
					// Performer might already exist
					performers, _ := performerStore.Search(p.Name)
					if len(performers) > 0 {
						p.ID = performers[0].ID
					}
				}
				if p.ID > 0 {
					sceneStore.AddPerformer(sc.ID, p.ID)
				}
			}

			// Import and link tags
			for _, t := range sc.Tags {
				existing, _ := tagStore.GetByName(t.Name)
				if existing != nil {
					t.ID = existing.ID
				} else {
					if err := tagStore.Create(&t); err != nil {
						continue
					}
				}
				if t.ID > 0 {
					sceneStore.AddTag(sc.ID, t.ID)
				}
			}

			fmt.Printf("  ✓ Imported with local ID: %d\n", sc.ID)
			imported++
		}

		fmt.Printf("\n✓ Successfully imported %d/%d scenes\n", imported, len(scenes))
		return nil
	},
}

var importMovieCmd = &cobra.Command{
	Use:   "movie [title or url]",
	Short: "Import movies from Adult Empire",
	Long: `Import movies from Adult Empire. TPDB does not have a movies database.

Movies can be imported by:
1. Searching by title: ./goondex import movie "Movie Title"
2. Direct URL: ./goondex import movie https://www.adultdvdempire.com/...

Note: For bulk movie import, movies are best imported through Adult Empire's catalog.`,
	Args: cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		input := args[0]

		fmt.Println("╔═══════════════════════════════════════════════════════════════╗")
		fmt.Println("║              MOVIE IMPORT - ADULT EMPIRE                      ║")
		fmt.Println("╚═══════════════════════════════════════════════════════════════╝")
		fmt.Println()
		fmt.Println("📌 Note: TPDB does not have movies. Movies are imported from Adult Empire.")
		fmt.Println()

		// Check if input is a URL
		isURL := len(input) > 4 && (input[:4] == "http" || input[:3] == "www")

		if isURL {
			fmt.Printf("🔗 Importing movie from URL: %s\n", input)
			fmt.Println()
			fmt.Println("ℹ️  To import movies, use the Adult Empire scraper:")
			fmt.Printf("   ./goondex adultemp scrape-movie %s\n", input)
		} else {
			fmt.Printf("🔍 Searching Adult Empire for: \"%s\"\n", input)
			fmt.Println()
			fmt.Println("ℹ️  To search and import movies, use:")
			fmt.Printf("   1. Search: ./goondex adultemp search-movie \"%s\"\n", input)
			fmt.Println("   2. Copy the URL of the movie you want")
			fmt.Println("   3. Import: ./goondex adultemp scrape-movie [url]")
		}

		fmt.Println()
		fmt.Println("💡 Tip: Movies imported from Adult Empire will include:")
		fmt.Println("   • Movie title, date, studio, director")
		fmt.Println("   • Front and back cover images")
		fmt.Println("   • Full description")
		fmt.Println("   • Cast (performers)")
		fmt.Println("   • Individual scenes within the movie")
		fmt.Println()
		fmt.Println("For now, movies need to be imported manually. Bulk import")
		fmt.Println("from Adult Empire is planned for a future release.")

		return nil
	},
}

// Enrich command with subcommands
var enrichCmd = &cobra.Command{
	Use:   "enrich",
	Short: "Enrich existing data with Adult Empire metadata",
	Long: `Automatically enrich performers and scenes with additional metadata from Adult Empire.

This command searches Adult Empire for matching entities and merges the data:
- TPDB data is primary (never overwritten)
- Adult Empire fills in missing fields (bio, ethnicity, measurements, etc.)
- Fuzzy name matching ensures accurate matches (70% threshold)
- Rate limited to prevent API overload

Examples:
  goondex enrich performer 123           # Enrich single performer
  goondex enrich all-performers          # Enrich all performers
  goondex enrich scene 456               # Enrich single scene
  goondex enrich all-scenes              # Enrich all scenes`,
}

func init() {
	enrichCmd.AddCommand(enrichPerformerCmd)
	enrichCmd.AddCommand(enrichAllPerformersCmd)
	enrichCmd.AddCommand(enrichSceneCmd)
	enrichCmd.AddCommand(enrichAllScenesCmd)

	// Flags for bulk enrich
	enrichAllPerformersCmd.Flags().Int("start-id", 1, "Performer ID to start from (for resuming)")
	enrichAllPerformersCmd.Flags().Int("limit", 0, "Maximum performers to enrich (0 = all)")
	enrichAllPerformersCmd.Flags().Duration("rate-limit", 500*time.Millisecond, "Delay between searches")
	enrichAllScenesCmd.Flags().Int("start-id", 1, "Scene ID to start from (for resuming)")
	enrichAllScenesCmd.Flags().Int("limit", 0, "Maximum scenes to enrich (0 = all)")
	enrichAllScenesCmd.Flags().Duration("rate-limit", 500*time.Millisecond, "Delay between searches")
}

var enrichPerformerCmd = &cobra.Command{
	Use:   "performer [id]",
	Short: "Enrich a single performer with Adult Empire data",
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		id := args[0]

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		performerStore := db.NewPerformerStore(database)

		// Get performer from DB
		var performerID int64
		if _, err := fmt.Sscanf(id, "%d", &performerID); err != nil {
			return fmt.Errorf("invalid performer ID: %w", err)
		}

		performer, err := performerStore.GetByID(performerID)
		if err != nil {
			return fmt.Errorf("performer not found: %w", err)
		}

		fmt.Printf("🔍 Enriching performer: %s (ID: %d)\n", performer.Name, performer.ID)

		// Search Adult Empire
		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		fmt.Printf("   Searching Adult Empire for '%s'...\n", performer.Name)
		results, err := scraper.SearchPerformersByName(context.Background(), performer.Name)
		if err != nil {
			return fmt.Errorf("search failed: %w", err)
		}

		if len(results) == 0 {
			fmt.Println("   ⚠ No matches found on Adult Empire")
			return nil
		}

		// Find best match using fuzzy matching
		var bestMatch *adultemp.SearchResult
		for i := range results {
			if merger.ShouldMerge(performer.Name, results[i].Title) {
				bestMatch = &results[i]
				break
			}
		}

		if bestMatch == nil {
			fmt.Printf("   ⚠ No confident matches found (searched %d results)\n", len(results))
			fmt.Println("   💡 Tip: First result was:", results[0].Title)
			return nil
		}

		fmt.Printf("   ✓ Found match: %s\n", bestMatch.Title)
		fmt.Printf("   📄 Scraping: %s\n", bestMatch.URL)

		// Scrape full data
		adultempData, err := scraper.ScrapePerformerByURL(context.Background(), bestMatch.URL)
		if err != nil {
			return fmt.Errorf("scraping failed: %w", err)
		}

		// Merge data
		merged := merger.MergePerformerData(performer, adultempData)

		// Update in database
		if err := performerStore.Update(merged); err != nil {
			return fmt.Errorf("failed to update performer: %w", err)
		}

		fmt.Printf("   ✓ Successfully enriched %s\n", performer.Name)
		fmt.Println()
		fmt.Println("📊 Enriched fields:")
		if adultempData.Birthdate != "" {
			fmt.Printf("   • Birthday: %s\n", adultempData.Birthdate)
		}
		if adultempData.Ethnicity != "" {
			fmt.Printf("   • Ethnicity: %s\n", adultempData.Ethnicity)
		}
		if adultempData.HairColor != "" {
			fmt.Printf("   • Hair Color: %s\n", adultempData.HairColor)
		}
		if adultempData.EyeColor != "" {
			fmt.Printf("   • Eye Color: %s\n", adultempData.EyeColor)
		}
		if adultempData.Measurements != "" {
			fmt.Printf("   • Measurements: %s\n", adultempData.Measurements)
		}

		return nil
	},
}

var enrichAllPerformersCmd = &cobra.Command{
	Use:   "all-performers",
	Short: "Enrich all performers with Adult Empire data",
	Long: `Automatically enrich all performers in the database with Adult Empire metadata.

This process:
- Searches Adult Empire for each performer by name
- Uses fuzzy matching to find confident matches
- Merges data only for high-confidence matches (70% name similarity)
- Rate limited to prevent API overload (default 500ms between searches)
- Tracks progress and can be resumed

Examples:
  goondex enrich all-performers                    # Enrich all performers
  goondex enrich all-performers --start-id 100     # Resume from ID 100
  goondex enrich all-performers --limit 50         # Enrich first 50 performers
  goondex enrich all-performers --rate-limit 1s    # Slower rate limit`,
	RunE: func(cmd *cobra.Command, args []string) error {
		startID, _ := cmd.Flags().GetInt("start-id")
		limit, _ := cmd.Flags().GetInt("limit")
		rateLimit, _ := cmd.Flags().GetDuration("rate-limit")

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		performerStore := db.NewPerformerStore(database)

		// Get all performers
		performers, err := performerStore.Search("")
		if err != nil {
			return fmt.Errorf("failed to search performers: %w", err)
		}

		fmt.Printf("🔍 Enriching performers from Adult Empire\n")
		fmt.Printf("   Total performers: %d\n", len(performers))
		fmt.Printf("   Start ID: %d\n", startID)
		if limit > 0 {
			fmt.Printf("   Limit: %d\n", limit)
		}
		fmt.Printf("   Rate limit: %v\n", rateLimit)
		fmt.Println()

		// Create scraper
		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		// Track stats
		totalProcessed := 0
		totalEnriched := 0
		totalSkipped := 0
		totalFailed := 0

		for _, performer := range performers {
			// Skip if before start ID
			if performer.ID < int64(startID) {
				continue
			}

			// Check limit
			if limit > 0 && totalProcessed >= limit {
				break
			}

			totalProcessed++
			fmt.Printf("[%d/%d] Processing: %s (ID: %d)\n", totalProcessed, len(performers), performer.Name, performer.ID)

			// Search Adult Empire
			results, err := scraper.SearchPerformersByName(context.Background(), performer.Name)
			if err != nil {
				fmt.Printf("   ⚠ Search failed: %v\n", err)
				totalFailed++
				time.Sleep(rateLimit)
				continue
			}

			if len(results) == 0 {
				fmt.Println("   ⚠ No matches found")
				totalSkipped++
				time.Sleep(rateLimit)
				continue
			}

			// Find best match using fuzzy matching
			var bestMatch *adultemp.SearchResult
			for i := range results {
				if merger.ShouldMerge(performer.Name, results[i].Title) {
					bestMatch = &results[i]
					break
				}
			}

			if bestMatch == nil {
				fmt.Printf("   ⚠ No confident match (closest: %s)\n", results[0].Title)
				totalSkipped++
				time.Sleep(rateLimit)
				continue
			}

			fmt.Printf("   ✓ Found: %s\n", bestMatch.Title)

			// Scrape full data
			adultempData, err := scraper.ScrapePerformerByURL(context.Background(), bestMatch.URL)
			if err != nil {
				fmt.Printf("   ⚠ Scraping failed: %v\n", err)
				totalFailed++
				time.Sleep(rateLimit)
				continue
			}

			// Merge data
			merged := merger.MergePerformerData(&performer, adultempData)

			// Update in database
			if err := performerStore.Update(merged); err != nil {
				fmt.Printf("   ⚠ Update failed: %v\n", err)
				totalFailed++
				time.Sleep(rateLimit)
				continue
			}

			fmt.Printf("   ✓ Enriched successfully\n")
			totalEnriched++

			// Rate limiting
			time.Sleep(rateLimit)
		}

		fmt.Println()
		fmt.Println("═══════════════════════════════════════")
		fmt.Printf("✓ Enrichment Complete\n")
		fmt.Printf("  Processed: %d\n", totalProcessed)
		fmt.Printf("  Enriched:  %d\n", totalEnriched)
		fmt.Printf("  Skipped:   %d\n", totalSkipped)
		fmt.Printf("  Failed:    %d\n", totalFailed)
		fmt.Println("═══════════════════════════════════════")

		return nil
	},
}

var enrichSceneCmd = &cobra.Command{
	Use:   "scene [id]",
	Short: "Enrich a single scene with Adult Empire data",
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		id := args[0]

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		sceneStore := db.NewSceneStore(database)

		// Get scene from DB
		var sceneID int64
		if _, err := fmt.Sscanf(id, "%d", &sceneID); err != nil {
			return fmt.Errorf("invalid scene ID: %w", err)
		}

		scene, err := sceneStore.GetByID(sceneID)
		if err != nil {
			return fmt.Errorf("scene not found: %w", err)
		}

		fmt.Printf("🔍 Enriching scene: %s (ID: %d)\n", scene.Title, scene.ID)

		// Search Adult Empire
		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		fmt.Printf("   Searching Adult Empire for '%s'...\n", scene.Title)
		results, err := scraper.SearchScenesByName(context.Background(), scene.Title)
		if err != nil {
			return fmt.Errorf("search failed: %w", err)
		}

		if len(results) == 0 {
			fmt.Println("   ⚠ No matches found on Adult Empire")
			return nil
		}

		// Find best match using fuzzy matching
		var bestMatch *adultemp.SearchResult
		for i := range results {
			if merger.ShouldMerge(scene.Title, results[i].Title) {
				bestMatch = &results[i]
				break
			}
		}

		if bestMatch == nil {
			fmt.Printf("   ⚠ No confident matches found (searched %d results)\n", len(results))
			fmt.Println("   💡 Tip: First result was:", results[0].Title)
			return nil
		}

		fmt.Printf("   ✓ Found match: %s\n", bestMatch.Title)
		fmt.Printf("   📄 Scraping: %s\n", bestMatch.URL)

		// Scrape full data
		adultempData, err := scraper.ScrapeSceneByURL(context.Background(), bestMatch.URL)
		if err != nil {
			return fmt.Errorf("scraping failed: %w", err)
		}

		// Merge scene data (fill in missing fields)
		if scene.Description == "" && adultempData.Description != "" {
			scene.Description = adultempData.Description
		}
		if scene.Director == "" && adultempData.Director != "" {
			scene.Director = adultempData.Director
		}
		if scene.ImageURL == "" && adultempData.Image != "" {
			scene.ImageURL = adultempData.Image
		}

		// Update in database
		if err := sceneStore.Update(scene); err != nil {
			return fmt.Errorf("failed to update scene: %w", err)
		}

		fmt.Printf("   ✓ Successfully enriched %s\n", scene.Title)

		return nil
	},
}

var enrichAllScenesCmd = &cobra.Command{
	Use:   "all-scenes",
	Short: "Enrich all scenes with Adult Empire data",
	Long: `Automatically enrich all scenes in the database with Adult Empire metadata.

This process:
- Searches Adult Empire for each scene by title
- Uses fuzzy matching to find confident matches
- Merges data only for high-confidence matches (70% title similarity)
- Rate limited to prevent API overload (default 500ms between searches)
- Tracks progress and can be resumed`,
	RunE: func(cmd *cobra.Command, args []string) error {
		startID, _ := cmd.Flags().GetInt("start-id")
		limit, _ := cmd.Flags().GetInt("limit")
		rateLimit, _ := cmd.Flags().GetDuration("rate-limit")

		database, err := getDB()
		if err != nil {
			return err
		}
		defer database.Close()

		sceneStore := db.NewSceneStore(database)

		// Get all scenes
		scenes, err := sceneStore.Search("")
		if err != nil {
			return fmt.Errorf("failed to search scenes: %w", err)
		}

		fmt.Printf("🔍 Enriching scenes from Adult Empire\n")
		fmt.Printf("   Total scenes: %d\n", len(scenes))
		fmt.Printf("   Start ID: %d\n", startID)
		if limit > 0 {
			fmt.Printf("   Limit: %d\n", limit)
		}
		fmt.Printf("   Rate limit: %v\n", rateLimit)
		fmt.Println()

		// Create scraper
		scraper, err := adultemp.NewScraper()
		if err != nil {
			return fmt.Errorf("failed to create scraper: %w", err)
		}

		// Track stats
		totalProcessed := 0
		totalEnriched := 0
		totalSkipped := 0
		totalFailed := 0

		for _, scene := range scenes {
			// Skip if before start ID
			if scene.ID < int64(startID) {
				continue
			}

			// Check limit
			if limit > 0 && totalProcessed >= limit {
				break
			}

			totalProcessed++
			fmt.Printf("[%d/%d] Processing: %s (ID: %d)\n", totalProcessed, len(scenes), scene.Title, scene.ID)

			// Search Adult Empire
			results, err := scraper.SearchScenesByName(context.Background(), scene.Title)
			if err != nil {
				fmt.Printf("   ⚠ Search failed: %v\n", err)
				totalFailed++
				time.Sleep(rateLimit)
				continue
			}

			if len(results) == 0 {
				fmt.Println("   ⚠ No matches found")
				totalSkipped++
				time.Sleep(rateLimit)
				continue
			}

			// Find best match using fuzzy matching
			var bestMatch *adultemp.SearchResult
			for i := range results {
				if merger.ShouldMerge(scene.Title, results[i].Title) {
					bestMatch = &results[i]
					break
				}
			}

			if bestMatch == nil {
				fmt.Printf("   ⚠ No confident match (closest: %s)\n", results[0].Title)
				totalSkipped++
				time.Sleep(rateLimit)
				continue
			}

			fmt.Printf("   ✓ Found: %s\n", bestMatch.Title)

			// Scrape full data
			adultempData, err := scraper.ScrapeSceneByURL(context.Background(), bestMatch.URL)
			if err != nil {
				fmt.Printf("   ⚠ Scraping failed: %v\n", err)
				totalFailed++
				time.Sleep(rateLimit)
				continue
			}

			// Merge scene data (fill in missing fields)
			if scene.Description == "" && adultempData.Description != "" {
				scene.Description = adultempData.Description
			}
			if scene.Director == "" && adultempData.Director != "" {
				scene.Director = adultempData.Director
			}
			if scene.ImageURL == "" && adultempData.Image != "" {
				scene.ImageURL = adultempData.Image
			}

			// Update in database
			if err := sceneStore.Update(&scene); err != nil {
				fmt.Printf("   ⚠ Update failed: %v\n", err)
				totalFailed++
				time.Sleep(rateLimit)
				continue
			}

			fmt.Printf("   ✓ Enriched successfully\n")
			totalEnriched++

			// Rate limiting
			time.Sleep(rateLimit)
		}

		fmt.Println()
		fmt.Println("═══════════════════════════════════════")
		fmt.Printf("✓ Enrichment Complete\n")
		fmt.Printf("  Processed: %d\n", totalProcessed)
		fmt.Printf("  Enriched:  %d\n", totalEnriched)
		fmt.Printf("  Skipped:   %d\n", totalSkipped)
		fmt.Printf("  Failed:    %d\n", totalFailed)
		fmt.Println("═══════════════════════════════════════")

		return nil
	},
}
