"""SARIF 2.1.0 reporter for mcpaudit.

Generates SARIF (Static Analysis Results Interchange Format) output,
compatible with GitHub Code Scanning, VS Code SARIF Viewer, and other tools.

Spec: https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
"""

from __future__ import annotations

import json
from typing import Any

from .. import __version__
from ..models import Finding, ScanResult, ScanSummary, Severity

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

TOOL_NAME = "mcpaudit"
TOOL_VERSION = __version__
TOOL_URI = "https://github.com/cmiretf/mcpaudit"


def _severity_to_sarif_level(severity: Severity) -> str:
    """Map mcpaudit severity to SARIF level."""
    return {
        Severity.CRITICAL: "error",
        Severity.HIGH: "error",
        Severity.MEDIUM: "warning",
        Severity.LOW: "note",
        Severity.INFO: "note",
    }[severity]


def _severity_to_sarif_rank(severity: Severity) -> float:
    """Map mcpaudit severity to SARIF security-severity rank (0-10)."""
    return {
        Severity.CRITICAL: 9.5,
        Severity.HIGH: 7.5,
        Severity.MEDIUM: 5.0,
        Severity.LOW: 2.5,
        Severity.INFO: 1.0,
    }[severity]


def _confidence_to_sarif_precision(confidence: str) -> str:
    """Map confidence level to SARIF precision."""
    return {
        "HIGH": "high",
        "MEDIUM": "medium",
        "LOW": "low",
    }.get(confidence, "medium")


def _build_rule(finding: Finding) -> dict[str, Any]:
    """Build a SARIF rule descriptor from a finding."""
    rule: dict[str, Any] = {
        "id": finding.rule_id,
        "name": finding.title,
        "shortDescription": {"text": finding.title},
        "fullDescription": {"text": finding.description},
        "defaultConfiguration": {
            "level": _severity_to_sarif_level(finding.severity),
        },
        "properties": {
            "security-severity": str(_severity_to_sarif_rank(finding.severity)),
            "precision": _confidence_to_sarif_precision(finding.confidence),
            "tags": ["security"],
        },
    }
    if finding.cwe:
        rule["properties"]["tags"].append(finding.cwe)
    if finding.recommendation:
        rule["help"] = {
            "text": finding.recommendation,
            "markdown": f"**Fix:** {finding.recommendation}",
        }
    return rule


def _build_result(finding: Finding) -> dict[str, Any]:
    """Build a SARIF result from a finding."""
    result: dict[str, Any] = {
        "ruleId": finding.rule_id,
        "level": _severity_to_sarif_level(finding.severity),
        "message": {"text": finding.description},
        "locations": [
            {
                "physicalLocation": {
                    "artifactLocation": {
                        "uri": finding.file,
                        "uriBaseId": "%SRCROOT%",
                    },
                    "region": {
                        "startLine": max(1, finding.line),
                        "startColumn": 1,
                    },
                },
            }
        ],
        "properties": {
            "security-severity": str(_severity_to_sarif_rank(finding.severity)),
            "confidence": finding.confidence,
        },
    }
    if finding.code_snippet:
        result["locations"][0]["physicalLocation"]["region"]["snippet"] = {
            "text": finding.code_snippet,
        }
    if finding.recommendation:
        result["fixes"] = [
            {
                "description": {"text": finding.recommendation},
            }
        ]
    return result


def format_sarif(results: list[ScanResult]) -> str:
    """Format scan results as SARIF 2.1.0 JSON.

    Args:
        results: List of scan results.

    Returns:
        SARIF JSON string.
    """
    all_findings: list[Finding] = []
    for r in results:
        all_findings.extend(r.findings)

    # Deduplicate rules by rule_id
    rules_map: dict[str, dict[str, Any]] = {}
    for f in all_findings:
        if f.rule_id not in rules_map:
            rules_map[f.rule_id] = _build_rule(f)

    sarif_results = [_build_result(f) for f in all_findings]

    summary = ScanSummary(results=results)

    sarif: dict[str, Any] = {
        "$schema": SARIF_SCHEMA,
        "version": SARIF_VERSION,
        "runs": [
            {
                "tool": {
                    "driver": {
                        "name": TOOL_NAME,
                        "version": TOOL_VERSION,
                        "informationUri": TOOL_URI,
                        "rules": list(rules_map.values()),
                        "properties": {
                            "tags": [
                                "mcp",
                                "security",
                                "static-analysis",
                            ],
                        },
                    },
                },
                "results": sarif_results,
                "invocations": [
                    {
                        "executionSuccessful": True,
                        "properties": {
                            "filesScanned": summary.total_files,
                            "linesScanned": summary.total_lines,
                            "overallGrade": summary.overall_grade,
                            "scanTimeMs": round(
                                summary.total_scan_time_ms, 2
                            ),
                        },
                    }
                ],
            }
        ],
    }

    return json.dumps(sarif, indent=2, ensure_ascii=False)
