"""
Unified Configuration for ROA2WEB Backend
Consolidates settings from Reports, Data Entry, and Telegram modules
"""

import os
import json
import logging
from pathlib import Path
from typing import List, Optional
from pydantic_settings import BaseSettings
from pydantic import BaseModel
from functools import lru_cache

logger = logging.getLogger(__name__)


class OracleServerConfig(BaseModel):
    """Configuration for a single Oracle server instance."""
    id: str  # Unique identifier (e.g., "romfast", "client_a")
    name: str  # Human-readable name (e.g., "Romfast - Producție")
    host: str = "localhost"
    port: int = 1521
    user: str
    password: str
    sid: Optional[str] = None
    service_name: Optional[str] = None

    def get_dsn(self) -> str:
        """Build DSN string for this server."""
        if self.service_name:
            return f"{self.host}:{self.port}/{self.service_name}"
        elif self.sid:
            return f"{self.host}:{self.port}:{self.sid}"
        else:
            return f"{self.host}:{self.port}/ROA"


class UnifiedSettings(BaseSettings):
    """Unified application settings for all modules."""

    # ============================================================================
    # GENERAL APPLICATION SETTINGS
    # ============================================================================
    app_name: str = "ROA2WEB Unified Backend"
    app_version: str = "1.0.0"
    debug: bool = False
    api_host: str = "0.0.0.0"
    api_port: int = 8000

    # ============================================================================
    # ORACLE DATABASE (Shared by all modules)
    # ============================================================================
    # Legacy single-server configuration (backward compatible)
    oracle_user: str = ""
    oracle_password: str = ""
    oracle_host: str = "localhost"
    oracle_port: int = 1526
    oracle_sid: str = "ROA"

    # ============================================================================
    # MULTI-ORACLE SERVER CONFIGURATION (Optional)
    # ============================================================================
    # JSON array of server configs. If not set, uses legacy single-server config.
    # Example: ORACLE_SERVERS='[{"id": "romfast", "name": "Romfast", "host": "localhost", "port": 1521, "user": "USER", "password": "PASS", "sid": "ROA"}]'
    oracle_servers: Optional[str] = None  # Raw JSON string from env

    # Parsed server configurations (populated in model_post_init)
    _oracle_servers_parsed: List[OracleServerConfig] = []

    def model_post_init(self, __context) -> None:
        """Parse ORACLE_SERVERS JSON and build server list.

        Oracle passwords are loaded from:
        1. secrets/{server_id}.oracle_pass file (preferred, more secure)
        2. password field in ORACLE_SERVERS JSON (fallback)
        """
        servers = []
        secrets_dir = Path(__file__).parent / "secrets"

        if self.oracle_servers:
            # Parse multi-server JSON configuration
            try:
                servers_data = json.loads(self.oracle_servers)
                if not isinstance(servers_data, list):
                    raise ValueError("ORACLE_SERVERS must be a JSON array")

                for server_data in servers_data:
                    server_id = server_data.get("id", "default")

                    # Try to load password from secrets file
                    pass_file = secrets_dir / f"{server_id}.oracle_pass"
                    if pass_file.exists():
                        server_data["password"] = pass_file.read_text().strip()
                        logger.debug(f"Loaded Oracle password for '{server_id}' from {pass_file}")
                    elif "password" not in server_data:
                        logger.warning(f"No password found for server '{server_id}' - check secrets/{server_id}.oracle_pass")

                    servers.append(OracleServerConfig(**server_data))

                logger.info(f"Loaded {len(servers)} Oracle servers from ORACLE_SERVERS config")
                for srv in servers:
                    logger.info(f"  - {srv.id}: {srv.name} ({srv.host}:{srv.port})")
            except json.JSONDecodeError as e:
                logger.error(f"Failed to parse ORACLE_SERVERS JSON: {e}")
                raise ValueError(f"Invalid ORACLE_SERVERS JSON format: {e}")
        else:
            # Backward compatibility: build default server from legacy config
            if self.oracle_user:
                # Try to load password from secrets file
                password = self.oracle_password
                pass_file = secrets_dir / "default.oracle_pass"
                if pass_file.exists():
                    password = pass_file.read_text().strip()
                    logger.debug(f"Loaded Oracle password from {pass_file}")

                default_server = OracleServerConfig(
                    id="default",
                    name="Default Server",
                    host=self.oracle_host,
                    port=self.oracle_port,
                    user=self.oracle_user,
                    password=password,
                    sid=self.oracle_sid,
                )
                servers.append(default_server)
                logger.info("Using legacy single-server Oracle configuration (ORACLE_USER/HOST/etc)")
                logger.info(f"  - default: {default_server.host}:{default_server.port}/{default_server.sid}")

        object.__setattr__(self, '_oracle_servers_parsed', servers)

    def get_oracle_servers(self) -> List[OracleServerConfig]:
        """Get list of configured Oracle servers."""
        return self._oracle_servers_parsed

    def get_oracle_server(self, server_id: str) -> Optional[OracleServerConfig]:
        """Get a specific Oracle server by ID."""
        for server in self._oracle_servers_parsed:
            if server.id == server_id:
                return server
        return None

    def get_default_oracle_server(self) -> Optional[OracleServerConfig]:
        """Get the default Oracle server (first in list or 'default')."""
        if not self._oracle_servers_parsed:
            return None
        # Try to find server with id='default', otherwise return first
        for server in self._oracle_servers_parsed:
            if server.id == "default":
                return server
        return self._oracle_servers_parsed[0]

    # ============================================================================
    # JWT AUTHENTICATION (Shared by all modules)
    # ============================================================================
    jwt_secret_key: str = "change-me-in-production"
    jwt_algorithm: str = "HS256"
    access_token_expire_minutes: int = 30
    refresh_token_expire_days: int = 7

    # ============================================================================
    # SESSION SECURITY - EMAIL 2FA (Telegram module)
    # ============================================================================
    auth_session_secret: str = "change-me-in-production"

    # ============================================================================
    # CORS
    # ============================================================================
    cors_origins: str = "http://localhost:3000,http://localhost:5173"

    # ============================================================================
    # REPORTS MODULE - CACHE CONFIGURATION
    # ============================================================================
    reports_cache_enabled: bool = True
    reports_cache_type: str = "hybrid"
    reports_cache_sqlite_path: str = "./data/cache/roa2web_cache.db"
    reports_cache_memory_max_size: int = 1000
    reports_cache_default_ttl: int = 900

    # Cache TTL per type (seconds)
    reports_cache_ttl_schema: int = 86400
    reports_cache_ttl_companies: int = 1800
    reports_cache_ttl_dashboard_summary: int = 1800
    reports_cache_ttl_dashboard_trends: int = 1800
    reports_cache_ttl_invoices: int = 600
    reports_cache_ttl_invoices_summary: int = 900
    reports_cache_ttl_treasury: int = 600

    # Cache maintenance
    reports_cache_cleanup_interval: int = 3600
    reports_cache_auto_invalidate: bool = False
    reports_cache_check_interval: int = 300
    reports_cache_track_performance: bool = True
    reports_cache_benchmark_on_startup: bool = False

    # ============================================================================
    # DATA ENTRY MODULE - CONFIGURATION
    # ============================================================================
    data_entry_sqlite_database_path: str = "data/receipts/receipts.db"
    data_entry_upload_path: str = "data/receipts/uploads"
    data_entry_max_upload_size_mb: int = 10
    data_entry_allowed_mime_types: List[str] = [
        "image/jpeg",
        "image/png",
        "image/gif",
        "image/webp",
        "application/pdf",
    ]

    # ============================================================================
    # TELEGRAM MODULE - BOT CONFIGURATION
    # ============================================================================
    telegram_bot_token: str = ""
    telegram_smtp_host: str = ""
    telegram_smtp_port: int = 587
    telegram_smtp_user: str = ""
    telegram_smtp_password: str = ""
    telegram_smtp_from_email: str = ""
    telegram_smtp_from_name: str = "ROA2WEB"
    telegram_smtp_use_tls: bool = True
    telegram_email_max_retries: int = 3
    telegram_email_retry_delay: float = 2.0
    telegram_sqlite_database_path: str = "data/telegram/telegram.db"

    class Config:
        env_file = ".env"
        env_file_encoding = "utf-8"
        extra = "ignore"
        case_sensitive = False

    # ============================================================================
    # COMPUTED PROPERTIES
    # ============================================================================

    @property
    def oracle_dsn(self) -> str:
        """Get Oracle DSN string."""
        return f"{self.oracle_host}:{self.oracle_port}/{self.oracle_sid}"

    @property
    def cors_origins_list(self) -> List[str]:
        """Get CORS origins as list."""
        return [origin.strip() for origin in self.cors_origins.split(",")]

    # Data Entry properties
    @property
    def data_entry_database_url(self) -> str:
        """Get SQLite database URL for async (Data Entry)."""
        # Resolve to absolute path for Windows/IIS compatibility
        abs_path = Path(self.data_entry_sqlite_database_path).resolve()
        return f"sqlite+aiosqlite:///{abs_path}"

    @property
    def data_entry_sync_database_url(self) -> str:
        """Get SQLite database URL for sync operations (Alembic)."""
        # Resolve to absolute path for Windows/IIS compatibility
        abs_path = Path(self.data_entry_sqlite_database_path).resolve()
        return f"sqlite:///{abs_path}"

    @property
    def data_entry_upload_path_resolved(self) -> Path:
        """Get resolved upload path."""
        path = Path(self.data_entry_upload_path)
        path.mkdir(parents=True, exist_ok=True)
        return path

    @property
    def data_entry_max_upload_size_bytes(self) -> int:
        """Get max upload size in bytes."""
        return self.data_entry_max_upload_size_mb * 1024 * 1024

    # Reports cache properties
    @property
    def reports_cache_sqlite_path_resolved(self) -> Path:
        """Get resolved cache SQLite path."""
        path = Path(self.reports_cache_sqlite_path)
        path.parent.mkdir(parents=True, exist_ok=True)
        return path

    # Telegram properties
    @property
    def telegram_sqlite_path_resolved(self) -> Path:
        """Get resolved Telegram SQLite path."""
        path = Path(self.telegram_sqlite_database_path)
        path.parent.mkdir(parents=True, exist_ok=True)
        return path


@lru_cache()
def get_settings() -> UnifiedSettings:
    """Get cached settings instance."""
    return UnifiedSettings()


# Convenience instance
settings = get_settings()
