from __future__ import annotations

import html
from pathlib import Path

from nifra.graph.builder import AttackSurfaceGraph
from nifra.reasoning.engine import ExploitChain, ReasoningResult

_SEVERITY_BADGE = {
    "critical": "![CRITICAL](https://img.shields.io/badge/severity-CRITICAL-red)",
    "high": "![HIGH](https://img.shields.io/badge/severity-HIGH-orange)",
    "medium": "![MEDIUM](https://img.shields.io/badge/severity-MEDIUM-yellow)",
    "low": "![LOW](https://img.shields.io/badge/severity-LOW-green)",
    "info": "![INFO](https://img.shields.io/badge/severity-INFO-blue)",
}


def _md_text(s: str) -> str:
    """HTML-escape a string safe for embedding inside HTML tags in GitHub Markdown."""
    return html.escape(str(s), quote=True)


def _md_inline(s: str) -> str:
    """Escape pipe and backtick for safe use in Markdown table cells."""
    return str(s).replace("|", "\\|").replace("`", "\\`")


class MarkdownReporter:
    """Generate GitHub PR comment-ready Markdown report."""

    def render(
        self,
        attack_surface: AttackSurfaceGraph,
        reasoning_result: ReasoningResult,
        project_name: str,
    ) -> str:
        lines: list[str] = []

        risk = reasoning_result.risk_level
        lines.append(f"## NIfra Security Scan — {project_name}")
        lines.append("")
        lines.append(
            f"**Risk Level:** `{risk}` | "
            f"**Findings:** {len(attack_surface.findings)} | "
            f"**Exploit Chains:** {len(reasoning_result.exploit_chains)}"
        )
        lines.append("")

        if not reasoning_result.exploit_chains:
            lines.append("✅ No security findings detected.")
            return "\n".join(lines)

        # Summary table
        lines.append("### Summary")
        lines.append("")
        lines.append("| # | Rule | Severity | Confidence | Reproducible |")
        lines.append("|---|------|----------|------------|--------------|")
        for i, chain in enumerate(reasoning_result.exploit_chains):
            badge = _SEVERITY_BADGE.get(chain.severity.lower(), chain.severity.upper())
            repro = "✅ Yes" if chain.exploit_reproducible else "⚠️ No"
            lines.append(
                f"| {i+1:03d} | `{_md_inline(chain.finding_rule_id)}` | {badge} | "
                f"{chain.confidence:.0%} | {repro} |"
            )

        lines.append("")

        # Detailed findings
        lines.append("### Findings Detail")
        for i, chain in enumerate(reasoning_result.exploit_chains):
            lines.append("")
            lines.append(f"<details>")
            lines.append(
                f"<summary><strong>Finding #{i+1:03d} — {_md_text(chain.finding_rule_id)} "
                f"({_md_text(chain.severity.upper())})</strong></summary>"
            )
            lines.append("")
            lines.append(f"**Reasoning:** {_md_text(chain.reasoning)}")
            lines.append("")
            lines.append("**Attack Chain:**")
            for step in chain.attack_chain_steps:
                lines.append(f"- {_md_text(step)}")
            lines.append("")
            lines.append(f"**Impact:** {_md_text(chain.impact)}")
            if chain.adversarial_payload:
                lines.append("")
                lines.append("**Adversarial Payload:**")
                lines.append(f"```\n{chain.adversarial_payload}\n```")
            lines.append("")
            lines.append("**Remediation:**")
            for fix in chain.remediation[:3]:
                action = fix.get("action", fix) if isinstance(fix, dict) else fix
                lines.append(f"- {_md_text(action)}")
            lines.append("")
            lines.append(f"**Confidence:** {chain.confidence:.0%} | **CVSS-AI:** {chain.cvss_ai:.1f}")
            lines.append("</details>")

        lines.append("")
        lines.append("---")
        lines.append(
            "_Generated by [NIfra](https://github.com/reyracom/Nifra-Agent) — "
            "AI Application Security Autopilot_"
        )
        return "\n".join(lines)

    def write(
        self,
        attack_surface: AttackSurfaceGraph,
        reasoning_result: ReasoningResult,
        project_name: str,
        output_path: Path,
    ) -> None:
        content = self.render(attack_surface, reasoning_result, project_name)
        output_path.write_text(content, encoding="utf-8")
