package migrate

import (
	"context"
	"fmt"
	"log/slog"
	"strings"

	"github.com/TopherMayor/unified-media-manager/internal/db"
)

// ArrSources holds paths to arr SQLite databases.
type ArrSources struct {
	Sonarr      string
	Radarr      string
	SonarrAnime string
	RadarrAnime string
	Lidarr      string
	Readarr    string
	Prowlarr   string
}

// ImportCount tracks imported and skipped counts for a category.
type ImportCount struct {
	Imported int
	Skipped  int
}

// Report holds the migration results.
type Report struct {
	Indexers    ImportCount
	Series      ImportCount
	Movies      ImportCount
	Albums      ImportCount
	Books       ImportCount
	Files       ImportCount
	Profiles    ImportCount
	RootFolders ImportCount
	Tags        ImportCount
	Blocklist   ImportCount
	Errors      int
}

func (r *Report) String() string {
	var b strings.Builder
	b.WriteString("Migration Report:\n")
	fmt.Fprintf(&b, "  Indexers:     %d imported, %d skipped\n", r.Indexers.Imported, r.Indexers.Skipped)
	fmt.Fprintf(&b, "  Series:       %d imported, %d deduplicated\n", r.Series.Imported, r.Series.Skipped)
	fmt.Fprintf(&b, "  Movies:       %d imported, %d deduplicated\n", r.Movies.Imported, r.Movies.Skipped)
	fmt.Fprintf(&b, "  Albums:       %d imported, %d deduplicated\n", r.Albums.Imported, r.Albums.Skipped)
	fmt.Fprintf(&b, "  Books:        %d imported, %d deduplicated\n", r.Books.Imported, r.Books.Skipped)
	fmt.Fprintf(&b, "  Files:        %d imported\n", r.Files.Imported)
	fmt.Fprintf(&b, "  Profiles:     %d imported\n", r.Profiles.Imported)
	fmt.Fprintf(&b, "  Root Folders: %d imported\n", r.RootFolders.Imported)
	fmt.Fprintf(&b, "  Tags:         %d imported\n", r.Tags.Imported)
	fmt.Fprintf(&b, "  Blocklist:    %d imported\n", r.Blocklist.Imported)
	fmt.Fprintf(&b, "  Errors:       %d\n", r.Errors)
	return b.String()
}

// Migrator orchestrates the data migration from arr SQLite databases to UMM PostgreSQL.
type Migrator struct {
	db      *db.DB
	sources ArrSources
	report  Report

	// Maps arr entity IDs to UMM media IDs, keyed by arr instance
	sonarrSeriesMap       map[int64]int64 // sonarr series ID → UMM media ID
	sonarrAnimeSeriesMap  map[int64]int64 // sonarr-anime series ID → UMM media ID
	radarrMovieMap        map[int64]int64 // radarr movie ID → UMM media ID
	radarrAnimeMovieMap   map[int64]int64 // radarr-anime movie ID → UMM media ID
	lidarrAlbumMap        map[int64]int64 // lidarr album ID → UMM media ID
	readarrBookMap        map[int64]int64 // readarr book ID → UMM media ID
}

// NewMigrator creates a new Migrator instance.
func NewMigrator(database *db.DB, sources ArrSources) *Migrator {
	return &Migrator{
		db:                   database,
		sources:              sources,
		sonarrSeriesMap:      make(map[int64]int64),
		sonarrAnimeSeriesMap: make(map[int64]int64),
		radarrMovieMap:       make(map[int64]int64),
		radarrAnimeMovieMap:  make(map[int64]int64),
		lidarrAlbumMap:       make(map[int64]int64),
		readarrBookMap:       make(map[int64]int64),
	}
}

// Run executes the full migration pipeline.
func (m *Migrator) Run(ctx context.Context) (*Report, error) {
	slog.Info("starting arr data migration")

	// Step 1: Import Prowlarr indexers
	if m.sources.Prowlarr != "" {
		slog.Info("importing prowlarr indexers", "path", m.sources.Prowlarr)
		if err := m.importProwlarr(ctx); err != nil {
			slog.Error("failed to import prowlarr", "error", err)
			m.report.Errors++
		}
	}

	// Step 2: Import Sonarr series
	if m.sources.Sonarr != "" {
		slog.Info("importing sonarr series", "path", m.sources.Sonarr)
		if err := m.importSonarr(ctx, m.sources.Sonarr, false); err != nil {
			slog.Error("failed to import sonarr", "error", err)
			m.report.Errors++
		}
	}

	// Step 3: Import Sonarr-anime (deduplicate by TVDB ID)
	if m.sources.SonarrAnime != "" {
		slog.Info("importing sonarr-anime series", "path", m.sources.SonarrAnime)
		if err := m.importSonarr(ctx, m.sources.SonarrAnime, true); err != nil {
			slog.Error("failed to import sonarr-anime", "error", err)
			m.report.Errors++
		}
	}

	// Step 4: Import Radarr movies
	if m.sources.Radarr != "" {
		slog.Info("importing radarr movies", "path", m.sources.Radarr)
		if err := m.importRadarr(ctx, m.sources.Radarr, false); err != nil {
			slog.Error("failed to import radarr", "error", err)
			m.report.Errors++
		}
	}

	// Step 5: Import Radarr-anime (deduplicate by TMDB ID)
	if m.sources.RadarrAnime != "" {
		slog.Info("importing radarr-anime movies", "path", m.sources.RadarrAnime)
		if err := m.importRadarr(ctx, m.sources.RadarrAnime, true); err != nil {
			slog.Error("failed to import radarr-anime", "error", err)
			m.report.Errors++
		}
	}

	// Step 6: Import Lidarr artists + albums
	if m.sources.Lidarr != "" {
		slog.Info("importing lidarr", "path", m.sources.Lidarr)
		if err := m.importLidarr(ctx); err != nil {
			slog.Error("failed to import lidarr", "error", err)
			m.report.Errors++
		}
	}

	// Step 7: Import Readarr books
	if m.sources.Readarr != "" {
		slog.Info("importing readarr", "path", m.sources.Readarr)
		if err := m.importReadarr(ctx); err != nil {
			slog.Error("failed to import readarr", "error", err)
			m.report.Errors++
		}
	}

	// Step 8: Reset PostgreSQL sequences
	if err := m.resetSequences(ctx); err != nil {
		slog.Error("failed to reset sequences", "error", err)
		m.report.Errors++
	}

	slog.Info("migration complete",
		"series", m.report.Series.Imported,
		"movies", m.report.Movies.Imported,
		"albums", m.report.Albums.Imported,
		"books", m.report.Books.Imported,
		"files", m.report.Files.Imported,
		"errors", m.report.Errors,
	)
	return &m.report, nil
}
