"""Risk config linting — detect common misconfigurations."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

from pyfortis._types import LimitType, MetricType, Severity
from pyfortis.config._raw_parser import raw_config_to_core
from pyfortis.errors import ConfigurationError


@dataclass(frozen=True, slots=True)
class LintIssue:
    level: str  # "error", "warning", "info"
    message: str
    path: str = ""
    details: dict[str, Any] = field(default_factory=dict)


def lint_config(config: dict[str, Any]) -> list[LintIssue]:
    """Lint a raw config dict, returning a list of issues."""
    issues: list[LintIssue] = []

    # Try parsing first
    try:
        limits, metrics, circuit_breakers, escalation, meta = raw_config_to_core(config)
    except ConfigurationError as exc:
        issues.append(LintIssue(level="error", message=str(exc), path="root"))
        return issues

    # Check for duplicate limit names
    seen_names: set[str] = set()
    for limit in limits:
        if limit.name in seen_names:
            issues.append(
                LintIssue(
                    level="error",
                    message=f"Duplicate limit name: '{limit.name}'",
                    path="limits",
                )
            )
        seen_names.add(limit.name)

    # Check for duplicate metric names
    seen_metrics: set[str] = set()
    for metric in metrics:
        if metric.name in seen_metrics:
            issues.append(
                LintIssue(
                    level="error",
                    message=f"Duplicate metric name: '{metric.name}'",
                    path="metrics",
                )
            )
        seen_metrics.add(metric.name)

    # Check for custom validators without built-in implementations
    builtin_types = {t.value for t in LimitType if t is not LimitType.CUSTOM}
    for limit in limits:
        if limit.type is LimitType.CUSTOM:
            issues.append(
                LintIssue(
                    level="info",
                    message=f"Limit '{limit.name}' uses custom type — ensure a validator is registered",
                    path=f"limits.{limit.name}",
                )
            )

    # Check escalation policy references valid severities
    defined_severities = {limit.severity for limit in limits}
    for sev in escalation.escalation:
        if sev not in defined_severities:
            issues.append(
                LintIssue(
                    level="warning",
                    message=f"Escalation policy references severity '{sev.value}' not used by any limit",
                    path="breach_policy.escalation",
                )
            )

    # Check for disabled limits (info)
    disabled = [l for l in limits if not l.enabled]
    if disabled:
        names = ", ".join(l.name for l in disabled)
        issues.append(
            LintIssue(
                level="info",
                message=f"Disabled limits: {names}",
                path="limits",
            )
        )

    # Check for missing required params on known types
    _check_position_params(limits, issues)
    _check_concentration_params(limits, issues)

    # Check version is present
    if not meta.get("version"):
        issues.append(
            LintIssue(level="warning", message="Missing 'version' in meta", path="meta")
        )

    return issues


def _check_position_params(limits: list, issues: list[LintIssue]) -> None:
    for limit in limits:
        if limit.type is LimitType.POSITION:
            if "max_long" not in limit.params and "max_short" not in limit.params:
                issues.append(
                    LintIssue(
                        level="warning",
                        message=f"Position limit '{limit.name}' has no max_long or max_short",
                        path=f"limits.{limit.name}.params",
                    )
                )


def _check_concentration_params(limits: list, issues: list[LintIssue]) -> None:
    for limit in limits:
        if limit.type is LimitType.CONCENTRATION:
            if "max_single_asset_pct" not in limit.params:
                issues.append(
                    LintIssue(
                        level="warning",
                        message=f"Concentration limit '{limit.name}' missing max_single_asset_pct",
                        path=f"limits.{limit.name}.params",
                    )
                )
