"""SARIF and JSON formatters for policy violations."""

from __future__ import annotations

from nestdx.session.models import PolicyViolation

SARIF_SCHEMA = (
    "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/"
    "sarif-2.1/schema/sarif-schema-2.1.0.json"
)
SARIF_VERSION = "2.1.0"


def _severity_to_sarif_level(severity: str) -> str:
    """Map PolicyViolation severity to SARIF level."""
    mapping = {
        "error": "error",
        "warning": "warning",
    }
    return mapping.get(severity, "note")


def _violation_to_rule_id(violation: PolicyViolation) -> str:
    """Derive a SARIF ruleId from a PolicyViolation."""
    if violation.pattern:
        return f"secrets/{violation.pattern}"
    return violation.rule


def _build_location(violation: PolicyViolation) -> dict | None:
    """Build a SARIF location object from a violation, if file info is available."""
    if not violation.file:
        return None

    physical_location: dict = {
        "artifactLocation": {
            "uri": violation.file,
        },
    }

    if violation.line is not None:
        physical_location["region"] = {
            "startLine": violation.line,
        }

    return {"physicalLocation": physical_location}


def format_sarif(
    violations: list[PolicyViolation],
    tool_name: str = "nestdx",
    tool_version: str = "0.1.0",
) -> dict:
    """Format violations as a SARIF 2.1.0 document.

    Returns a dict that can be serialized to JSON.
    """
    # Collect unique rules
    rules_seen: dict[str, dict] = {}
    results: list[dict] = []

    for v in violations:
        rule_id = _violation_to_rule_id(v)

        if rule_id not in rules_seen:
            rules_seen[rule_id] = {
                "id": rule_id,
                "shortDescription": {
                    "text": v.rule,
                },
            }

        result: dict = {
            "ruleId": rule_id,
            "level": _severity_to_sarif_level(v.severity),
            "message": {
                "text": v.message,
            },
        }

        location = _build_location(v)
        if location:
            result["locations"] = [location]

        results.append(result)

    return {
        "$schema": SARIF_SCHEMA,
        "version": SARIF_VERSION,
        "runs": [
            {
                "tool": {
                    "driver": {
                        "name": tool_name,
                        "version": tool_version,
                        "rules": list(rules_seen.values()),
                    },
                },
                "results": results,
            },
        ],
    }


def format_json(violations: list[PolicyViolation]) -> list[dict]:
    """Format violations as a simple JSON-serializable list of dicts."""
    output: list[dict] = []
    for v in violations:
        entry: dict = {
            "rule": v.rule,
            "severity": v.severity,
            "message": v.message,
        }
        if v.file is not None:
            entry["file"] = v.file
        if v.line is not None:
            entry["line"] = v.line
        if v.pattern is not None:
            entry["pattern"] = v.pattern
        output.append(entry)
    return output
