"""Monitoring configuration for Fluxibly.

Defines MonitoringConfig — controls what data is collected, where it's stored,
and how sensitive data is handled.
"""

from __future__ import annotations

import os
from typing import Any

from pydantic import BaseModel, Field


class MonitoringConfig(BaseModel):
    """Configuration for monitoring data collection.

    Monitoring is configured exclusively via environment variables
    (FLUXIBLY_MONITORING_*). Use MonitoringConfig.from_env() to load.
    Never pass monitoring config through AgentConfig or LLMConfig.
    """

    enabled: bool = Field(
        default=False, description="Enable monitoring data collection"
    )

    # --- Database connection ---
    db_host: str = Field(default="localhost")
    db_port: int = Field(default=5432)
    db_name: str = Field(default="fluxibly_monitoring")
    db_user: str = Field(default="postgres")
    db_password: str = Field(default="")
    db_pool_size: int = Field(default=5)
    db_max_overflow: int = Field(default=10)

    # --- What to capture ---
    capture_input: bool = Field(
        default=True, description="Capture full input messages"
    )
    capture_output: bool = Field(
        default=True, description="Capture full output content"
    )
    capture_context: bool = Field(
        default=True, description="Capture context dict"
    )
    capture_tool_io: bool = Field(
        default=True, description="Capture tool call inputs/outputs"
    )
    capture_raw_response: bool = Field(
        default=False, description="Capture raw provider response"
    )

    # --- Sensitive data handling ---
    mask_api_keys: bool = Field(
        default=True, description="Mask API keys in stored data"
    )
    excluded_fields: list[str] = Field(
        default_factory=lambda: [
            "api_key",
            "password",
            "secret",
            "token",
            "authorization",
        ],
        description="Fields to mask in stored data",
    )

    # --- Data retention ---
    retention_days: int = Field(
        default=90, description="Days to keep data (0=forever)"
    )

    # --- Tags for grouping/filtering ---
    service_name: str = Field(
        default="default",
        description="Service identifier for multi-service setups",
    )
    environment: str = Field(
        default="development",
        description="'development' | 'staging' | 'production'",
    )
    tags: dict[str, str] = Field(
        default_factory=dict, description="Custom tags for filtering"
    )

    # --- Writer tuning ---
    writer_batch_size: int = Field(
        default=100, description="Records to buffer before flushing"
    )
    writer_flush_interval_ms: int = Field(
        default=1000, description="Max time between flushes (ms)"
    )

    @classmethod
    def from_env(cls) -> MonitoringConfig:
        """Load config from FLUXIBLY_MONITORING_* environment variables."""
        return cls(
            enabled=os.getenv("FLUXIBLY_MONITORING_ENABLED", "false").lower()
            == "true",
            db_host=os.getenv(
                "FLUXIBLY_MONITORING_DASHBOARD_DB_HOST", "localhost"
            ),
            db_port=int(
                os.getenv("FLUXIBLY_MONITORING_DASHBOARD_DB_PORT", "5432")
            ),
            db_name=os.getenv(
                "FLUXIBLY_MONITORING_DASHBOARD_DB_NAME", "fluxibly_monitoring"
            ),
            db_user=os.getenv(
                "FLUXIBLY_MONITORING_DASHBOARD_DB_USER", "postgres"
            ),
            db_password=os.getenv(
                "FLUXIBLY_MONITORING_DASHBOARD_DB_PASSWORD", ""
            ),
            db_pool_size=int(
                os.getenv("FLUXIBLY_MONITORING_DB_POOL_SIZE", "5")
            ),
            db_max_overflow=int(
                os.getenv("FLUXIBLY_MONITORING_DB_MAX_OVERFLOW", "10")
            ),
            retention_days=int(
                os.getenv("FLUXIBLY_MONITORING_RETENTION_DAYS", "90")
            ),
        )

    @property
    def dsn(self) -> str:
        """PostgreSQL connection string (password masked for safe logging)."""
        masked_pw = "***" if self.db_password else ""
        return f"postgresql://{self.db_user}:{masked_pw}@{self.db_host}:{self.db_port}/{self.db_name}"

    @property
    def _dsn_with_password(self) -> str:
        """PostgreSQL connection string with real password (internal use only)."""
        return f"postgresql://{self.db_user}:{self.db_password}@{self.db_host}:{self.db_port}/{self.db_name}"

    def __repr__(self) -> str:
        return (
            f"MonitoringConfig(enabled={self.enabled}, "
            f"db_host='{self.db_host}', db_port={self.db_port}, "
            f"db_name='{self.db_name}', db_user='{self.db_user}', "
            f"db_password='***')"
        )

    def to_connect_kwargs(self) -> dict[str, Any]:
        """Return kwargs suitable for asyncpg.create_pool()."""
        return {
            "host": self.db_host,
            "port": self.db_port,
            "database": self.db_name,
            "user": self.db_user,
            "password": self.db_password,
            "min_size": 1,
            "max_size": self.db_pool_size,
        }
