"""Configuration loading and validation."""

from __future__ import annotations

import os
import warnings
from dataclasses import dataclass, field
from pathlib import Path

import yaml


@dataclass
class RepoConfig:
    name: str
    path: str
    provider_rotation: list[str] = field(default_factory=lambda: ["gemini"])
    exclude_patterns: list[str] = field(default_factory=list)


@dataclass
class BudgetConfig:
    max_per_run_usd: float = 2.0
    alert_threshold_usd: float = 1.5


@dataclass
class NotificationConfig:
    channel: str = "telegram"
    target: str = ""
    webhook: str = ""


@dataclass
class DecisionConfig:
    expiry_days: int = 90
    path: str = ".noxaudit/decisions.jsonl"


@dataclass
class IssuesConfig:
    enabled: bool = False
    severity_threshold: str = "medium"  # "low", "medium", or "high"
    labels: list[str] = field(default_factory=lambda: ["noxaudit"])
    assignees: list[str] = field(default_factory=list)
    repository_url: str = "https://github.com/atriumn/noxaudit"


@dataclass
class ValidateConfig:
    """Post-audit finding validation configuration."""

    enabled: bool = False
    provider: str = "gemini"
    model: str = ""  # empty = use provider default
    drop_false_positives: bool = True
    min_confidence: str = ""  # "", "low", "medium", "high"


@dataclass
class DedupConfig:
    """Post-audit deduplication configuration."""

    enabled: bool = True
    provider: str = "gemini"
    model: str = ""  # empty = use provider default


@dataclass
class PrepassConfig:
    """Pre-pass configuration for file filtering before main audit."""

    enabled: bool = False
    threshold_tokens: int = 600_000
    auto_disable: bool = False


@dataclass
class ProviderConfig:
    """Per-provider configuration (e.g., model overrides)."""

    model: str | None = None


ALL_FOCUS_NAMES = [
    "security",
    "docs",
    "patterns",
    "testing",
    "hygiene",
    "dependencies",
    "performance",
]


def normalize_focus(raw: str | list[str] | bool) -> list[str]:
    """Normalize a focus value to a list of focus area names.

    "off"/False → [], "all" → all names, "security" → ["security"],
    "security,performance" → ["security", "performance"], list passthrough.
    """
    # YAML parses bare `off` as False, `on` as True
    if isinstance(raw, bool) or raw is None:
        return [] if not raw else list(ALL_FOCUS_NAMES)
    if isinstance(raw, list):
        return [str(item) for item in raw]
    raw = str(raw)
    if raw == "off":
        return []
    if raw == "all":
        return list(ALL_FOCUS_NAMES)
    # Support comma-separated string from CLI
    if "," in raw:
        return [s.strip() for s in raw.split(",") if s.strip()]
    return [raw]


@dataclass
class NoxauditConfig:
    repos: list[RepoConfig] = field(default_factory=list)
    budget: BudgetConfig = field(default_factory=BudgetConfig)
    notifications: list[NotificationConfig] = field(default_factory=list)
    decisions: DecisionConfig = field(default_factory=DecisionConfig)
    issues: IssuesConfig = field(default_factory=IssuesConfig)
    prepass: PrepassConfig = field(default_factory=PrepassConfig)
    validate: ValidateConfig = field(default_factory=ValidateConfig)
    dedup: DedupConfig = field(default_factory=DedupConfig)
    providers: dict[str, ProviderConfig] = field(default_factory=dict)
    reports_dir: str = ".noxaudit/reports"
    model: str = "claude-sonnet-4-5-20250929"
    chunk_size: int = 0  # 0 = no chunking, >0 = files per chunk

    def get_provider_for_repo(self, repo_name: str, run_index: int = 0) -> str:
        for repo in self.repos:
            if repo.name == repo_name:
                providers = repo.provider_rotation
                return providers[run_index % len(providers)]
        return "gemini"

    def get_model_for_provider(self, provider_name: str) -> str:
        """Get the model for a provider, considering provider-specific overrides."""
        provider_config = self.providers.get(provider_name)
        if provider_config and provider_config.model:
            return provider_config.model
        return self.model


