"""NFO Management API endpoints.

This module provides REST API endpoints for managing tvshow.nfo files
and associated media (poster, logo, fanart).
"""
import asyncio
import logging
from datetime import datetime
from pathlib import Path
from typing import List

from fastapi import APIRouter, Depends, HTTPException, status

from src.config.settings import settings
from src.core.entities.series import Serie
from src.core.SeriesApp import SeriesApp
from src.core.services.nfo_factory import get_nfo_factory
from src.core.services.nfo_service import NFOService
from src.core.services.nfo_repair_service import (
    REQUIRED_TAGS,
    NfoRepairService,
    find_missing_tags,
)
from src.core.services.tmdb_client import TMDBAPIError
from src.server.models.nfo import (
    MediaDownloadRequest,
    MediaFilesStatus,
    NFOBatchCreateRequest,
    NFOBatchCreateResponse,
    NFOBatchResult,
    NFOCheckResponse,
    NFOContentResponse,
    NFOCreateRequest,
    NFOCreateResponse,
    NfoDiagnosticsResponse,
    NFOMissingResponse,
    NFOMissingSeries,
    NfoRepairResponse,
)
from src.server.utils.dependencies import get_series_app, require_auth
from src.server.utils.media import check_media_files, get_media_file_paths

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/nfo", tags=["nfo"])


async def get_nfo_service() -> NFOService:
    """Get NFO service dependency.
    
    Returns:
        NFOService instance
        
    Raises:
        HTTPException: If NFO service not configured
    """
    try:
        # Use centralized factory for consistent initialization
        factory = get_nfo_factory()
        return factory.create()
    except ValueError as e:
        # Factory raises ValueError if API key not configured
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail=str(e)
        ) from e


# =============================================================================
# IMPORTANT: Literal path routes must be defined BEFORE path parameter routes
# to avoid route matching conflicts. For example, /batch/create must come
# before /{serie_id}/create, otherwise "batch" is treated as a serie_id.
# =============================================================================


@router.post("/batch/create", response_model=NFOBatchCreateResponse)
async def batch_create_nfo(
    request: NFOBatchCreateRequest,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
    nfo_service: NFOService = Depends(get_nfo_service)
) -> NFOBatchCreateResponse:
    """Batch create NFO files for multiple series.
    
    Args:
        request: Batch creation options
        _auth: Authentication dependency
        series_app: Series app dependency
        nfo_service: NFO service dependency
        
    Returns:
        NFOBatchCreateResponse with results
    """
    results: List[NFOBatchResult] = []
    successful = 0
    failed = 0
    skipped = 0
    
    # Get all series
    series_list = series_app.list.GetList()
    series_map = {
        getattr(s, 'key', None): s
        for s in series_list
        if getattr(s, 'key', None)
    }
    
    # Process each series
    semaphore = asyncio.Semaphore(request.max_concurrent)
    
    async def process_serie(serie_id: str) -> NFOBatchResult:
        """Process a single series."""
        async with semaphore:
            try:
                serie = series_map.get(serie_id)
                if not serie:
                    return NFOBatchResult(
                        serie_id=serie_id,
                        serie_folder="",
                        success=False,
                        message="Series not found"
                    )
                
                # Ensure folder name includes year if available
                serie_folder = serie.ensure_folder_with_year()
                
                # Check if NFO exists
                if request.skip_existing:
                    has_nfo = await nfo_service.check_nfo_exists(serie_folder)
                    if has_nfo:
                        return NFOBatchResult(
                            serie_id=serie_id,
                            serie_folder=serie_folder,
                            success=False,
                            message="Skipped - NFO already exists"
                        )
                
                # Create NFO
                nfo_path = await nfo_service.create_tvshow_nfo(
                    serie_name=serie.name or serie_folder,
                    serie_folder=serie_folder,
                    download_poster=request.download_media,
                    download_logo=request.download_media,
                    download_fanart=request.download_media
                )
                
                return NFOBatchResult(
                    serie_id=serie_id,
                    serie_folder=serie_folder,
                    success=True,
                    message="NFO created successfully",
                    nfo_path=str(nfo_path)
                )
                
            except TMDBAPIError as e:
                logger.warning("TMDB API error for %s, creating minimal fallback: %s", serie_id, e)
                # TMDB failed, create minimal NFO
                try:
                    serie_folder = serie.ensure_folder_with_year()
                except Exception:
                    serie_folder = serie_folder
                
                serie_name = serie.name or serie_folder
                nfo_path = await nfo_service.create_minimal_nfo(
                    serie_name=serie_name,
                    serie_folder=serie_folder
                )
                
                return NFOBatchResult(
                    serie_id=serie_id,
                    serie_folder=serie_folder,
                    success=True,
                    message="Created minimal NFO (TMDB lookup failed)",
                    nfo_path=str(nfo_path)
                )
            except Exception as e:
                logger.error(
                    f"Error creating NFO for {serie_id}: {e}",
                    exc_info=True
                )
                return NFOBatchResult(
                    serie_id=serie_id,
                    serie_folder=serie.folder if serie else "",
                    success=False,
                    message=f"Error: {str(e)}"
                )
    
    # Process all series concurrently
    tasks = [process_serie(sid) for sid in request.serie_ids]
    results = await asyncio.gather(*tasks)
    
    # Count results
    for result in results:
        if result.success:
            successful += 1
        elif "Skipped" in result.message:
            skipped += 1
        else:
            failed += 1
    
    return NFOBatchCreateResponse(
        total=len(request.serie_ids),
        successful=successful,
        failed=failed,
        skipped=skipped,
        results=list(results)
    )


