"""Authentication Pydantic models for the Aniworld web application.

This module defines simple request/response shapes used by the auth API and
by the authentication service. Keep models small and focused so they are
easy to validate and test.
"""
from __future__ import annotations

import re
from datetime import datetime, timezone
from typing import Optional

from pydantic import BaseModel, Field, field_validator


class LoginRequest(BaseModel):
    """Request body for a login attempt.

    Fields:
    - password: master password string (minimum 8 chars recommended)
    - remember: optional flag to request a long-lived session
    """

    password: str = Field(..., min_length=1, description="Master password")
    remember: Optional[bool] = Field(
        False, description="Keep session alive"
    )


class LoginResponse(BaseModel):
    """Response returned after a successful login."""

    access_token: str = Field(..., description="JWT access token")
    token_type: str = Field("bearer", description="Token type")
    expires_at: Optional[datetime] = Field(None, description="Optional expiry timestamp")


class SetupRequest(BaseModel):
    """Request to initialize the master password during first-time setup.
    
    This request includes all configuration fields needed to set up the application.
    """

    # Required fields
    master_password: str = Field(
        ..., min_length=8, description="New master password"
    )
    anime_directory: Optional[str] = Field(
        None, description="Optional anime directory path"
    )
    
    # Application settings
    name: Optional[str] = Field(
        default="Aniworld", description="Application name"
    )
    data_dir: Optional[str] = Field(
        default="data", description="Data directory path"
    )
    
    # Scheduler configuration
    scheduler_enabled: Optional[bool] = Field(
        default=True, description="Enable/disable scheduler"
    )
    scheduler_interval_minutes: Optional[int] = Field(
        default=60, ge=1, description="Scheduler interval in minutes (legacy)"
    )
    scheduler_schedule_time: Optional[str] = Field(
        default="03:00", description="Daily run time in HH:MM format"
    )
    scheduler_schedule_days: Optional[list] = Field(
        default=None, description="Days of week to run scheduler (mon-sun)"
    )
    scheduler_auto_download_after_rescan: Optional[bool] = Field(
        default=False, description="Auto-download missing episodes after rescan"
    )
    scheduler_folder_scan_enabled: Optional[bool] = Field(
        default=False, description="Run folder maintenance during scheduled run"
    )
    
    # Logging configuration
    logging_level: Optional[str] = Field(
        default="INFO", description="Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)"
    )
    logging_file: Optional[str] = Field(
        default=None, description="Log file path"
    )
    logging_max_bytes: Optional[int] = Field(
        default=None, ge=0, description="Max log file size in bytes"
    )
    logging_backup_count: Optional[int] = Field(
        default=3, ge=0, description="Number of backup log files"
    )
    
    # Backup configuration
    backup_enabled: Optional[bool] = Field(
        default=False, description="Enable/disable backups"
    )
    backup_path: Optional[str] = Field(
        default="data/backups", description="Backup directory path"
    )
    backup_keep_days: Optional[int] = Field(
        default=30, ge=0, description="Days to keep backups"
    )
    
    # NFO configuration
    nfo_tmdb_api_key: Optional[str] = Field(
        default=None, description="TMDB API key"
    )
    nfo_auto_create: Optional[bool] = Field(
        default=True, description="Auto-create NFO files"
    )
    nfo_update_on_scan: Optional[bool] = Field(
        default=True, description="Update NFO on scan"
    )
    nfo_download_poster: Optional[bool] = Field(
        default=True, description="Download poster images"
    )
    nfo_download_logo: Optional[bool] = Field(
        default=True, description="Download logo images"
    )
    nfo_download_fanart: Optional[bool] = Field(
        default=True, description="Download fanart images"
    )
    nfo_image_size: Optional[str] = Field(
        default="original", description="Image size preference (original or w500)"
    )
    
    @field_validator("logging_level")
    @classmethod
    def validate_logging_level(cls, v: Optional[str]) -> Optional[str]:
        """Validate logging level."""
        if v is None:
            return v
        allowed = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
        lvl = v.upper()
        if lvl not in allowed:
            raise ValueError(f"Invalid logging level: {v}. Must be one of {allowed}")
        return lvl
    
    @field_validator("nfo_image_size")
    @classmethod
    def validate_image_size(cls, v: Optional[str]) -> Optional[str]:
        """Validate image size."""
        if v is None:
            return v
        allowed = {"original", "w500"}
        size = v.lower()
        if size not in allowed:
            raise ValueError(f"Invalid image size: {v}. Must be 'original' or 'w500'")
        return size


class AuthStatus(BaseModel):
    """Public status about whether auth is configured and the current user state."""

    configured: bool = Field(..., description="Whether a master password is set")
    authenticated: bool = Field(False, description="Whether the caller is authenticated")


class SessionModel(BaseModel):
    """Lightweight session representation stored/returned by the auth service.

    This model can be persisted if a persistent session store is used.
    """

    session_id: str = Field(..., description="Unique session identifier")
    user: Optional[str] = Field(None, description="Username or identifier")
    created_at: datetime = Field(
        default_factory=lambda: datetime.now(timezone.utc)
    )
    expires_at: Optional[datetime] = Field(None)


class RegisterRequest(BaseModel):
    """Request to register a new user (for testing purposes)."""

    username: str = Field(
        ..., min_length=3, max_length=50, description="Username"
    )
    password: str = Field(..., min_length=8, description="Password")
    email: str = Field(..., description="Email address")

    @field_validator("email")
    @classmethod
    def validate_email(cls, v: str) -> str:
        """Validate email format."""
        # Basic email validation
        pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
        if not re.match(pattern, v):
            raise ValueError("Invalid email address")
        return v

    @field_validator("username")
    @classmethod
    def validate_username(cls, v: str) -> str:
        """Validate username contains no special characters."""
        if not re.match(r"^[a-zA-Z0-9_-]+$", v):
            raise ValueError(
                "Username can only contain letters, numbers, underscore, "
                "and hyphen"
            )
        return v


