"""Main application settings extending trigger settings."""

from pathlib import Path
from typing import Annotated

from pydantic import Field, PostgresDsn
from pydantic_settings import SettingsConfigDict

from noteflow.config.constants import APP_DIR_NAME
from noteflow.config.settings._base import ENV_FILE, EXTRA_IGNORE
from noteflow.config.settings._triggers import TriggerSettings


def _default_meetings_dir() -> Path:
    """Return default meetings directory path."""
    return Path.home() / APP_DIR_NAME / "meetings"


class Settings(TriggerSettings):
    """Application settings loaded from environment variables.

    Environment variables:
        NOTEFLOW_DATABASE_URL: PostgreSQL connection URL
            Example: postgresql+asyncpg://user:pass@host:5432/dbname?
                options=-csearch_path%3Dnoteflow
        NOTEFLOW_DB_POOL_SIZE: Connection pool size (default: 5)
        NOTEFLOW_DB_ECHO: Echo SQL statements (default: False)
        NOTEFLOW_ASR_MODEL_SIZE: Whisper model size (default: base)
        NOTEFLOW_ASR_DEVICE: ASR device (default: cpu)
        NOTEFLOW_ASR_COMPUTE_TYPE: ASR compute type (default: int8)
        NOTEFLOW_MEETINGS_DIR: Directory for meeting audio storage (default: ~/.noteflow/meetings)
        NOTEFLOW_RETENTION_ENABLED: Enable automatic retention policy (default: False)
        NOTEFLOW_RETENTION_DAYS: Days to retain completed meetings (default: 90)
        NOTEFLOW_RETENTION_CHECK_INTERVAL_HOURS: Hours between retention checks (default: 24)
    """

    model_config = SettingsConfigDict(
        env_prefix="NOTEFLOW_",
        env_file=ENV_FILE,
        env_file_encoding="utf-8",
        enable_decoding=False,
        extra=EXTRA_IGNORE,
    )

    # Database settings
    database_url: Annotated[
        PostgresDsn,
        Field(
            description="PostgreSQL connection URL with asyncpg driver",
            examples=["postgresql+asyncpg://user:pass@localhost:5432/noteflow"],
        ),
    ]
    db_pool_size: Annotated[
        int,
        Field(default=5, ge=1, le=50, description="Database connection pool size"),
    ]
    db_echo: Annotated[
        bool,
        Field(default=False, description="Echo SQL statements to log"),
    ]

    # ASR settings
    asr_model_size: Annotated[
        str,
        Field(default="base", description="Whisper model size"),
    ]
    asr_device: Annotated[
        str,
        Field(default="cpu", description="ASR device (cpu or cuda)"),
    ]
    asr_compute_type: Annotated[
        str,
        Field(default="int8", description="ASR compute type"),
    ]

    # Server settings
    grpc_port: Annotated[
        int,
        Field(default=50051, ge=1, le=65535, description="gRPC server port"),
    ]

    # Storage settings
    meetings_dir: Annotated[
        Path,
        Field(
            default_factory=_default_meetings_dir,
            description="Directory for meeting audio and metadata storage",
        ),
    ]

    # Retention settings
    retention_enabled: Annotated[
        bool,
        Field(default=False, description="Enable automatic retention policy"),
    ]
    retention_days: Annotated[
        int,
        Field(default=90, ge=1, le=3650, description="Days to retain completed meetings"),
    ]
    retention_check_interval_hours: Annotated[
        int,
        Field(default=24, ge=1, le=168, description="Hours between retention checks"),
    ]

    # Diarization settings
    diarization_enabled: Annotated[
        bool,
        Field(default=False, description="Enable speaker diarization"),
    ]
    diarization_hf_token: Annotated[
        str | None,
        Field(default=None, description="HuggingFace token for pyannote models"),
    ]
    diarization_device: Annotated[
        str,
        Field(default="auto", description="Diarization device (auto, cpu, cuda, mps)"),
    ]
    diarization_streaming_latency: Annotated[
        float,
        Field(default=0.5, ge=0.1, le=5.0, description="Streaming diarization latency in seconds"),
    ]
    diarization_min_speakers: Annotated[
        int,
        Field(default=1, ge=1, le=20, description="Minimum expected speakers"),
    ]
    diarization_max_speakers: Annotated[
        int,
        Field(default=10, ge=1, le=50, description="Maximum expected speakers"),
    ]
    diarization_refinement_enabled: Annotated[
        bool,
        Field(default=True, description="Enable post-meeting diarization refinement"),
    ]
    diarization_job_ttl_hours: Annotated[
        int,
        Field(default=1, ge=1, le=168, description="Hours to retain diarization job records"),
    ]

    # gRPC streaming settings
    grpc_max_chunk_size_mb: Annotated[
        int,
        Field(default=1, ge=1, le=100, description="Maximum gRPC chunk size in MB"),
    ]
    grpc_chunk_timeout_seconds: Annotated[
        float,
        Field(default=0.1, ge=0.01, le=10.0, description="Timeout for receiving audio chunks"),
    ]
    grpc_queue_max_size: Annotated[
        int,
        Field(default=1000, ge=100, le=10000, description="Maximum audio queue size"),
    ]
    grpc_partial_cadence_seconds: Annotated[
        float,
        Field(default=2.0, ge=0.5, le=10.0, description="Interval for emitting partial transcripts"),
    ]
    grpc_min_partial_audio_seconds: Annotated[
        float,
        Field(default=0.5, ge=0.1, le=5.0, description="Minimum audio for partial inference"),
    ]

    # Webhook settings
    webhook_timeout_seconds: Annotated[
        float,
        Field(default=10.0, ge=1.0, le=60.0, description="Webhook HTTP request timeout"),
    ]
    webhook_max_retries: Annotated[
        int,
        Field(default=3, ge=0, le=10, description="Maximum webhook delivery attempts"),
    ]
    webhook_backoff_base: Annotated[
        float,
        Field(default=2.0, ge=1.1, le=5.0, description="Exponential backoff multiplier for webhook retries"),
    ]
    webhook_max_response_length: Annotated[
        int,
        Field(default=500, ge=100, le=10000, description="Maximum response body length to log"),
    ]

    # LLM/Summarization settings
    llm_temperature: Annotated[
        float,
        Field(default=0.3, ge=0.0, le=2.0, description="Temperature for LLM inference"),
    ]
    llm_default_openai_model: Annotated[
        str,
        Field(default="gpt-4o-mini", description="Default OpenAI model for summarization"),
    ]
    llm_default_anthropic_model: Annotated[
        str,
        Field(default="claude-3-haiku-20240307", description="Default Anthropic model for summarization"),
    ]
    llm_timeout_seconds: Annotated[
        float,
        Field(default=60.0, ge=10.0, le=300.0, description="Timeout for LLM requests"),
    ]

    # Ollama settings
    ollama_host: Annotated[
        str,
        Field(default="http://localhost:11434", description="Ollama server host URL"),
    ]
    ollama_timeout_seconds: Annotated[
        float,
        Field(default=120.0, ge=10.0, le=600.0, description="Timeout for Ollama requests"),
    ]

    # OpenTelemetry settings
    otel_endpoint: Annotated[
        str | None,
        Field(default=None, description="OTLP endpoint for telemetry export"),
    ]
    otel_insecure: Annotated[
        bool | None,
        Field(
            default=None,
            description="Use insecure (non-TLS) connection. If None, inferred from endpoint scheme",
        ),
    ]
    otel_service_name: Annotated[
        str,
        Field(default="noteflow", description="Service name for OpenTelemetry resource"),
    ]

    # Logging settings
    log_level: Annotated[
        str,
        Field(default="INFO", description="Log level (DEBUG, INFO, WARNING, ERROR)"),
    ]
    log_format: Annotated[
        str,
        Field(
            default="auto",
            description="Log format: auto (TTY=console, else JSON), console (Rich), json",
        ),
    ]

    @property
    def database_url_str(self) -> str:
        """Return database URL as string."""
        return str(self.database_url)