@router.get("/missing", response_model=NFOMissingResponse)
async def get_missing_nfo(
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
    nfo_service: NFOService = Depends(get_nfo_service)
) -> NFOMissingResponse:
    """Get list of series without NFO files.
    
    Args:
        _auth: Authentication dependency
        series_app: Series app dependency
        nfo_service: NFO service dependency
        
    Returns:
        NFOMissingResponse with series list
    """
    try:
        series_list = series_app.list.GetList()
        missing_series: List[NFOMissingSeries] = []
        
        for serie in series_list:
            serie_id = getattr(serie, 'key', None)
            if not serie_id:
                continue
            
            # Ensure folder name includes year if available
            serie_folder = serie.ensure_folder_with_year()
            has_nfo = await nfo_service.check_nfo_exists(serie_folder)
            
            if not has_nfo:
                # Build full path and check media files
                folder_path = Path(settings.anime_directory) / serie_folder
                media_status = check_media_files(folder_path)
                file_paths = get_media_file_paths(folder_path)
                
                media_files = MediaFilesStatus(
                    has_poster=media_status.get("poster", False),
                    has_logo=media_status.get("logo", False),
                    has_fanart=media_status.get("fanart", False),
                    poster_path=str(file_paths["poster"]) if file_paths.get("poster") else None,
                    logo_path=str(file_paths["logo"]) if file_paths.get("logo") else None,
                    fanart_path=str(file_paths["fanart"]) if file_paths.get("fanart") else None
                )
                
                has_media = (
                    media_files.has_poster
                    or media_files.has_logo
                    or media_files.has_fanart
                )
                
                missing_series.append(NFOMissingSeries(
                    serie_id=serie_id,
                    serie_folder=serie_folder,
                    serie_name=serie.name or serie_folder,
                    has_media=has_media,
                    media_files=media_files
                ))
        
        return NFOMissingResponse(
            total_series=len(series_list),
            missing_nfo_count=len(missing_series),
            series=missing_series
        )
        
    except Exception as e:
        logger.exception("Error getting missing NFOs: %s", e)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to get missing NFOs: {str(e)}"
        ) from e


# =============================================================================
# Series-specific endpoints (with {serie_id} path parameter)
# These must come AFTER literal path routes like /batch/create and /missing
# =============================================================================


