import logging
from typing import Any, Dict, List, Optional

from fastapi import APIRouter, Depends, HTTPException, status

logger = logging.getLogger(__name__)

from src.server.models.config import AppConfig, ConfigUpdate, ValidationResult
from src.server.services.config_service import (
    ConfigBackupError,
    ConfigServiceError,
    ConfigValidationError,
    get_config_service,
)
from src.server.utils.dependencies import require_auth

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


@router.get("", response_model=AppConfig)
def get_config(auth: Optional[dict] = Depends(require_auth)) -> AppConfig:
    """Return current application configuration."""
    try:
        config_service = get_config_service()
        return config_service.load_config()
    except ConfigServiceError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to load config: {e}"
        ) from e


@router.put("", response_model=AppConfig)
async def update_config(
    update: ConfigUpdate, auth: dict = Depends(require_auth)
) -> AppConfig:
    """Apply an update to the configuration and persist it.

    Creates automatic backup before applying changes. If anime_directory
    is configured, starts the scheduler service.
    """
    try:
        config_service = get_config_service()
        updated_config = config_service.update_config(update)

        # Sync anime_directory to settings if it was updated
        from src.config.settings import settings as app_settings

        anime_dir_changed = False
        if update.other and update.other.get("anime_directory"):
            anime_dir = update.other.get("anime_directory")
            if anime_dir and not app_settings.anime_directory:
                app_settings.anime_directory = str(anime_dir)
                anime_dir_changed = True
                logger.info("Synced anime_directory from config: %s", anime_dir)

        # Start scheduler if anime_directory was just configured
        if anime_dir_changed:
            try:
                from src.server.services.scheduler_service import (
                    get_scheduler_service,
                )

                scheduler_svc = get_scheduler_service()
                logger.info(
                    "Starting scheduler after anime_directory configuration"
                )
                await scheduler_svc.ensure_started()
                logger.info(
                    "Scheduler started successfully after config update"
                )
            except Exception as sched_exc:
                logger.warning(
                    "Failed to start scheduler after config update: %s",
                    sched_exc,
                )
                # Config was already saved, don't fail the request

        return updated_config

    except ConfigValidationError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid configuration: {e}"
        ) from e
    except ConfigServiceError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update config: {e}"
        ) from e


@router.post("/validate", response_model=ValidationResult)
def validate_config(
    cfg: AppConfig, auth: dict = Depends(require_auth)  # noqa: ARG001
) -> ValidationResult:
    """Validate a provided AppConfig without applying it.

    Returns ValidationResult with any validation errors.
    """
    try:
        config_service = get_config_service()
        return config_service.validate_config(cfg)
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        ) from e


@router.get("/backups", response_model=List[Dict[str, object]])
def list_backups(
    auth: dict = Depends(require_auth)
) -> List[Dict[str, object]]:
    """List all available configuration backups.

    Returns list of backup metadata including name, size, and created time.
    """
    try:
        config_service = get_config_service()
        return config_service.list_backups()
    except ConfigServiceError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to list backups: {e}"
        ) from e


@router.post("/backups", response_model=Dict[str, str])
def create_backup(
    name: Optional[str] = None, auth: dict = Depends(require_auth)
) -> Dict[str, str]:
    """Create a backup of the current configuration.

    Args:
        name: Optional custom backup name (timestamp used if not provided)

    Returns:
        Dictionary with backup name and message
    """
    try:
        config_service = get_config_service()
        backup_path = config_service.create_backup(name)
        return {
            "name": backup_path.name,
            "message": "Backup created successfully"
        }
    except ConfigBackupError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Failed to create backup: {e}"
        ) from e


@router.post("/backups/{backup_name}/restore", response_model=AppConfig)
def restore_backup(
    backup_name: str, auth: dict = Depends(require_auth)
) -> AppConfig:
    """Restore configuration from a backup.

    Creates backup of current config before restoring.

    Args:
        backup_name: Name of backup file to restore

    Returns:
        Restored configuration
    """
    try:
        config_service = get_config_service()
        return config_service.restore_backup(backup_name)
    except ConfigBackupError as e:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Failed to restore backup: {e}"
        ) from e


@router.delete("/backups/{backup_name}")
def delete_backup(
    backup_name: str, auth: dict = Depends(require_auth)
) -> Dict[str, str]:
    """Delete a configuration backup.

    Args:
        backup_name: Name of backup file to delete

    Returns:
        Success message
    """
    try:
        config_service = get_config_service()
        config_service.delete_backup(backup_name)
        return {"message": f"Backup '{backup_name}' deleted successfully"}
    except ConfigBackupError as e:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Failed to delete backup: {e}"
        ) from e


@router.get("/section/advanced", response_model=Dict[str, object])
def get_advanced_config(
    auth: Optional[dict] = Depends(require_auth)
) -> Dict[str, object]:
    """Get advanced configuration section.

    Returns:
        Dictionary with advanced configuration settings
    """
    try:
        config_service = get_config_service()
        app_config = config_service.load_config()
        return app_config.other.get("advanced", {})
    except ConfigServiceError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to load advanced config: {e}"
        ) from e


