"""
Configuration module for Gradio application.

Loads configuration from:
- config.yaml: General app settings (committed to git)
- .env: Secrets and user-specific settings (git-ignored)
"""

from pathlib import Path
from typing import Any, Dict, List, Optional

import yaml
from pydantic import BaseModel, Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
from rich.console import Console


class RepositoryInfo(BaseModel):
    """Information about a project repository."""

    repo_name: str = Field(description="Repository name")
    repo_url: str = Field(description="Repository URL")

    @property
    def path(self) -> Path:
        """
        Get the full path to the repository.

        Uses settings.hf_repo_dir as the base directory.

        Returns:
            Full path to repository

        Raises:
            ValueError: If hf_repo_dir is not set in .env configuration
        """
        # Import here to avoid circular dependency
        from config import settings

        if settings.hf_repo_dir is None:
            raise ValueError(
                f"HF_REPO_DIR is not set in .env file. "
                f"Please set it to use repository path for '{self.repo_name}'"
            )
        return settings.hf_repo_dir / self.repo_name


class AppConfig(BaseModel):
    """Configuration for an individual app."""

    title: str = Field(description="Display title for the app")
    icon: str = Field(default="📱", description="Emoji icon for the app")
    description: str = Field(default="", description="Description of the app")
    enabled: bool = Field(default=True, description="Whether the app is enabled")
    order: int = Field(default=100, description="Display order (lower numbers first)")
    config: Optional[Dict[str, Any]] = Field(
        default=None,
        description="App-specific configuration (dict that can be converted to Pydantic model)",
    )


class Settings(BaseSettings):
    """Application settings loaded from config.yaml and .env files."""

    # App Configuration (from config.yaml)
    project_name: str = Field(default="MyProject", description="Project name")
    project_title: str = Field(
        default="My Project - Dynamic Gradio Apps", description="Project title"
    )
    project_description: str = Field(
        default="A flexible Gradio-based application framework",
        description="Project description",
    )
    apps_directory: str = Field(
        default="apps", description="Directory containing app modules"
    )
    theme: str = Field(default="default", description="Gradio theme")
    share: bool = Field(
        default=False, description="Whether to create a public share link"
    )
    server_name: str = Field(default="127.0.0.1", description="Server host")
    server_port: int = Field(default=7860, description="Server port")
    gradio_mount_path: str = Field(default="/", description="Path to mount Gradio app")
    cors_origins: List[str] = Field(
        default=["*"], description="Allowed CORS origins"
    )

    # Project Repositories (from config.yaml)
    repositories: Optional[List[RepositoryInfo]] = Field(
        default=None, description="List of project repositories"
    )

    # Logging Configuration (from config.yaml)
    logging: Optional[Dict[str, Any]] = Field(
        default=None, description="Logging configuration"
    )

    # App-specific configurations
    apps: Dict[str, AppConfig] = Field(
        default_factory=dict, description="App configurations"
    )

    # Secrets (from .env)
    hf_token: Optional[str] = Field(default=None, description="Hugging Face API token")
    openai_api_key: Optional[str] = Field(default=None, description="OpenAI API key")
    anthropic_api_key: Optional[str] = Field(
        default=None, description="Anthropic API key"
    )

    # Hugging Face Directories (from .env)
    hf_repo_dir: Optional[Path] = Field(
        default=None,
        description="Hugging Face repos directory (datasets, models, etc.)",
    )
    hf_cache_dir: Optional[Path] = Field(
        default=None, description="Hugging Face cache directory"
    )

    # User-specific settings (from .env)
    debug: bool = Field(default=False, description="Enable debug mode")
    log_level: str = Field(default="INFO", description="Logging level")

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

    @field_validator("hf_repo_dir", "hf_cache_dir", mode="before")
    @classmethod
    def convert_to_path(cls, v: Any) -> Optional[Path]:
        """Convert string paths to Path objects."""
        if v is None or v == "":
            return None
        if isinstance(v, str):
            return Path(v)
        if isinstance(v, Path):
            return v
        return None

    def get_app_config(self, app_key: str) -> Optional[AppConfig]:
        """
        Get configuration for a specific app.

        Args:
            app_key: The app key (filename without .py extension)

        Returns:
            AppConfig if found, None otherwise
        """
        return self.apps.get(app_key)

    @classmethod
    def load_from_yaml(cls, yaml_path: str = "config.yaml") -> "Settings":
        """
        Load settings from YAML file and environment variables.

        Environment variables take precedence over YAML settings.

        Args:
            yaml_path: Path to the YAML configuration file

        Returns:
            Settings instance with merged configuration
        """
        config_file = Path(yaml_path)

        # Load YAML config if it exists
        yaml_config: Dict[str, Any] = {}
        if config_file.exists():
            with open(config_file, "r", encoding="utf-8") as f:
                yaml_config = yaml.safe_load(f) or {}

        # Convert app configs to AppConfig models
        if "apps" in yaml_config:
            apps_dict = {}
            for app_key, app_data in yaml_config["apps"].items():
                if isinstance(app_data, dict):
                    apps_dict[app_key] = AppConfig(**app_data)
            yaml_config["apps"] = apps_dict

        # Convert repositories to RepositoryInfo models
        if "repositories" in yaml_config and yaml_config["repositories"]:
            repos_list = []
            for repo_data in yaml_config["repositories"]:
                if isinstance(repo_data, dict):
                    repos_list.append(RepositoryInfo(**repo_data))
            yaml_config["repositories"] = repos_list

        # Create settings instance (env vars will override yaml values)
        return cls(**yaml_config)