@router.get("/{serie_id}/check", response_model=NFOCheckResponse)
async def check_nfo(
    serie_id: str,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
    nfo_service: NFOService = Depends(get_nfo_service)
) -> NFOCheckResponse:
    """Check if NFO and media files exist for a series.
    
    Args:
        serie_id: Series identifier
        _auth: Authentication dependency
        series_app: Series app dependency
        nfo_service: NFO service dependency
        
    Returns:
        NFOCheckResponse with NFO and media status
        
    Raises:
        HTTPException: If series not found
    """
    try:
        # Get series info
        series_list = series_app.list.GetList()
        serie = next(
            (s for s in series_list if getattr(s, 'key', None) == serie_id),
            None
        )
        
        if not serie:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Series not found: {serie_id}"
            )
        
        # Ensure folder name includes year if available
        serie_folder = serie.ensure_folder_with_year()
        folder_path = Path(settings.anime_directory) / serie_folder
        
        # Check NFO
        has_nfo = await nfo_service.check_nfo_exists(serie_folder)
        nfo_path = None
        if has_nfo:
            nfo_path = str(folder_path / "tvshow.nfo")
        
        # Check media files using utility function
        media_status = check_media_files(
            folder_path,
            check_poster=True,
            check_logo=True,
            check_fanart=True,
            check_nfo=False  # Already checked above
        )
        
        # Get file paths
        file_paths = get_media_file_paths(folder_path)
        
        # Build MediaFilesStatus model
        media_files = MediaFilesStatus(
            has_poster=media_status.get("poster", False),
            has_logo=media_status.get("logo", False),
            has_fanart=media_status.get("fanart", False),
            poster_path=str(file_paths["poster"]) if file_paths["poster"] else None,
            logo_path=str(file_paths["logo"]) if file_paths["logo"] else None,
            fanart_path=str(file_paths["fanart"]) if file_paths["fanart"] else None
        )
        
        return NFOCheckResponse(
            serie_id=serie_id,
            serie_folder=serie_folder,
            has_nfo=has_nfo,
            nfo_path=nfo_path,
            media_files=media_files
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.exception("Error checking NFO for %s: %s", serie_id, e)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to check NFO: {str(e)}"
        ) from e


@router.post("/{serie_id}/create", response_model=NFOCreateResponse)
async def create_nfo(
    serie_id: str,
    request: NFOCreateRequest,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
    nfo_service: NFOService = Depends(get_nfo_service)
) -> NFOCreateResponse:
    """Create NFO file and download media for a series.
    
    Args:
        serie_id: Series identifier
        request: NFO creation options
        _auth: Authentication dependency
        series_app: Series app dependency
        nfo_service: NFO service dependency
        
    Returns:
        NFOCreateResponse with creation result
        
    Raises:
        HTTPException: If series not found or creation fails
    """
    try:
        # Get series info
        series_list = series_app.list.GetList()
        serie = next(
            (s for s in series_list if getattr(s, 'key', None) == serie_id),
            None
        )
        
        if not serie:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Series not found: {serie_id}"
            )
        
        # Ensure folder name includes year if available
        serie_folder = serie.ensure_folder_with_year()
        
        # If year not provided in request but serie has year, use it
        year = request.year or serie.year
        
        # Check if NFO already exists
        if not request.overwrite_existing:
            has_nfo = await nfo_service.check_nfo_exists(serie_folder)
            if has_nfo:
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="NFO already exists. Use overwrite_existing=true"
                )
        
        # Create NFO
        serie_name = request.serie_name or serie.name or serie_folder
        nfo_path = await nfo_service.create_tvshow_nfo(
            serie_name=serie_name,
            serie_folder=serie_folder,
            year=year,
            download_poster=request.download_poster,
            download_logo=request.download_logo,
            download_fanart=request.download_fanart
        )
        
        # Check media files
        folder_path = Path(settings.anime_directory) / serie_folder
        media_status = check_media_files(folder_path)
        file_paths = get_media_file_paths(folder_path)
        
        media_files = MediaFilesStatus(
            has_poster=media_status.get("poster", False),
            has_logo=media_status.get("logo", False),
            has_fanart=media_status.get("fanart", False),
            poster_path=str(file_paths["poster"]) if file_paths.get("poster") else None,
            logo_path=str(file_paths["logo"]) if file_paths.get("logo") else None,
            fanart_path=str(file_paths["fanart"]) if file_paths.get("fanart") else None
        )
        
        return NFOCreateResponse(
            serie_id=serie_id,
            serie_folder=serie_folder,
            nfo_path=str(nfo_path),
            media_files=media_files,
            message="NFO and media files created successfully"
        )
        
    except HTTPException:
        raise
    except TMDBAPIError as e:
        logger.warning("TMDB API error for %s, creating minimal fallback: %s", serie_id, e)
        # TMDB failed, create minimal NFO with just folder name
        try:
            serie_folder = serie.ensure_folder_with_year()
        except Exception:
            serie_folder = serie_folder
        
        folder_path = Path(settings.anime_directory) / serie_folder
        serie_name_fallback = request.serie_name or serie.name or serie_folder
        
        nfo_path = await nfo_service.create_minimal_nfo(
            serie_name=serie_name_fallback,
            serie_folder=serie_folder,
            year=year
        )
        
        # Check media files (will likely be empty)
        media_status = check_media_files(folder_path)
        file_paths = get_media_file_paths(folder_path)
        
        media_files = MediaFilesStatus(
            has_poster=media_status.get("poster", False),
            has_logo=media_status.get("logo", False),
            has_fanart=media_status.get("fanart", False),
            poster_path=str(file_paths["poster"]) if file_paths.get("poster") else None,
            logo_path=str(file_paths["logo"]) if file_paths.get("logo") else None,
            fanart_path=str(file_paths["fanart"]) if file_paths.get("fanart") else None
        )
        
        return NFOCreateResponse(
            serie_id=serie_id,
            serie_folder=serie_folder,
            nfo_path=str(nfo_path),
            media_files=media_files,
            message="Created minimal NFO (TMDB lookup failed)"
        )
    except Exception as e:
        logger.error(
            f"Error creating NFO for {serie_id}: {e}",
            exc_info=True
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to create NFO: {str(e)}"
        ) from e


