"""Markdown report generator."""

from __future__ import annotations

from sanicode.report.persist import ScanResult

_SEVERITY_ORDER = {"critical": 0, "high": 1, "medium": 2, "low": 3, "info": 4}
_ALL_SEVERITIES = ["critical", "high", "medium", "low", "info"]


def _effective_severity(finding: dict) -> str:
    return finding.get("derived_severity") or finding.get("severity", "info")


def _format_compliance(compliance: dict) -> list[str]:
    """Return formatted compliance lines for a finding's compliance block."""
    lines: list[str] = []

    owasp = compliance.get("owasp_asvs")
    if owasp:
        ids = ", ".join(item["id"] for item in owasp if item.get("id"))
        level = owasp[0].get("level") if owasp else None
        entry = f"- OWASP ASVS: {ids}"
        if level:
            entry += f" ({level})"
        lines.append(entry)

    nist = compliance.get("nist_800_53")
    if nist:
        lines.append(f"- NIST 800-53: {', '.join(nist)}")

    stig = compliance.get("asd_stig")
    if stig:
        ids = ", ".join(item["id"] for item in stig if item.get("id"))
        cat = stig[0].get("cat") if stig else None
        entry = f"- ASD STIG: {ids}"
        if cat:
            entry += f" ({cat})"
        lines.append(entry)

    pci = compliance.get("pci_dss")
    if pci:
        lines.append(f"- PCI DSS: {', '.join(pci)}")

    return lines


def generate_markdown(result: ScanResult) -> str:
    """Generate a Markdown-formatted security report from a ScanResult.

    Findings are sorted by severity (critical first), then by file path,
    then by line number. Uses ``derived_severity`` when present, falling
    back to ``severity``.

    Args:
        result: Completed ScanResult produced by the scanner.

    Returns:
        A Markdown string suitable for writing to a .md file or stdout.
    """
    lines: list[str] = []

    # Header
    lines += [
        "# Sanicode Security Report",
        "",
        f"**Scanned:** {result.scanned_path}  ",
        f"**Date:** {result.scan_timestamp}  ",
        f"**Scan ID:** {result.scan_id}  ",
        f"**Sanicode Version:** {result.sanicode_version}",
        "",
    ]

    # Summary table
    summary = result.summary
    by_severity: dict[str, int] = summary.get("by_severity", {})
    total = summary.get("total_findings", len(result.findings))

    lines += [
        "## Summary",
        "",
        "| Severity | Count |",
        "|----------|------:|",
    ]
    for sev in _ALL_SEVERITIES:
        lines.append(f"| {sev.capitalize()} | {by_severity.get(sev, 0)} |")

    lines += [
        "",
        f"**Total findings:** {total}",
        "",
    ]

    # Knowledge graph stats (optional block)
    graph_nodes = summary.get("graph_nodes")
    if graph_nodes is not None:
        entry_points = summary.get("graph_entry_points", 0)
        sinks = summary.get("graph_sinks", 0)
        sanitizers = summary.get("graph_sanitizers", 0)
        graph_edges = summary.get("graph_edges", 0)
        lines += [
            "### Knowledge Graph",
            "",
            f"- **Nodes:** {graph_nodes} "
            f"(entry points: {entry_points}, sinks: {sinks}, sanitizers: {sanitizers})",
            f"- **Edges:** {graph_edges}",
            "",
        ]

    # Findings section
    lines.append("## Findings")

    if not result.findings:
        lines += ["", "No security findings detected."]
        return "\n".join(lines)

    sorted_findings = sorted(
        result.findings,
        key=lambda f: (
            _SEVERITY_ORDER.get(_effective_severity(f), 4),
            f.get("file", ""),
            f.get("line", 0),
        ),
    )

    for i, finding in enumerate(sorted_findings):
        sev = _effective_severity(finding)
        rule_id = finding.get("rule_id", "")
        message = finding.get("message", "")
        cwe_id = finding.get("cwe_id")
        cwe_name = finding.get("cwe_name", "")
        file_path = finding.get("file", "")
        line = finding.get("line", "")
        compliance = finding.get("compliance")
        remediation = finding.get("remediation") or (
            compliance.get("remediation") if compliance else None
        )

        cwe_suffix = f" (CWE-{cwe_id})" if cwe_id else ""
        lines += [
            "",
            f"### [{sev.upper()}] {rule_id} — {message}{cwe_suffix}",
            "",
            f"**File:** {file_path}:{line}  ",
            f"**Severity:** {sev}  ",
        ]

        if cwe_id:
            cwe_label = f"CWE-{cwe_id}"
            if cwe_name:
                cwe_label += f" ({cwe_name})"
            lines.append(f"**CWE:** {cwe_label}")

        if compliance:
            compliance_lines = _format_compliance(compliance)
            if compliance_lines:
                lines += ["", "**Compliance:**"] + compliance_lines

        if remediation:
            lines += ["", f"**Remediation:** {remediation}"]

        if i < len(sorted_findings) - 1:
            lines += ["", "---"]

    return "\n".join(lines)