# Global settings instance
settings = Settings.load_from_yaml()


if __name__ == "__main__":
    # Test settings loading with Rich console
    console = Console()

    console.rule("[bold cyan]Settings Configuration[/bold cyan]")
    console.print()
    console.print("[bold]Project Settings:[/bold]")
    console.print(f"  [cyan]Project Name:[/cyan] {settings.project_name}")
    console.print(f"  [cyan]Project Title:[/cyan] {settings.project_title}")
    console.print(f"  [cyan]Project Description:[/cyan] {settings.project_description}")
    console.print(f"  [cyan]Apps Directory:[/cyan] {settings.apps_directory}")
    console.print(f"  [cyan]Theme:[/cyan] {settings.theme}")
    console.print(f"  [cyan]Share:[/cyan] {settings.share}")
    console.print(
        f"  [cyan]Server:[/cyan] {settings.server_name}:{settings.server_port}"
    )
    console.print()

    console.print("[bold]Runtime Settings:[/bold]")
    console.print(f"  [cyan]Debug:[/cyan] {settings.debug}")
    console.print(f"  [cyan]Log Level:[/cyan] {settings.log_level}")
    console.print()

    console.print("[bold]API Keys:[/bold]")
    console.print(
        f"  [cyan]HuggingFace Token:[/cyan] {'[green]***[/green]' if settings.hf_token else '[dim]Not set[/dim]'}"
    )
    console.print(
        f"  [cyan]OpenAI API Key:[/cyan] {'[green]***[/green]' if settings.openai_api_key else '[dim]Not set[/dim]'}"
    )
    console.print(
        f"  [cyan]Anthropic API Key:[/cyan] {'[green]***[/green]' if settings.anthropic_api_key else '[dim]Not set[/dim]'}"
    )
    console.print()

    console.print("[bold]HuggingFace Directories:[/bold]")
    console.print(
        f"  [cyan]Repo Dir:[/cyan] {settings.hf_repo_dir or '[dim]Not set[/dim]'}"
    )
    console.print(
        f"  [cyan]Cache Dir:[/cyan] {settings.hf_cache_dir or '[dim]Not set[/dim]'}"
    )
    console.print()

    if settings.repositories:
        console.print("[bold]Project Repositories:[/bold]")
        for repo in settings.repositories:
            console.print(f"  [cyan]{repo.repo_name}:[/cyan] {repo.repo_url}")
        console.print()

    console.rule("[bold cyan]App Configurations[/bold cyan]")
    console.print()
    for app_key, app_config in settings.apps.items():
        status = (
            "[green]enabled[/green]" if app_config.enabled else "[dim]disabled[/dim]"
        )
        console.print(
            f"{app_config.icon} [bold]{app_config.title}[/bold] [dim]({app_key})[/dim] - {status}"
        )
        console.print(f"   [dim]Order: {app_config.order}[/dim]")
        console.print(f"   [dim]{app_config.description}[/dim]")
        console.print()
