"""HTML Report Generator for MCP Security Audit.

Generates a self-contained HTML report with inline CSS.
Dark theme, dashboard layout with score, severity breakdown, and findings.
"""

from __future__ import annotations

from datetime import datetime, timezone

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


def format_html(summary: ScanSummary) -> str:
    """Generate a self-contained HTML report from scan results.

    Args:
        summary: Aggregate scan summary with all results.

    Returns:
        Complete HTML string with inline CSS and all findings.
    """
    timestamp: str = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
    counts: dict[str, int] = summary.severity_counts
    grade: str = summary.overall_grade
    grade_color: str = _grade_color(grade)

    findings_html: str = _build_findings_html(summary)
    files_summary: str = _build_files_summary(summary)

    return f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MCP Security Audit Report</title>
<style>
{_get_css()}
</style>
</head>
<body>
<div class="container">
  <header>
    <h1>MCP Security Audit</h1>
    <p class="subtitle">Static Security Analysis Report</p>
    <p class="timestamp">{timestamp}</p>
  </header>

  <div class="dashboard">
    <div class="card grade-card">
      <div class="card-label">Overall Grade</div>
      <div class="grade" style="color: {grade_color}">{grade}</div>
    </div>
    <div class="card">
      <div class="card-label">Files Scanned</div>
      <div class="card-value">{summary.total_files}</div>
    </div>
    <div class="card">
      <div class="card-label">Lines Scanned</div>
      <div class="card-value">{summary.total_lines:,}</div>
    </div>
    <div class="card">
      <div class="card-label">Total Findings</div>
      <div class="card-value">{summary.total_findings}</div>
    </div>
    <div class="card">
      <div class="card-label">Scan Time</div>
      <div class="card-value">{summary.total_scan_time_ms:.0f}ms</div>
    </div>
  </div>

  <div class="severity-bar">
    <h2>Severity Breakdown</h2>
    <div class="bar-container">
      {_build_severity_bar(counts)}
    </div>
    <div class="severity-legend">
      <span class="legend-item">
        <span class="dot critical"></span>Critical: {counts['CRITICAL']}
      </span>
      <span class="legend-item">
        <span class="dot high"></span>High: {counts['HIGH']}
      </span>
      <span class="legend-item">
        <span class="dot medium"></span>Medium: {counts['MEDIUM']}
      </span>
      <span class="legend-item">
        <span class="dot low"></span>Low: {counts['LOW']}
      </span>
      <span class="legend-item">
        <span class="dot info"></span>Info: {counts['INFO']}
      </span>
    </div>
  </div>

  <div class="files-section">
    <h2>Files Summary</h2>
    {files_summary}
  </div>

  <div class="findings-section">
    <h2>Detailed Findings</h2>
    {findings_html}
  </div>

  <footer>
    <p>Generated by <strong>mcpaudit v{__version__}</strong> — Zero-dependency MCP security scanner</p>
    <p>Created by Carlos Miret | github.com/cmiretf</p>
  </footer>
