"""One-time migration service for legacy key and data files.

This module provides functionality to migrate series data from legacy
file-based storage (key/data files) to the database. The migration is
designed to be idempotent and run only once per environment.
"""
from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Optional

import structlog
from sqlalchemy.ext.asyncio import AsyncSession

logger = structlog.get_logger(__name__)


async def migrate_series_from_files_to_db(
    anime_dir: str,
    db: AsyncSession,
) -> int:
    """Migrate series from legacy key/data files to database.

    Scans for folders containing legacy 'key' or 'data' files and imports
    any series not already in the database. The DB version wins if a series
    exists in both places.

    Args:
        anime_dir: Path to the anime directory
        db: Database session

    Returns:
        Number of series imported
    """
    from src.server.database.service import AnimeSeriesService, EpisodeService

    if not anime_dir or not os.path.isdir(anime_dir):
        logger.warning(
            "Anime directory does not exist, skipping legacy migration",
            anime_dir=anime_dir
        )
        return 0

    migrated_count = 0
    scanned_count = 0

    try:
        for folder_name in os.listdir(anime_dir):
            folder_path = os.path.join(anime_dir, folder_name)

            if not os.path.isdir(folder_path):
                continue

            scanned_count += 1

            # Check for 'key' file (single line with series key)
            key_file = os.path.join(folder_path, "key")
            # Check for 'data' file (JSON with series metadata)
            data_file = os.path.join(folder_path, "data")

            series_data: Optional[dict] = None

            # Try to load from 'data' file first (more complete)
            if os.path.isfile(data_file):
                series_data = _load_data_file(data_file)
            elif os.path.isfile(key_file):
                # Fall back to 'key' file - just the key, need to infer other data
                series_data = _load_key_file(key_file, folder_name)

            if series_data is None:
                continue

            key = series_data.get("key")
            if not key:
                logger.warning(
                    "Skipping folder with no valid key",
                    folder=folder_name
                )
                continue

            # Check if already in DB
            existing = await AnimeSeriesService.get_by_key(db, key)
            if existing:
                logger.debug(
                    "Series already in database, skipping",
                    key=key,
                    folder=folder_name
                )
                continue

            # Create the series in DB
            try:
                name = series_data.get("name") or folder_name
                site = series_data.get("site", "https://aniworld.to")
                folder = series_data.get("folder", folder_name)
                year = series_data.get("year")

                anime_series = await AnimeSeriesService.create(
                    db=db,
                    key=key,
                    name=name,
                    site=site,
                    folder=folder,
                    year=year,
                )

                # Create episodes if present
                episode_dict = series_data.get("episodeDict", {})
                if episode_dict:
                    for season, episode_numbers in episode_dict.items():
                        for episode_number in episode_numbers:
                            await EpisodeService.create(
                                db=db,
                                series_id=anime_series.id,
                                season=season,
                                episode_number=episode_number,
                            )

                migrated_count += 1
                logger.info(
                    "Migrated series from legacy file",
                    key=key,
                    name=name,
                    folder=folder_name
                )

            except Exception as e:
                logger.warning(
                    "Failed to migrate series from legacy file",
                    key=key,
                    folder=folder_name,
                    error=str(e)
                )

    except Exception as e:
        logger.error(
            "Legacy migration failed",
            anime_dir=anime_dir,
            error=str(e),
            exc_info=True
        )

    logger.info(
        "Legacy file migration complete",
        scanned_folders=scanned_count,
        migrated=migrated_count
    )
    return migrated_count


def _load_data_file(data_file_path: str) -> Optional[dict]:
    """Load and parse a legacy 'data' file (JSON).

    Args:
        data_file_path: Path to the data file

    Returns:
        Parsed data dict or None if parsing fails
    """
    try:
        with open(data_file_path, "r", encoding="utf-8") as f:
            data = json.load(f)

        if not isinstance(data, dict):
            logger.warning(
                "Data file is not a dictionary",
                file=data_file_path
            )
            return None

        # Ensure episodeDict has int keys
        if "episodeDict" in data and isinstance(data["episodeDict"], dict):
            data["episodeDict"] = {
                int(k): v for k, v in data["episodeDict"].items()
            }

        return data

    except json.JSONDecodeError as e:
        logger.warning(
            "Failed to parse legacy data file (JSON error)",
            file=data_file_path,
            error=str(e)
        )
        return None
    except Exception as e:
        logger.warning(
            "Failed to read legacy data file",
            file=data_file_path,
            error=str(e)
        )
        return None


def _load_key_file(key_file_path: str, folder_name: str) -> Optional[dict]:
    """Load a legacy 'key' file (single line with series key).

    Args:
        key_file_path: Path to the key file
        folder_name: Folder name to use as fallback name

    Returns:
        Data dict with key and inferred fields, or None if loading fails
    """
    try:
        with open(key_file_path, "r", encoding="utf-8") as f:
            key = f.read().strip()

        if not key:
            logger.warning(
                "Key file is empty",
                file=key_file_path
            )
            return None

        # Infer basic data from key file
        return {
            "key": key,
            "name": folder_name,
            "site": "https://aniworld.to",
            "folder": folder_name,
            "episodeDict": {},
        }

    except Exception as e:
        logger.warning(
            "Failed to read legacy key file",
            file=key_file_path,
            error=str(e)
        )
        return None
