"""
Web Application Configuration

Centralized configuration for the web application.
"""

import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import TYPE_CHECKING, Any

from shared.config import DEFAULT_DPI

if TYPE_CHECKING:
    from shared.storage.base import StorageBackend


def get_storage_backend(
    config_path: Path | str | None = None,
) -> "StorageBackend":
    """Get storage backend for file operations.

    Args:
        config_path: Optional path to storage configuration file.
            If not provided, uses STORAGE_CONFIG_PATH env var or falls back to env vars.

    Returns:
        Configured StorageBackend instance.
    """
    from shared.storage import get_storage_backend as _get_storage_backend

    # Check for config file path
    if config_path is None:
        config_path_str = os.environ.get("STORAGE_CONFIG_PATH")
        if config_path_str:
            config_path = Path(config_path_str)

    return _get_storage_backend(config_path=config_path)


@dataclass(frozen=True)
class ModelConfig:
    """YOLO model configuration.

    Note: Model files are stored locally (not in STORAGE_BASE_PATH) because:
    - Models need to be accessible by inference service on any platform
    - Models may be version-controlled or deployed separately
    - Models are part of the application, not user data
    """

    model_path: Path = Path("runs/train/invoice_fields/weights/best.pt")
    confidence_threshold: float = 0.5
    use_gpu: bool = True
    dpi: int = DEFAULT_DPI


@dataclass(frozen=True)
class ServerConfig:
    """Server configuration."""

    host: str = "0.0.0.0"
    port: int = 8000
    debug: bool = False
    reload: bool = False
    workers: int = 1


@dataclass(frozen=True)
class FileConfig:
    """File handling configuration.

    This config holds file handling settings. For file operations,
    use the storage backend with PREFIXES from shared.storage.prefixes.

    Example:
        from shared.storage import PREFIXES, get_storage_backend

        storage = get_storage_backend()
        path = PREFIXES.document_path(document_id)
        storage.upload_bytes(content, path)

    Note: The path fields (upload_dir, result_dir, etc.) are deprecated.
    They are kept for backward compatibility with existing code and tests.
    New code should use the storage backend with PREFIXES instead.
    """

    max_file_size_mb: int = 50
    allowed_extensions: tuple[str, ...] = (".pdf", ".png", ".jpg", ".jpeg")
    dpi: int = DEFAULT_DPI
    presigned_url_expiry_seconds: int = 3600

    # Deprecated path fields - kept for backward compatibility
    # New code should use storage backend with PREFIXES instead
    # All paths are now under data/ to match WSL storage layout
    upload_dir: Path = field(default_factory=lambda: Path("data/uploads"))
    result_dir: Path = field(default_factory=lambda: Path("data/results"))
    admin_upload_dir: Path = field(default_factory=lambda: Path("data/raw_pdfs"))
    admin_images_dir: Path = field(default_factory=lambda: Path("data/admin_images"))

    def __post_init__(self) -> None:
        """Create directories if they don't exist (for backward compatibility)."""
        object.__setattr__(self, "upload_dir", Path(self.upload_dir))
        object.__setattr__(self, "result_dir", Path(self.result_dir))
        object.__setattr__(self, "admin_upload_dir", Path(self.admin_upload_dir))
        object.__setattr__(self, "admin_images_dir", Path(self.admin_images_dir))
        self.upload_dir.mkdir(parents=True, exist_ok=True)
        self.result_dir.mkdir(parents=True, exist_ok=True)
        self.admin_upload_dir.mkdir(parents=True, exist_ok=True)
        self.admin_images_dir.mkdir(parents=True, exist_ok=True)


# Backward compatibility alias
StorageConfig = FileConfig


@dataclass(frozen=True)
class AsyncConfig:
    """Async processing configuration.

    Note: For file paths, use the storage backend with PREFIXES.
    Example: PREFIXES.upload_path(filename, "async")
    """

    # Queue settings
    queue_max_size: int = 100
    worker_count: int = 1
    task_timeout_seconds: int = 300

    # Rate limiting defaults
    default_requests_per_minute: int = 10
    default_max_concurrent_jobs: int = 3
    default_min_poll_interval_ms: int = 1000

    # Storage
    result_retention_days: int = 7
    max_file_size_mb: int = 50

    # Deprecated: kept for backward compatibility
    # Path under data/ to match WSL storage layout
    temp_upload_dir: Path = field(default_factory=lambda: Path("data/uploads/async"))

    # Cleanup
    cleanup_interval_hours: int = 1

    def __post_init__(self) -> None:
        """Create directories if they don't exist (for backward compatibility)."""
        object.__setattr__(self, "temp_upload_dir", Path(self.temp_upload_dir))
        self.temp_upload_dir.mkdir(parents=True, exist_ok=True)


@dataclass
class AppConfig:
    """Main application configuration."""

    model: ModelConfig = field(default_factory=ModelConfig)
    server: ServerConfig = field(default_factory=ServerConfig)
    file: FileConfig = field(default_factory=FileConfig)
    async_processing: AsyncConfig = field(default_factory=AsyncConfig)
    storage_backend: "StorageBackend | None" = None

    @property
    def storage(self) -> FileConfig:
        """Backward compatibility alias for file config."""
        return self.file

    @classmethod
    def from_dict(cls, config_dict: dict[str, Any]) -> "AppConfig":
        """Create config from dictionary."""
        file_config = config_dict.get("file", config_dict.get("storage", {}))
        return cls(
            model=ModelConfig(**config_dict.get("model", {})),
            server=ServerConfig(**config_dict.get("server", {})),
            file=FileConfig(**file_config),
            async_processing=AsyncConfig(**config_dict.get("async_processing", {})),
        )


def create_app_config(
    storage_config_path: Path | str | None = None,
) -> AppConfig:
    """Create application configuration with storage backend.

    Args:
        storage_config_path: Optional path to storage configuration file.

    Returns:
        Configured AppConfig instance with storage backend initialized.
    """
    storage_backend = get_storage_backend(config_path=storage_config_path)
    return AppConfig(storage_backend=storage_backend)


# Default configuration instance
default_config = AppConfig()