</div>
</body>
</html>"""


def _build_severity_bar(counts: dict[str, int]) -> str:
    """Build the severity distribution bar HTML.

    Args:
        counts: Dict mapping severity name to count.

    Returns:
        HTML string with bar segments.
    """
    total: int = sum(counts.values())
    if total == 0:
        return '<div class="bar-segment clean" style="width:100%">Clean</div>'

    segments: list[str] = []
    for sev_name, css_class in [
        ("CRITICAL", "critical"),
        ("HIGH", "high"),
        ("MEDIUM", "medium"),
        ("LOW", "low"),
        ("INFO", "info"),
    ]:
        count: int = counts.get(sev_name, 0)
        if count > 0:
            pct: float = max(count / total * 100, 5)  # min 5% for visibility
            segments.append(
                f'<div class="bar-segment {css_class}" '
                f'style="width:{pct:.1f}%">{count}</div>'
            )
    return "\n      ".join(segments)


def _build_files_summary(summary: ScanSummary) -> str:
    """Build the files summary table HTML.

    Args:
        summary: Aggregate scan summary.

    Returns:
        HTML table string.
    """
    if not summary.results:
        return "<p>No files scanned.</p>"

    rows: list[str] = []
    for r in summary.results:
        grade_color: str = _grade_color(r.grade)
        finding_count: int = len(r.findings)
        status: str = "Clean" if finding_count == 0 else f"{finding_count} findings"
        rows.append(
            f"<tr>"
            f'<td class="file-path">{_escape(r.file)}</td>'
            f'<td style="color:{grade_color};font-weight:bold">{r.grade}</td>'
            f"<td>{r.lines_scanned:,}</td>"
            f"<td>{status}</td>"
            f"<td>{r.scan_time_ms:.1f}ms</td>"
            f"</tr>"
        )

    return f"""<table>
    <thead>
      <tr><th>File</th><th>Grade</th><th>Lines</th><th>Status</th><th>Time</th></tr>
    </thead>
    <tbody>
      {"".join(rows)}
    </tbody>
    </table>"""


def _build_findings_html(summary: ScanSummary) -> str:
    """Build the detailed findings HTML.

    Args:
        summary: Aggregate scan summary.

    Returns:
        HTML string with all findings.
    """
    if summary.total_findings == 0:
        return '<div class="no-findings">No security findings detected.</div>'

    sections: list[str] = []
    for result in summary.results:
        if not result.findings:
            continue

        findings_html: list[str] = []
        severity_order: list[Severity] = list(Severity)
        sorted_findings: list[Finding] = sorted(
            result.findings,
            key=lambda x: severity_order.index(x.severity),
        )

        for f in sorted_findings:
            sev_class: str = f.severity.value.lower()
            snippet_html: str = ""
            if f.code_snippet:
                snippet_html = (
                    f'<div class="snippet">'
                    f"<code>{_escape(f.code_snippet)}</code></div>"
                )
            rec_html: str = ""
            if f.recommendation:
                rec_html = (
                    f'<div class="recommendation">'
                    f"Fix: {_escape(f.recommendation)}</div>"
                )

            confidence_class: str = f.confidence.lower() if f.confidence else "high"
            confidence_html: str = (
                f'<span class="confidence-badge {confidence_class}">'
                f"{_escape(f.confidence)}</span>"
            )

            findings_html.append(f"""
        <div class="finding {sev_class}">
          <div class="finding-header">
            <span class="severity-badge {sev_class}">{f.severity.value}</span>
            {confidence_html}
            <span class="rule-id">{_escape(f.rule_id)}</span>
            <span class="finding-title">{_escape(f.title)}</span>
            <span class="line-num">Line {f.line}</span>
          </div>
          <div class="finding-body">
            <p>{_escape(f.description)}</p>
            {snippet_html}
            {rec_html}
          </div>
        </div>""")

        sections.append(
            f'<div class="file-findings">'
            f'<h3>{_escape(result.file)}</h3>'
            f'{"".join(findings_html)}'
            f"</div>"
        )

    return "\n".join(sections)


def _grade_color(grade: str) -> str:
    """Get CSS color for a security grade.

    Args:
        grade: Letter grade (A+ through F).

    Returns:
        CSS color string.
    """
    colors: dict[str, str] = {
        "A+": "#00e676",
        "A": "#66bb6a",
        "B": "#ffca28",
        "C": "#ff9800",
        "D": "#ff5722",
        "F": "#f44336",
    }
    return colors.get(grade, "#888")


def _escape(text: str) -> str:
    """Escape HTML special characters.

    Args:
        text: Raw text to escape.

    Returns:
        HTML-safe string.
    """
    return (
        text.replace("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace('"', "&quot;")
    )


def _get_css() -> str:
    """Return the complete CSS for the report.

    Returns:
        CSS string with all styles.
    """
    return """
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: #0d1117;
  color: #c9d1d9;
  line-height: 1.6;
}
.container {
  max-width: 1100px;
  margin: 0 auto;
  padding: 2rem;
}
header {
  text-align: center;
  margin-bottom: 2rem;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid #21262d;
}
header h1 {
  font-size: 2rem;
  color: #58a6ff;
  margin-bottom: 0.3rem;
}
.subtitle { color: #8b949e; font-size: 1.1rem; }
.timestamp { color: #484f58; font-size: 0.85rem; margin-top: 0.5rem; }
.dashboard {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1rem;
  margin-bottom: 2rem;
}
.card {
  background: #161b22;
  border: 1px solid #21262d;
  border-radius: 8px;
  padding: 1.2rem;
  text-align: center;
}
.card-label { color: #8b949e; font-size: 0.8rem; text-transform: uppercase; }
.card-value { font-size: 1.8rem; font-weight: bold; margin-top: 0.3rem; }
.grade-card .grade { font-size: 3rem; font-weight: 900; }
h2 {
  font-size: 1.3rem;
  color: #c9d1d9;
  margin-bottom: 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid #21262d;
}
.severity-bar { margin-bottom: 2rem; }
.bar-container {
  display: flex;
  height: 32px;
  border-radius: 6px;
  overflow: hidden;
  margin-bottom: 0.8rem;
}
.bar-segment {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  font-weight: bold;
  color: #fff;
}
.bar-segment.critical { background: #f44336; }
.bar-segment.high { background: #ff9800; }
.bar-segment.medium { background: #ffca28; color: #000; }
.bar-segment.low { background: #4caf50; }
.bar-segment.info { background: #2196f3; }
.bar-segment.clean { background: #00e676; color: #000; }
.severity-legend {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.legend-item { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; }
.dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
}
.dot.critical { background: #f44336; }
.dot.high { background: #ff9800; }
.dot.medium { background: #ffca28; }
.dot.low { background: #4caf50; }
.dot.info { background: #2196f3; }
table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 2rem;
}
th, td {
  padding: 0.6rem 0.8rem;
  text-align: left;
  border-bottom: 1px solid #21262d;
}
th { color: #8b949e; font-size: 0.8rem; text-transform: uppercase; }
.file-path {
  font-family: 'SF Mono', Monaco, monospace;
  font-size: 0.85rem;
  color: #58a6ff;
}
.file-findings { margin-bottom: 1.5rem; }
.file-findings h3 {
  font-family: 'SF Mono', Monaco, monospace;
  font-size: 0.9rem;
  color: #58a6ff;
  margin-bottom: 0.8rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid #21262d;
}
.finding {
  background: #161b22;
  border: 1px solid #21262d;
  border-radius: 6px;
  margin-bottom: 0.8rem;
  overflow: hidden;
}
.finding.critical { border-left: 3px solid #f44336; }
.finding.high { border-left: 3px solid #ff9800; }
.finding.medium { border-left: 3px solid #ffca28; }
.finding.low { border-left: 3px solid #4caf50; }
.finding.info { border-left: 3px solid #2196f3; }
.finding-header {
  padding: 0.6rem 1rem;
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
}
.severity-badge {
  padding: 0.15rem 0.5rem;
  border-radius: 4px;
  font-size: 0.7rem;
  font-weight: bold;
  color: #fff;
}
.severity-badge.critical { background: #f44336; }
.severity-badge.high { background: #ff9800; }
.severity-badge.medium { background: #ffca28; color: #000; }
.severity-badge.low { background: #4caf50; }
.severity-badge.info { background: #2196f3; }
.confidence-badge {
  padding: 0.1rem 0.4rem;
  border-radius: 3px;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
}
.confidence-badge.high {
  background: rgba(255, 255, 255, 0.15);
  color: #e6edf3;
  border: 1px solid rgba(255, 255, 255, 0.2);
}
.confidence-badge.medium {
  background: rgba(255, 202, 40, 0.15);
  color: #ffca28;
  border: 1px solid rgba(255, 202, 40, 0.3);
}
.confidence-badge.low {
  background: rgba(139, 148, 158, 0.15);
  color: #8b949e;
  border: 1px solid rgba(139, 148, 158, 0.3);
}
.rule-id {
  font-family: 'SF Mono', Monaco, monospace;
  font-size: 0.8rem;
  color: #8b949e;
}
.finding-title { font-weight: 600; }
.line-num {
  margin-left: auto;
  font-family: 'SF Mono', Monaco, monospace;
  font-size: 0.8rem;
  color: #484f58;
}
.finding-body {
  padding: 0.6rem 1rem 0.8rem;
  border-top: 1px solid #21262d;
}
.finding-body p { margin-bottom: 0.4rem; }
.snippet {
  background: #0d1117;
  border: 1px solid #21262d;
  border-radius: 4px;
  padding: 0.5rem 0.8rem;
  margin: 0.4rem 0;
  overflow-x: auto;
}
.snippet code {
  font-family: 'SF Mono', Monaco, monospace;
  font-size: 0.85rem;
  color: #e6edf3;
}
.recommendation {
  color: #3fb950;
  font-size: 0.85rem;
  margin-top: 0.3rem;
}
.no-findings {
  background: #161b22;
  border: 1px solid #21262d;
  border-radius: 8px;
  padding: 2rem;
  text-align: center;
  color: #3fb950;
  font-size: 1.2rem;
}
footer {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid #21262d;
  text-align: center;
  color: #484f58;
  font-size: 0.85rem;
}
footer strong { color: #58a6ff; }
"""