@router.put("/{serie_id}/update", response_model=NFOCreateResponse)
async def update_nfo(
    serie_id: str,
    download_media: bool = True,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
    nfo_service: NFOService = Depends(get_nfo_service)
) -> NFOCreateResponse:
    """Update existing NFO file with fresh TMDB data.
    
    Args:
        serie_id: Series identifier
        download_media: Whether to re-download media files
        _auth: Authentication dependency
        series_app: Series app dependency
        nfo_service: NFO service dependency
        
    Returns:
        NFOCreateResponse with update result
        
    Raises:
        HTTPException: If series or NFO not found
    """
    try:
        # Get series info
        series_list = series_app.list.GetList()
        serie = next(
            (s for s in series_list if getattr(s, 'key', None) == serie_id),
            None
        )
        
        if not serie:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Series not found: {serie_id}"
            )
        
        # Ensure folder name includes year if available
        serie_folder = serie.ensure_folder_with_year()
        
        # Check if NFO exists
        has_nfo = await nfo_service.check_nfo_exists(serie_folder)
        if not has_nfo:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="NFO file not found. Use create endpoint instead."
            )
        
        # Update NFO
        nfo_path = await nfo_service.update_tvshow_nfo(
            serie_folder=serie_folder,
            download_media=download_media
        )
        
        # Check media files
        folder_path = Path(settings.anime_directory) / serie_folder
        media_status = check_media_files(folder_path)
        file_paths = get_media_file_paths(folder_path)
        
        media_files = MediaFilesStatus(
            has_poster=media_status.get("poster", False),
            has_logo=media_status.get("logo", False),
            has_fanart=media_status.get("fanart", False),
            poster_path=str(file_paths["poster"]) if file_paths.get("poster") else None,
            logo_path=str(file_paths["logo"]) if file_paths.get("logo") else None,
            fanart_path=str(file_paths["fanart"]) if file_paths.get("fanart") else None
        )
        
        return NFOCreateResponse(
            serie_id=serie_id,
            serie_folder=serie_folder,
            nfo_path=str(nfo_path),
            media_files=media_files,
            message="NFO updated successfully"
        )
        
    except HTTPException:
        raise
    except TMDBAPIError as e:
        logger.warning("TMDB API error updating NFO for %s: %s", serie_id, e)
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail=f"TMDB API error: {str(e)}"
        ) from e
    except Exception as e:
        logger.error(
            f"Error updating NFO for {serie_id}: {e}",
            exc_info=True
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update NFO: {str(e)}"
        ) from e


