"""
BREACH.AI - Markdown Output Formatter
=====================================
Export scan results to Markdown format.
"""

from datetime import datetime
from typing import Dict, Any, List, Optional
from pathlib import Path


class MarkdownFormatter:
    """
    Format scan results as Markdown.

    Outputs human-readable Markdown suitable for:
    - GitHub/GitLab issues
    - Documentation
    - Reports
    - README files
    """

    SEVERITY_EMOJI = {
        "critical": "🔴",
        "high": "🟠",
        "medium": "🟡",
        "low": "🟢",
        "info": "🔵",
    }

    def __init__(self, include_poc: bool = True, include_evidence: bool = True):
        """
        Initialize the Markdown formatter.

        Args:
            include_poc: Include PoC code blocks
            include_evidence: Include evidence details
        """
        self.include_poc = include_poc
        self.include_evidence = include_evidence

    def format(
        self,
        target: str,
        mode: str,
        findings: List[Dict[str, Any]],
        stats: Dict[str, Any],
        duration_seconds: int,
        started_at: Optional[datetime] = None,
        completed_at: Optional[datetime] = None,
    ) -> str:
        """
        Format scan results as Markdown string.

        Args:
            target: The scanned target URL
            mode: Scan mode used
            findings: List of finding dictionaries
            stats: Scan statistics
            duration_seconds: Total scan duration
            started_at: Scan start time
            completed_at: Scan completion time

        Returns:
            Markdown string
        """
        lines = []

        # Header
        lines.append("# BREACH Security Scan Report")
        lines.append("")
        lines.append(f"**Target:** {target}")
        lines.append(f"**Mode:** {mode.upper()}")
        lines.append(f"**Date:** {datetime.utcnow().strftime('%Y-%m-%d %H:%M UTC')}")
        lines.append(f"**Duration:** {duration_seconds // 60}m {duration_seconds % 60}s")
        lines.append("")

        # Executive Summary
        lines.append("## Executive Summary")
        lines.append("")

        total_findings = len(findings)
        exploited_count = sum(1 for f in findings if f.get("is_exploited"))

        if total_findings == 0:
            lines.append("No vulnerabilities were discovered during this scan.")
        else:
            lines.append(f"**{total_findings}** vulnerabilities discovered")
            if exploited_count > 0:
                lines.append(f"**{exploited_count}** successfully exploited with proof")
            lines.append("")

            # Severity breakdown
            lines.append("| Severity | Count |")
            lines.append("|----------|-------|")
            lines.append(f"| {self.SEVERITY_EMOJI['critical']} Critical | {stats.get('critical_count', 0)} |")
            lines.append(f"| {self.SEVERITY_EMOJI['high']} High | {stats.get('high_count', 0)} |")
            lines.append(f"| {self.SEVERITY_EMOJI['medium']} Medium | {stats.get('medium_count', 0)} |")
            lines.append(f"| {self.SEVERITY_EMOJI['low']} Low | {stats.get('low_count', 0)} |")
            lines.append(f"| {self.SEVERITY_EMOJI['info']} Info | {stats.get('info_count', 0)} |")
            lines.append("")

            # Business Impact
            impact = stats.get("total_impact", 0)
            if impact > 0:
                if impact >= 1_000_000:
                    impact_str = f"${impact/1_000_000:.1f}M"
                elif impact >= 1_000:
                    impact_str = f"${impact/1_000:.0f}K"
                else:
                    impact_str = f"${impact:.0f}"
                lines.append(f"**Estimated Business Impact:** {impact_str}")
                lines.append("")

        # Findings
        if findings:
            lines.append("## Findings")
            lines.append("")

            # Sort by severity
            severity_order = {"critical": 0, "high": 1, "medium": 2, "low": 3, "info": 4}
            sorted_findings = sorted(
                findings,
                key=lambda f: severity_order.get(f.get("severity", "info").lower(), 5)
            )

            for i, f in enumerate(sorted_findings, 1):
                lines.extend(self._format_finding(i, f))
                lines.append("")

        # Footer
        lines.append("---")
        lines.append("")
        lines.append(f"*Generated by BREACH v2.0.0 on {datetime.utcnow().isoformat()}*")

        return "\n".join(lines)

    def _format_finding(self, index: int, finding: Dict[str, Any]) -> List[str]:
        """Format a single finding as Markdown."""
        lines = []

        severity = finding.get("severity", "info").lower()
        emoji = self.SEVERITY_EMOJI.get(severity, "")
        title = finding.get("title", "Unknown Vulnerability")

        # Exploited badge
        exploited_badge = ""
        if finding.get("is_exploited"):
            confidence = finding.get("exploitation_confidence", 0) * 100
            exploited_badge = f" [EXPLOITED {confidence:.0f}%]"

        lines.append(f"### {index}. {emoji} {title}{exploited_badge}")
        lines.append("")

        # Details table
        lines.append("| Property | Value |")
        lines.append("|----------|-------|")
        lines.append(f"| Severity | **{severity.upper()}** |")
        lines.append(f"| Category | {finding.get('vulnerability_type') or finding.get('category', 'N/A')} |")
        lines.append(f"| Endpoint | `{finding.get('endpoint', 'N/A')}` |")
        lines.append(f"| Method | {finding.get('method', 'GET')} |")

        if finding.get("parameter"):
            lines.append(f"| Parameter | `{finding['parameter']}` |")

        impact = finding.get("business_impact", 0)
        if impact > 0:
            if impact >= 1_000_000:
                impact_str = f"${impact/1_000_000:.1f}M"
            elif impact >= 1_000:
                impact_str = f"${impact/1_000:.0f}K"
            else:
                impact_str = f"${impact:.0f}"
            lines.append(f"| Business Impact | {impact_str} |")

        lines.append("")

        # Description
        if finding.get("description"):
            lines.append("**Description:**")
            lines.append(finding["description"])
            lines.append("")

        # Payload
        if finding.get("payload"):
            lines.append("**Payload:**")
            lines.append(f"```")
            lines.append(finding["payload"])
            lines.append("```")
            lines.append("")

        # cURL command
        if self.include_poc and finding.get("curl_command"):
            lines.append("**Reproduction (cURL):**")
            lines.append("```bash")
            lines.append(finding["curl_command"])
            lines.append("```")
            lines.append("")

        # PoC Script
        if self.include_poc and finding.get("poc_script"):
            lines.append("**PoC Script:**")
            lines.append("```python")
            lines.append(finding["poc_script"])
            lines.append("```")
            lines.append("")

        # Reproduction Steps
        if finding.get("reproduction_steps"):
            lines.append("**Reproduction Steps:**")
            for step in finding["reproduction_steps"]:
                lines.append(f"1. {step}")
            lines.append("")

        # Evidence (for exploited findings)
        if self.include_evidence and finding.get("is_exploited"):
            proof_type = finding.get("proof_type") or finding.get("exploitation_proof_type")
            if proof_type:
                lines.append(f"**Exploitation Proof:** {proof_type}")
                lines.append("")

        # Remediation
        remediation = finding.get("remediation") or finding.get("fix_suggestion")
        if remediation:
            lines.append("**Remediation:**")
            lines.append(remediation)
            lines.append("")

        # CWE Reference
        if finding.get("cwe_id"):
            lines.append(f"**Reference:** [CWE-{finding['cwe_id']}](https://cwe.mitre.org/data/definitions/{finding['cwe_id']}.html)")
            lines.append("")

        return lines

    def save(
        self,
        filepath: str,
        target: str,
        mode: str,
        findings: List[Dict[str, Any]],
        stats: Dict[str, Any],
        duration_seconds: int,
        **kwargs,
    ) -> None:
        """
        Save scan results to a Markdown file.

        Args:
            filepath: Output file path
            target: The scanned target URL
            mode: Scan mode used
            findings: List of finding dictionaries
            stats: Scan statistics
            duration_seconds: Total scan duration
            **kwargs: Additional arguments passed to format()
        """
        content = self.format(
            target=target,
            mode=mode,
            findings=findings,
            stats=stats,
            duration_seconds=duration_seconds,
            **kwargs,
        )

        Path(filepath).write_text(content)
