"""Three-layer configuration: global → project → environment variables."""

from __future__ import annotations

import logging
import os
from pathlib import Path

import yaml
from pydantic import BaseModel, Field

logger = logging.getLogger(__name__)


class DatabaseConfig(BaseModel):
    url: str = "postgresql://loom:loom_local@localhost:5432/loom"
    pool_min_size: int = 2
    pool_max_size: int = 10


class RedisConfig(BaseModel):
    url: str = "redis://localhost:6379"


class McpConfig(BaseModel):
    port: int = 8765
    host: str = "0.0.0.0"
    health_port: int = 8765


class SkillsConfig(BaseModel):
    model: str = "claude-sonnet-4-6"
    api_key: str = ""
    max_tokens: int = 8192
    temperature: float = 0.2
    enrichment_concurrency: int = 5  # max parallel tasks during enrichment


class OrchestrationConfig(BaseModel):
    # Claim TTL (Stream B)
    claim_ttl_seconds: int = 1800          # 30 minutes default
    heartbeat_interval_seconds: int = 120  # 2 minutes
    sweep_interval_seconds: int = 60       # 1 minute
    # Retry (Stream C)
    max_retries: int = 3
    retry_base_delay_seconds: int = 60        # 1 minute base
    retry_max_delay_seconds: int = 3600       # 1 hour cap
    # Escalation toggle — disable to suppress AI-generated fix tasks
    enable_escalation: bool = True
    # Escalation dedup/rate-limit (Phase 7)
    escalation_dedup_ttl_seconds: int = 600     # guard TTL
    max_escalations_per_tick: int = 5           # rate limit per tick


class IntegrationsConfig(BaseModel):
    slack_webhook_url: str = ""
    obsidian_vault_path: str = ""


class AuthConfig(BaseModel):
    enabled: bool = False
    token_header: str = "x-loom-api-key"


class DashboardConfig(BaseModel):
    enabled: bool = True
    title: str = "Loom Dashboard"


class LoomConfig(BaseModel):
    project_name: str = "default"
    project_id: str = ""
    database: DatabaseConfig = Field(default_factory=DatabaseConfig)
    redis: RedisConfig = Field(default_factory=RedisConfig)
    mcp: McpConfig = Field(default_factory=McpConfig)
    skills: SkillsConfig = Field(default_factory=SkillsConfig)
    orchestration: OrchestrationConfig = Field(default_factory=OrchestrationConfig)
    integrations: IntegrationsConfig = Field(default_factory=IntegrationsConfig)
    auth: AuthConfig = Field(default_factory=AuthConfig)
    dashboard: DashboardConfig = Field(default_factory=DashboardConfig)
    log_level: str = "INFO"


def _load_yaml(path: Path) -> dict:
    if not path.exists():
        return {}
    with open(path) as f:
        return yaml.safe_load(f) or {}


def _flatten_yaml(data: dict) -> dict:
    """Convert nested YAML structure to flat LoomConfig fields."""
    flat: dict = {}
    if "loom" in data:
        loom = data["loom"]
        if "project_name" in loom:
            flat["project_name"] = loom["project_name"]
        if "project_id" in loom:
            flat["project_id"] = str(loom["project_id"])
    if "database" in data:
        flat["database"] = DatabaseConfig(**data["database"])
    if "redis" in data:
        flat["redis"] = RedisConfig(**data["redis"])
    if "mcp" in data:
        flat["mcp"] = McpConfig(**data["mcp"])
    if "skills" in data:
        flat["skills"] = SkillsConfig(**data["skills"])
    if "orchestration" in data:
        flat["orchestration"] = OrchestrationConfig(**data["orchestration"])
    if "integrations" in data:
        flat["integrations"] = IntegrationsConfig(**data["integrations"])
    if "auth" in data:
        flat["auth"] = AuthConfig(**data["auth"])
    if "logging" in data and "level" in data["logging"]:
        flat["log_level"] = data["logging"]["level"]
    return flat


def load_config(project_dir: str | Path | None = None) -> LoomConfig:
    """Load config merging global → project → env vars."""
    # Layer 1: global defaults
    global_path = Path.home() / ".loom" / "config.yaml"
    global_data = _flatten_yaml(_load_yaml(global_path))

    # Layer 2: project overrides
    project_data: dict = {}
    if project_dir:
        project_path = Path(project_dir) / ".loom" / "config.yaml"
        project_data = _flatten_yaml(_load_yaml(project_path))

    # Merge: project overrides global
    merged = {**global_data, **project_data}
    config = LoomConfig(**merged)

    # Layer 3: env var overrides
    if url := os.environ.get("LOOM_DATABASE_URL"):
        config.database.url = url
    if pool_min := os.environ.get("LOOM_DATABASE_POOL_MIN"):
        config.database.pool_min_size = int(pool_min)
    if pool_max := os.environ.get("LOOM_DATABASE_POOL_MAX"):
        config.database.pool_max_size = int(pool_max)
    if url := os.environ.get("LOOM_REDIS_URL"):
        config.redis.url = url
    if port := os.environ.get("LOOM_MCP_PORT"):
        config.mcp.port = int(port)
    if health_port := os.environ.get("LOOM_HEALTH_PORT"):
        config.mcp.health_port = int(health_port)
    if level := os.environ.get("LOOM_LOG_LEVEL"):
        config.log_level = level
    if pid := os.environ.get("LOOM_PROJECT_ID"):
        config.project_id = pid
    if _skills_key := os.environ.get("LOOM_SKILLS_API_KEY"):
        config.skills.api_key = _skills_key
    elif _anthro_key := os.environ.get("ANTHROPIC_API_KEY"):
        logger.debug("LOOM_SKILLS_API_KEY not set, falling back to ANTHROPIC_API_KEY")
        config.skills.api_key = _anthro_key
    if model := os.environ.get("LOOM_SKILLS_MODEL"):
        config.skills.model = model
    if enrich_conc := os.environ.get("LOOM_ENRICHMENT_CONCURRENCY"):
        config.skills.enrichment_concurrency = int(enrich_conc)
    if ttl := os.environ.get("LOOM_CLAIM_TTL"):
        config.orchestration.claim_ttl_seconds = int(ttl)
    if max_retries := os.environ.get("LOOM_MAX_RETRIES"):
        config.orchestration.max_retries = int(max_retries)
    if base_delay := os.environ.get("LOOM_RETRY_BASE_DELAY"):
        config.orchestration.retry_base_delay_seconds = int(base_delay)
    if max_delay := os.environ.get("LOOM_RETRY_MAX_DELAY"):
        config.orchestration.retry_max_delay_seconds = int(max_delay)
    if esc_enabled := os.environ.get("LOOM_ENABLE_ESCALATION"):
        config.orchestration.enable_escalation = esc_enabled.lower() in ("true", "1", "yes")

    if slack_url := os.environ.get("LOOM_SLACK_WEBHOOK_URL"):
        config.integrations.slack_webhook_url = slack_url
    if vault_path := os.environ.get("LOOM_OBSIDIAN_VAULT_PATH"):
        config.integrations.obsidian_vault_path = vault_path

    if auth_enabled := os.environ.get("LOOM_AUTH_ENABLED"):
        config.auth.enabled = auth_enabled.lower() in ("true", "1", "yes")

    return config