@router.get("/{serie_id}/content", response_model=NFOContentResponse)
async def get_nfo_content(
    serie_id: str,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
    nfo_service: NFOService = Depends(get_nfo_service)
) -> NFOContentResponse:
    """Get NFO file content for a series.
    
    Args:
        serie_id: Series identifier
        _auth: Authentication dependency
        series_app: Series app dependency
        nfo_service: NFO service dependency
        
    Returns:
        NFOContentResponse with NFO content
        
    Raises:
        HTTPException: If series or NFO not found
    """
    try:
        # Get series info
        series_list = series_app.list.GetList()
        serie = next(
            (s for s in series_list if getattr(s, 'key', None) == serie_id),
            None
        )
        
        if not serie:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Series not found: {serie_id}"
            )
        
        # Ensure folder name includes year if available
        serie_folder = serie.ensure_folder_with_year()
        
        # Check if NFO exists
        nfo_path = (
            Path(settings.anime_directory) / serie_folder / "tvshow.nfo"
        )
        if not nfo_path.exists():
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="NFO file not found"
            )
        
        # Read NFO content
        content = nfo_path.read_text(encoding="utf-8")
        file_size = nfo_path.stat().st_size
        last_modified = datetime.fromtimestamp(nfo_path.stat().st_mtime)
        
        return NFOContentResponse(
            serie_id=serie_id,
            serie_folder=serie_folder,
            content=content,
            file_size=file_size,
            last_modified=last_modified
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(
            f"Error reading NFO content for {serie_id}: {e}",
            exc_info=True
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to read NFO content: {str(e)}"
        ) from e


@router.get("/{serie_id}/media/status", response_model=MediaFilesStatus)
async def get_media_status(
    serie_id: str,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app)
) -> MediaFilesStatus:
    """Get media files status for a series.
    
    Args:
        serie_id: Series identifier
        _auth: Authentication dependency
        series_app: Series app dependency
        
    Returns:
        MediaFilesStatus with file existence info
        
    Raises:
        HTTPException: If series not found
    """
    try:
        # Get series info
        series_list = series_app.list.GetList()
        serie = next(
            (s for s in series_list if getattr(s, 'key', None) == serie_id),
            None
        )
        
        if not serie:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Series not found: {serie_id}"
            )
        
        # Build full path and check media files
        folder_path = Path(settings.anime_directory) / serie.folder
        media_status = check_media_files(folder_path)
        file_paths = get_media_file_paths(folder_path)
        
        return MediaFilesStatus(
            has_poster=media_status.get("poster", False),
            has_logo=media_status.get("logo", False),
            has_fanart=media_status.get("fanart", False),
            poster_path=str(file_paths["poster"]) if file_paths.get("poster") else None,
            logo_path=str(file_paths["logo"]) if file_paths.get("logo") else None,
            fanart_path=str(file_paths["fanart"]) if file_paths.get("fanart") else None
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(
            f"Error checking media status for {serie_id}: {e}",
            exc_info=True
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to check media status: {str(e)}"
        ) from e


@router.post("/{serie_id}/media/download", response_model=MediaFilesStatus)
async def download_media(
    serie_id: str,
    request: MediaDownloadRequest,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
    nfo_service: NFOService = Depends(get_nfo_service)
) -> MediaFilesStatus:
    """Download missing media files for a series.
    
    Args:
        serie_id: Series identifier
        request: Media download options
        _auth: Authentication dependency
        series_app: Series app dependency
        nfo_service: NFO service dependency
        
    Returns:
        MediaFilesStatus after download attempt
        
    Raises:
        HTTPException: If series or NFO not found
    """
    try:
        # Get series info
        series_list = series_app.list.GetList()
        serie = next(
            (s for s in series_list if getattr(s, 'key', None) == serie_id),
            None
        )
        
        if not serie:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Series not found: {serie_id}"
            )
        
        # Ensure folder name includes year if available
        serie_folder = serie.ensure_folder_with_year()
        
        # Check if NFO exists (needed for TMDB ID)
        has_nfo = await nfo_service.check_nfo_exists(serie_folder)
        if not has_nfo:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="NFO required for media download. Create NFO first."
            )
        
        # For now, update NFO which will re-download media
        # In future, could add standalone media download
        if (request.download_poster or request.download_logo
                or request.download_fanart):
            await nfo_service.update_tvshow_nfo(
                serie_folder=serie_folder,
                download_media=True
            )
        
        # Build full path and check media files
        folder_path = Path(settings.anime_directory) / serie_folder
        media_status = check_media_files(folder_path)
        file_paths = get_media_file_paths(folder_path)
        
        return MediaFilesStatus(
            has_poster=media_status.get("poster", False),
            has_logo=media_status.get("logo", False),
            has_fanart=media_status.get("fanart", False),
            poster_path=str(file_paths["poster"]) if file_paths.get("poster") else None,
            logo_path=str(file_paths["logo"]) if file_paths.get("logo") else None,
            fanart_path=str(file_paths["fanart"]) if file_paths.get("fanart") else None
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(
            f"Error downloading media for {serie_id}: {e}",
            exc_info=True
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to download media: {str(e)}"
        ) from e


@router.get("/{serie_key}/diagnostics", response_model=NfoDiagnosticsResponse)
async def get_nfo_diagnostics(
    serie_key: str,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
) -> NfoDiagnosticsResponse:
    """Get NFO diagnostics showing missing required tags.

    Args:
        serie_key: Series key identifier
        _auth: Authentication dependency
        series_app: SeriesApp instance

    Returns:
        NfoDiagnosticsResponse with has_nfo, missing_tags, required_tags

    Raises:
        HTTPException 404: Series not found
    """
    serie = None
    for s in series_app.list.GetList():
        if getattr(s, "key", None) == serie_key:
            serie = s
            break

    if not serie:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Series with key '{serie_key}' not found",
        )

    serie_folder = serie.ensure_folder_with_year()
    folder_path = Path(settings.anime_directory) / serie_folder
    nfo_path = folder_path / "tvshow.nfo"

    required_tag_names = list(REQUIRED_TAGS.values())

    if not nfo_path.exists():
        return NfoDiagnosticsResponse(
            has_nfo=False,
            nfo_path=None,
            missing_tags=required_tag_names,
            required_tags=required_tag_names,
        )

    missing = find_missing_tags(nfo_path)

    return NfoDiagnosticsResponse(
        has_nfo=True,
        nfo_path=str(nfo_path),
        missing_tags=missing,
        required_tags=required_tag_names,
    )


