"""Data models shared across scanner components."""

from __future__ import annotations

from dataclasses import asdict, dataclass, field
from pathlib import Path
from typing import Any

from razin.types import Classification, Confidence, Severity

type FrontmatterData = dict[str, Any] | None


@dataclass(frozen=True)
class Evidence:
    """Evidence location and snippet for a finding."""

    path: str
    line: int | None
    snippet: str


@dataclass(frozen=True)
class FindingCandidate:
    """Pre-normalized finding generated by a detector."""

    rule_id: str
    score: int
    confidence: Confidence
    title: str
    description: str
    evidence: Evidence
    recommendation: str
    classification: Classification = "security"
    internal_rule_id: str | None = None


@dataclass(frozen=True)
class SeverityOverride:
    """Audit metadata for severity changes applied after scoring."""

    original: Severity
    applied: Severity
    reason: str


@dataclass(frozen=True)
class Finding:
    """Serialized finding representation used in reports."""

    id: str
    severity: Severity
    score: int
    confidence: Confidence
    title: str
    description: str
    evidence: Evidence
    skill: str
    rule_id: str
    recommendation: str
    classification: Classification = "security"
    severity_override: SeverityOverride | None = None

    def to_dict(self) -> dict[str, Any]:
        """Convert finding to a JSON-serializable dictionary."""
        return asdict(self)


@dataclass(frozen=True)
class Summary:
    """Per-skill summary report."""

    schema_version: str
    skill: str
    overall_score: int
    overall_severity: Severity
    finding_count: int
    counts_by_severity: dict[Severity, int]
    counts_by_rule: dict[str, int]
    top_risks: tuple[dict[str, object], ...]
    shown_finding_count: int | None = None
    output_filter: dict[str, object] | None = None
    rule_overrides: dict[str, dict[str, Severity]] | None = None

    def to_dict(self) -> dict[str, Any]:
        """Convert summary to a JSON-serializable dictionary."""
        data = asdict(self)
        data["top_risks"] = list(data["top_risks"])
        return data


@dataclass(frozen=True)
class DocumentField:
    """Document field and location metadata."""

    path: tuple[str, ...]
    value: str
    line: int
    snippet: str
    in_code_block: bool = False
    field_source: str = "prose"


@dataclass(frozen=True)
class DocumentKey:
    """Document key and location metadata."""

    path: tuple[str, ...]
    key: str
    line: int
    snippet: str


@dataclass(frozen=True)
class ParsedSkillDocument:
    """Parsed SKILL.md document with extracted fields and keys."""

    file_path: Path
    raw_text: str
    frontmatter: FrontmatterData
    body: str
    fields: tuple[DocumentField, ...]
    keys: tuple[DocumentKey, ...]


@dataclass(frozen=True)
class ScanResult:
    """Aggregated scan execution result."""

    scanned_files: int
    total_findings: int
    aggregate_score: int
    aggregate_severity: Severity
    counts_by_severity: dict[Severity, int]
    findings: tuple[Finding, ...]
    duration_seconds: float
    warnings: tuple[str, ...]
    cache_hits: int
    cache_misses: int
    high_severity_min: int = 70
    medium_severity_min: int = 40
    aggregate_min_rule_score: int = 40
    counts_by_rule: dict[str, int] = field(default_factory=dict)
    active_rule_overrides: dict[str, dict[str, Severity]] = field(default_factory=dict)