def load_config(config_path: str | Path | None = None) -> NoxauditConfig:
    """Load config from noxaudit.yml, falling back to defaults."""
    if config_path is None:
        config_path = Path("noxaudit.yml")
    else:
        config_path = Path(config_path)

    if not config_path.exists():
        return NoxauditConfig()

    with open(config_path) as f:
        raw = yaml.safe_load(f) or {}

    # Emit deprecation warnings for removed config keys
    if "schedule" in raw:
        warnings.warn(
            "The 'schedule' config key is deprecated and ignored. "
            "Use --focus or set up cron-based scheduling instead.",
            DeprecationWarning,
            stacklevel=2,
        )
    if "frames" in raw:
        warnings.warn(
            "The 'frames' config key is deprecated and ignored. "
            "Use --focus or set up cron-based scheduling instead.",
            DeprecationWarning,
            stacklevel=2,
        )

    repos = []
    for r in raw.get("repos", []):
        repos.append(
            RepoConfig(
                name=r["name"],
                path=os.path.expanduser(r["path"]),
                provider_rotation=r.get("provider_rotation", ["gemini"]),
                exclude_patterns=r.get("exclude", []),
            )
        )

    budget_raw = raw.get("budget", {})
    budget = BudgetConfig(
        max_per_run_usd=budget_raw.get("max_per_run_usd", 2.0),
        alert_threshold_usd=budget_raw.get("alert_threshold_usd", 1.5),
    )

    notifications = []
    for n in raw.get("notifications", []):
        notifications.append(
            NotificationConfig(
                channel=n.get("channel", "telegram"),
                target=n.get("target", ""),
                webhook=n.get("webhook", ""),
            )
        )

    decisions_raw = raw.get("decisions", {})
    decisions = DecisionConfig(
        expiry_days=decisions_raw.get("expiry_days", 90),
        path=decisions_raw.get("path", ".noxaudit/decisions.jsonl"),
    )

    issues_raw = raw.get("issues", {})
    issues = IssuesConfig(
        enabled=issues_raw.get("enabled", False),
        severity_threshold=issues_raw.get("severity_threshold", "medium"),
        labels=issues_raw.get("labels", ["noxaudit"]),
        assignees=issues_raw.get("assignees", []),
        repository_url=issues_raw.get("repository_url", "https://github.com/atriumn/noxaudit"),
    )

    prepass_raw = raw.get("prepass", {})
    prepass = PrepassConfig(
        enabled=prepass_raw.get("enabled", False),
        threshold_tokens=prepass_raw.get("threshold_tokens", 600_000),
        auto_disable=not prepass_raw.get("auto", True),
    )

    validate_raw = raw.get("validate", {})
    validate = ValidateConfig(
        enabled=validate_raw.get("enabled", False),
        provider=validate_raw.get("provider", "gemini"),
        model=validate_raw.get("model", ""),
        drop_false_positives=validate_raw.get("drop_false_positives", True),
        min_confidence=validate_raw.get("min_confidence", ""),
    )

    dedup_raw = raw.get("dedup", {})
    dedup = DedupConfig(
        enabled=dedup_raw.get("enabled", True),
        provider=dedup_raw.get("provider", "gemini"),
        model=dedup_raw.get("model", ""),
    )

    providers: dict[str, ProviderConfig] = {}
    for provider_name, provider_cfg in raw.get("providers", {}).items():
        if isinstance(provider_cfg, dict):
            providers[provider_name] = ProviderConfig(model=provider_cfg.get("model"))

    return NoxauditConfig(
        repos=repos,
        budget=budget,
        notifications=notifications,
        decisions=decisions,
        issues=issues,
        prepass=prepass,
        validate=validate,
        dedup=dedup,
        providers=providers,
        reports_dir=raw.get("reports_dir", ".noxaudit/reports"),
        model=raw.get("model", "claude-sonnet-4-5-20250929"),
        chunk_size=raw.get("chunk_size", 0),
    )