@router.post("/section/advanced", response_model=Dict[str, str])
def update_advanced_config(
    config: Dict[str, object], auth: dict = Depends(require_auth)
) -> Dict[str, str]:
    """Update advanced configuration section.

    Args:
        config: Advanced configuration settings
        auth: Authentication token (required)

    Returns:
        Success message
    """
    try:
        config_service = get_config_service()
        app_config = config_service.load_config()

        # Update advanced section in other
        if "advanced" not in app_config.other:
            app_config.other["advanced"] = {}
        app_config.other["advanced"].update(config)

        config_service.save_config(app_config)
        return {"message": "Advanced configuration updated successfully"}
    except ConfigServiceError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update advanced config: {e}"
        ) from e


@router.post("/directory", response_model=Dict[str, Any])
async def update_directory(
    directory_config: Dict[str, str], auth: dict = Depends(require_auth)
) -> Dict[str, Any]:
    """Update anime directory configuration.

    Args:
        directory_config: Dictionary with 'directory' key
        auth: Authentication token (required)

    Returns:
        Success message
    """
    try:
        directory = directory_config.get("directory")
        if not directory:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Directory path is required"
            )

        config_service = get_config_service()
        app_config = config_service.load_config()

        # Store directory in other section
        app_config.other["anime_directory"] = directory

        config_service.save_config(app_config)
        
        # Sync series from data files to database
        sync_count = 0
        try:
            import structlog

            from src.server.services.anime_service import sync_legacy_series_to_db
            logger = structlog.get_logger(__name__)
            sync_count = await sync_legacy_series_to_db(directory, logger)
            logger.info(
                "Directory updated: synced series from data files",
                directory=directory,
                count=sync_count
            )
        except Exception as e:
            # Log but don't fail the directory update if sync fails
            import structlog
            structlog.get_logger(__name__).warning(
                "Failed to sync series after directory update",
                error=str(e)
            )
        
        response: Dict[str, Any] = {
            "message": "Anime directory updated successfully",
            "synced_series": sync_count
        }
        
        return response
    except ConfigServiceError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update directory: {e}"
        ) from e


@router.post("/export")
async def export_config(
    export_options: Dict[str, bool], auth: dict = Depends(require_auth)
):
    """Export configuration to JSON file.

    Args:
        export_options: Options for export (include_sensitive, etc.)
        auth: Authentication token (required)

    Returns:
        JSON file download response
    """
    try:
        import json

        from fastapi.responses import Response

        config_service = get_config_service()
        app_config = config_service.load_config()

        # Convert to dict
        config_dict = app_config.model_dump()

        # Optionally remove sensitive data
        if not export_options.get("include_sensitive", False):
            # Remove sensitive fields if present
            config_dict.pop("password_salt", None)
            config_dict.pop("password_hash", None)

        # Create filename with timestamp
        from datetime import datetime
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"aniworld_config_{timestamp}.json"

        # Return as downloadable JSON
        content = json.dumps(config_dict, indent=2)
        return Response(
            content=content,
            media_type="application/json",
            headers={
                "Content-Disposition": f'attachment; filename="{filename}"'
            }
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to export config: {e}"
        ) from e


@router.post("/reset", response_model=Dict[str, str])
def reset_config(
    reset_options: Dict[str, bool], auth: dict = Depends(require_auth)
) -> Dict[str, str]:
    """Reset configuration to defaults.

    Args:
        reset_options: Options for reset (preserve_security, etc.)
        auth: Authentication token (required)

    Returns:
        Success message
    """
    try:
        config_service = get_config_service()

        # Create backup before resetting
        config_service.create_backup("pre_reset")

        # Load default config
        default_config = AppConfig()

        # If preserve_security is True, keep authentication settings
        if reset_options.get("preserve_security", True):
            current_config = config_service.load_config()
            # Preserve security-related fields from other
            if "password_salt" in current_config.other:
                default_config.other["password_salt"] = (
                    current_config.other["password_salt"]
                )
            if "password_hash" in current_config.other:
                default_config.other["password_hash"] = (
                    current_config.other["password_hash"]
                )

        # Save default config
        config_service.save_config(default_config)

        return {
            "message": "Configuration reset to defaults successfully"
        }
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to reset config: {e}"
        ) from e


@router.post("/tmdb/validate", response_model=Dict[str, Any])
async def validate_tmdb_key(
    api_key_data: Dict[str, str], auth: dict = Depends(require_auth)
) -> Dict[str, Any]:
    """Validate TMDB API key by making a test request.

    Args:
        api_key_data: Dictionary with 'api_key' field
        auth: Authentication token (required)

    Returns:
        Validation result with success status and message
    """
    import aiohttp
    
    api_key = api_key_data.get("api_key", "").strip()
    
    if not api_key:
        return {
            "valid": False,
            "message": "API key is required"
        }
    
    try:
        # Test the API key with a simple configuration request
        url = f"https://api.themoviedb.org/3/configuration?api_key={api_key}"
        
        timeout = aiohttp.ClientTimeout(total=10)
        async with aiohttp.ClientSession() as session:
            async with session.get(url, timeout=timeout) as response:
                if response.status == 200:
                    return {
                        "valid": True,
                        "message": "TMDB API key is valid"
                    }
                elif response.status == 401:
                    return {
                        "valid": False,
                        "message": "Invalid API key"
                    }
                else:
                    return {
                        "valid": False,
                        "message": f"TMDB API error: {response.status}"
                    }
    except aiohttp.ClientError as e:
        return {
            "valid": False,
            "message": f"Connection error: {str(e)}"
        }
    except Exception as e:
        return {
            "valid": False,
            "message": f"Validation error: {str(e)}"
        }