@router.post("/{serie_key}/repair", response_model=NfoRepairResponse)
async def repair_nfo(
    serie_key: str,
    _auth: dict = Depends(require_auth),
    series_app: SeriesApp = Depends(get_series_app),
    nfo_service: NFOService = Depends(get_nfo_service),
) -> NfoRepairResponse:
    """Repair or recreate NFO file for a series.

    Detects missing required tags and re-fetches metadata from TMDB.

    Args:
        serie_key: Series key identifier
        _auth: Authentication dependency
        series_app: SeriesApp instance
        nfo_service: NFO service for TMDB operations

    Returns:
        NfoRepairResponse with success status and details

    Raises:
        HTTPException 404: Series not found
        HTTPException 400: Cannot repair (e.g., no TMDB data available)
    """
    serie = None
    for s in series_app.list.GetList():
        if getattr(s, "key", None) == serie_key:
            serie = s
            break

    if not serie:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Series with key '{serie_key}' not found",
        )

    serie_folder = serie.ensure_folder_with_year()
    folder_path = Path(settings.anime_directory) / serie_folder
    nfo_path = folder_path / "tvshow.nfo"

    # Get missing tags before repair for reporting
    missing_before = find_missing_tags(nfo_path) if nfo_path.exists() else list(REQUIRED_TAGS.values())

    try:
        repair_service = NfoRepairService(nfo_service)

        if nfo_path.exists():
            repaired = await repair_service.repair_series(folder_path, serie_folder)
            if not repaired:
                return NfoRepairResponse(
                    success=True,
                    message="NFO is already complete, no repair needed",
                    repaired_tags=[],
                )
        else:
            # No NFO exists — create new one
            await nfo_service.create_tvshow_nfo(
                serie_name=serie.name,
                serie_folder=serie_folder,
                download_poster=True,
                download_logo=True,
                download_fanart=True,
            )

        return NfoRepairResponse(
            success=True,
            message=f"NFO repaired successfully. Fixed {len(missing_before)} missing tags.",
            repaired_tags=missing_before,
        )

    except TMDBAPIError as e:
        logger.warning("NFO repair failed for '%s': %s", serie_key, e)
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Cannot repair NFO: {str(e)}. Ensure TMDB ID is set.",
        ) from e
    except Exception as e:
        logger.error("NFO repair error for '%s': %s", serie_key, e, exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to repair NFO: {str(e)}",
        ) from e
