"""
Fabric Warehouse Advisor — Performance Check Reports
======================================================
Generates text, Markdown, and HTML reports from :class:`CheckSummary`.
"""

from __future__ import annotations

from typing import Dict, List

from .findings import (
    CheckSummary,
    Finding,
    LEVEL_CRITICAL,
    LEVEL_HIGH,
    LEVEL_MEDIUM,
    LEVEL_LOW,
    LEVEL_INFO,
    SEVERITY_ORDER,
    CATEGORY_WAREHOUSE_TYPE,
    CATEGORY_DATA_TYPES,
    CATEGORY_CACHING,
    CATEGORY_STATISTICS,
    CATEGORY_VORDER,
    CATEGORY_COLLATION,
    CATEGORY_QUERY_REGRESSION,
)


# -- Category display metadata ------------------------------------------

_CATEGORY_LABELS = {
    CATEGORY_WAREHOUSE_TYPE: "Warehouse Type",
    CATEGORY_DATA_TYPES: "Data Types",
    CATEGORY_CACHING: "Caching",
    CATEGORY_VORDER: "V-Order Optimization",
    CATEGORY_STATISTICS: "Statistics Health",
    CATEGORY_COLLATION: "Collation Consistency",
    CATEGORY_QUERY_REGRESSION: "Query Regression",
}

_CATEGORY_ORDER = [
    CATEGORY_DATA_TYPES,
    CATEGORY_CACHING,
    CATEGORY_VORDER,
    CATEGORY_STATISTICS,
    CATEGORY_COLLATION,
    CATEGORY_QUERY_REGRESSION,
]

_LEVEL_ICONS = {
    LEVEL_CRITICAL: "❌",
    LEVEL_HIGH: "🔴",
    LEVEL_MEDIUM: "🟠",
    LEVEL_LOW: "🟡",
    LEVEL_INFO: "✅",
}


# ======================================================================
# TEXT REPORT
# ======================================================================

def generate_text_report(summary: CheckSummary) -> str:
    """Generate a plain-text report with Unicode box drawing."""
    lines: List[str] = []
    w = 72

    lines.append("╔" + "═" * w + "╗")
    lines.append("║" + " Fabric Warehouse Performance Check Report".center(w) + "║")
    lines.append("╚" + "═" * w + "╝")
    lines.append("")
    lines.append(f"  Warehouse : {summary.warehouse_name}")
    lines.append(f"  Edition   : {summary.warehouse_edition}")
    lines.append(f"  Tables    : {summary.total_tables_analyzed}")
    lines.append(f"  Columns   : {summary.total_columns_analyzed}")
    lines.append("")

    # Summary bar
    lines.append("━" * w)
    lines.append("  SUMMARY")
    lines.append(f"    ❌ CRITICAL : {summary.critical_count}")
    lines.append(f"    🔴 HIGH     : {summary.high_count}")
    lines.append(f"    🟠 MEDIUM   : {summary.medium_count}")
    lines.append(f"    🟡 LOW      : {summary.low_count}")
    lines.append(f"    ✅ INFO     : {summary.info_count}")
    lines.append(f"    Total      : {len(summary.findings)} findings")
    lines.append("━" * w)
    lines.append("")

    # Findings grouped by category
    for cat in _CATEGORY_ORDER:
        cat_findings = summary.findings_by_category(cat)
        if not cat_findings:
            continue

        label = _CATEGORY_LABELS.get(cat, cat)
        crit = sum(1 for f in cat_findings if f.is_critical)
        high = sum(1 for f in cat_findings if f.is_high)
        med = sum(1 for f in cat_findings if f.is_medium)
        low = sum(1 for f in cat_findings if f.is_low)
        info = sum(1 for f in cat_findings if f.is_info)

        lines.append(f"━━━ {label.upper()} ({crit} critical, {high} high, {med} medium, {low} low, {info} info) ━━━")
        lines.append("")

        if cat == CATEGORY_QUERY_REGRESSION:
            lines.append("  ⚠️  This analysis runs warehouse-wide and is not filtered")
            lines.append("     by schema/table selections.")
            lines.append("")

        # Group same-check findings for deduplication
        grouped = _group_findings(cat_findings)
        for check_name, findings in grouped.items():
            if len(findings) > 5:
                # Summarize large groups
                lines.append(f"  {_LEVEL_ICONS.get(findings[0].level, '•')} "
                             f"{findings[0].message} (×{len(findings)} occurrences)")
                lines.append(f"    Affected objects:")
                for f in findings[:5]:
                    lines.append(f"      • {f.object_name}")
                if len(findings) > 5:
                    lines.append(f"      ... and {len(findings) - 5} more")
                if findings[0].recommendation:
                    lines.append(f"    → {findings[0].recommendation}")
                lines.append("")
            else:
                for f in findings:
                    icon = _LEVEL_ICONS.get(f.level, "•")
                    lines.append(f"  {icon} [{f.object_name}] {f.message}")
                    if f.detail:
                        lines.append(f"    {f.detail}")
                    if f.recommendation:
                        lines.append(f"    → {f.recommendation}")
                    if f.sql_fix:
                        lines.append(f"    SQL: {f.sql_fix}")
                    lines.append("")

    # Footer
    lines.append("═" * w)
    lines.append("  Generated by Fabric Warehouse Advisor")
    lines.append("═" * w)

    return "\n".join(lines)


# ======================================================================
# MARKDOWN REPORT
# ======================================================================

def generate_markdown_report(summary: CheckSummary) -> str:
    """Generate a Markdown report."""
    lines: List[str] = []

    lines.append("# 🔍 Fabric Warehouse Performance Check Report")
    lines.append("")
    lines.append(f"| Property | Value |")
    lines.append(f"|----------|-------|")
    lines.append(f"| Warehouse | `{summary.warehouse_name}` |")
    lines.append(f"| Edition | `{summary.warehouse_edition}` |")
    lines.append(f"| Tables Analysed | {summary.total_tables_analyzed} |")
    lines.append(f"| Columns Analysed | {summary.total_columns_analyzed} |")
    lines.append("")

    # Summary
    lines.append("## Summary")
    lines.append("")
    lines.append(f"| Level | Count |")
    lines.append(f"|-------|-------|")
    lines.append(f"| ❌ Critical | **{summary.critical_count}** |")
    lines.append(f"| 🔴 High | **{summary.high_count}** |")
    lines.append(f"| 🟠 Medium | **{summary.medium_count}** |")
    lines.append(f"| 🟡 Low | **{summary.low_count}** |")
    lines.append(f"| ✅ Info | {summary.info_count} |")
    lines.append(f"| **Total** | **{len(summary.findings)}** |")
    lines.append("")

    # Findings by category
    for cat in _CATEGORY_ORDER:
        cat_findings = summary.findings_by_category(cat)
        if not cat_findings:
            continue

        label = _CATEGORY_LABELS.get(cat, cat)
        crit = sum(1 for f in cat_findings if f.is_critical)
        high = sum(1 for f in cat_findings if f.is_high)

        badge = ""
        if crit > 0:
            badge = f" — ❌ {crit} critical"
        elif high > 0:
            badge = f" — 🔴 {high} high"

        lines.append(f"## {label}{badge}")
        lines.append("")

        if cat == CATEGORY_QUERY_REGRESSION:
            lines.append("> **⚠️ Note:** This analysis runs warehouse-wide and is not filtered by schema/table selections.")
            lines.append("")

        grouped = _group_findings(cat_findings)
        for check_name, findings in grouped.items():
            if len(findings) > 5:
                f0 = findings[0]
                lines.append(f"### {_LEVEL_ICONS.get(f0.level, '•')} {f0.message} (×{len(findings)})")
                lines.append("")
                if f0.detail:
                    lines.append(f"> {f0.detail}")
                    lines.append("")
                lines.append("<details>")
                lines.append(f"<summary>Affected objects ({len(findings)})</summary>")
                lines.append("")
                for f in findings:
                    lines.append(f"- `{f.object_name}`")
                lines.append("")
                lines.append("</details>")
                lines.append("")
                if f0.recommendation:
                    lines.append(f"**Recommendation:** {f0.recommendation}")
                    lines.append("")
                if f0.sql_fix:
                    lines.append("```sql")
                    lines.append(f0.sql_fix)
                    lines.append("```")
                    lines.append("")
            else:
                for f in findings:
                    icon = _LEVEL_ICONS.get(f.level, "•")
                    lines.append(f"- {icon} **`{f.object_name}`** — {f.message}")
                    if f.detail:
                        lines.append(f"  > {f.detail}")
                    if f.recommendation:
                        lines.append(f"  - **Recommendation:** {f.recommendation}")
                    if f.sql_fix:
                        lines.append(f"  ```sql")
                        lines.append(f"  {f.sql_fix}")
                        lines.append(f"  ```")
                    lines.append("")

    # Footer
    lines.append("---")
    lines.append("*Generated by Fabric Warehouse Advisor*")

    return "\n".join(lines)


# ======================================================================
# HTML REPORT
# ======================================================================

def generate_html_report(summary: CheckSummary, captured_at: str | None = None) -> str:
    """Generate a self-contained HTML report."""
    from datetime import datetime, timezone
    if captured_at is None:
        captured_at = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")

    crit_count = summary.critical_count
    high_count = summary.high_count
    med_count = summary.medium_count
    low_count = summary.low_count
    info_count = summary.info_count

    html_parts: List[str] = []
    html_parts.append(_HTML_HEAD)

    # Header
    html_parts.append('<div class="container">')
    html_parts.append('<h1>\U0001f50d Fabric Warehouse Performance Check Report</h1>')
    html_parts.append(f'<div class="meta-bar">\u2699\ufe0f Generated: {captured_at}</div>')

    # Metadata cards
    html_parts.append('<div class="summary-grid">')
    html_parts.append(_card("Warehouse", summary.warehouse_name, "\U0001f3e2"))
    html_parts.append(_card("Edition", summary.warehouse_edition, "\U0001f4e6"))
    html_parts.append(_card("Tables", str(summary.total_tables_analyzed), "\U0001f4cb"))
    html_parts.append(_card("Columns", str(summary.total_columns_analyzed), "\U0001f4d0"))
    html_parts.append('</div>')

    # Severity summary
    html_parts.append('<div class="summary-grid">')
    html_parts.append(_severity_card("Critical", crit_count, "critical", "\U0001f534"))
    html_parts.append(_severity_card("High", high_count, "high", "\U0001f7e0"))
    html_parts.append(_severity_card("Medium", med_count, "medium", "\U0001f7e1"))
    html_parts.append(_severity_card("Low", low_count, "low", "\U0001f535"))
    html_parts.append(_severity_card("Info", info_count, "info", "\U0001f7e2"))
    html_parts.append(_severity_card("Total", len(summary.findings), "total", "\U0001f4ca"))
    html_parts.append('</div>')

    # Findings by category
    for cat in _CATEGORY_ORDER:
        cat_findings = summary.findings_by_category(cat)
        if not cat_findings:
            continue

        label = _CATEGORY_LABELS.get(cat, cat)
        crit = sum(1 for f in cat_findings if f.is_critical)
        high = sum(1 for f in cat_findings if f.is_high)
        med = sum(1 for f in cat_findings if f.is_medium)
        low = sum(1 for f in cat_findings if f.is_low)
        info = sum(1 for f in cat_findings if f.is_info)

        cat_id = cat.replace(' ', '-')
        html_parts.append(f'<h2>{label}</h2>')
        if cat == CATEGORY_QUERY_REGRESSION:
            html_parts.append(
                '<div class="meta-bar" style="margin-bottom:12px;">'
                '⚠️ This analysis runs warehouse-wide and is not filtered '
                'by schema/table selections.'
                '</div>'
            )
        html_parts.append(
            f'<p class="cat-summary" data-cat="{cat_id}">'
            f'<span class="badge critical filter-badge" data-level="critical" data-cat="{cat_id}">{crit} critical</span> '
            f'<span class="badge high filter-badge" data-level="high" data-cat="{cat_id}">{high} high</span> '
            f'<span class="badge medium filter-badge" data-level="medium" data-cat="{cat_id}">{med} medium</span> '
            f'<span class="badge low filter-badge" data-level="low" data-cat="{cat_id}">{low} low</span> '
            f'<span class="badge info filter-badge" data-level="info" data-cat="{cat_id}">{info} info</span>'
            f'</p>'
        )

        # Findings table
        html_parts.append(f'<table data-cat="{cat_id}">')
        html_parts.append(
            '<thead><tr>'
            '<th class="col-level">Level</th><th>Object</th>'
            '<th>Rule Name</th><th>Finding</th>'
            '<th>Recommendation</th>'
            '</tr></thead>'
        )
        html_parts.append('<tbody>')

        grouped = _group_findings(cat_findings)
        for check_name, findings in grouped.items():
            if len(findings) > 10:
                # Collapsed summary row
                f0 = findings[0]
                level_cls = f0.level.lower()
                html_parts.append(
                    f'<tr class="finding-{level_cls}" data-level="{level_cls}">'
                    f'<td class="col-level"><span class="badge {level_cls}">{f0.level}</span></td>'
                    f'<td><em>{len(findings)} objects</em></td>'
                    f'<td><code>{_esc(f0.check_name)}</code></td>'
                    f'<td>{_esc(f0.message)}'
                )
                if f0.detail:
                    html_parts.append(f'<br><small>{_esc(f0.detail)}</small>')
                html_parts.append(
                    f'<br><details><summary>Show all {len(findings)} objects</summary><ul>'
                )
                for f in findings:
                    html_parts.append(f'<li><code>{_esc(f.object_name)}</code></li>')
                html_parts.append('</ul></details></td>')
                rec = _esc(f0.recommendation) if f0.recommendation else ""
                if f0.sql_fix:
                    rec += (
                        f'<details class="sql-details"><summary>Show SQL</summary>'
                        f'<pre class="sql">{_esc(f0.sql_fix)}</pre></details>'
                    )
                html_parts.append(f'<td>{rec}</td></tr>')
            else:
                for f in findings:
                    level_cls = f.level.lower()
                    html_parts.append(
                        f'<tr class="finding-{level_cls}" data-level="{level_cls}">'
                        f'<td class="col-level"><span class="badge {level_cls}">{f.level}</span></td>'
                        f'<td><code>{_esc(f.object_name)}</code></td>'
                        f'<td><code>{_esc(f.check_name)}</code></td>'
                        f'<td>{_esc(f.message)}'
                    )
                    if f.detail:
                        html_parts.append(f'<br><small>{_esc(f.detail)}</small>')
                    html_parts.append('</td>')
                    rec = _esc(f.recommendation) if f.recommendation else ""
                    if f.sql_fix:
                        rec += (
                            f'<details class="sql-details"><summary>Show SQL</summary>'
                            f'<pre class="sql">{_esc(f.sql_fix)}</pre></details>'
                        )
                    html_parts.append(f'<td>{rec}</td></tr>')

        html_parts.append('</tbody></table>')

    # Footer
    html_parts.append(
        '<p class="footer">Generated by Fabric Warehouse Advisor</p>'
    )
    html_parts.append('</div>')

    return "\n".join(html_parts)


# -- Helpers -------------------------------------------------------------

def _group_findings(findings: List[Finding]) -> Dict[str, List[Finding]]:
    """Group findings by check_name, preserving order."""
    grouped: Dict[str, List[Finding]] = {}
    for f in findings:
        grouped.setdefault(f.check_name, []).append(f)
    return grouped


def _esc(text: str) -> str:
    """Escape HTML special characters."""
    return (
        text.replace("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace('"', "&quot;")
    )


def _card(label: str, value: str, icon: str = "") -> str:
    icon_html = f"{icon} " if icon else ""
    return (
        f'<div class="card">'
        f'<div class="card-label">{label}</div>'
        f'<div class="card-value">{icon_html}{_esc(value)}</div>'
        f'</div>'
    )


def _severity_card(label: str, count: int, css_class: str, icon: str = "") -> str:
    icon_html = f"{icon} " if icon else ""
    return (
        f'<div class="card severity-{css_class}">'
        f'<div class="card-label">{label}</div>'
        f'<div class="card-value">{icon_html}{count}</div>'
        f'</div>'
    )


# -- HTML template -------------------------------------------------------

_HTML_HEAD = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Fabric Warehouse Performance Check Report</title>
<style>
  :root {
    --fabric-blue: #0078d4;
    --fabric-dark: #1a1a2e;
    --critical-red: #d32f2f;
    --high-orange: #e65100;
    --medium-amber: #f57c00;
    --low-yellow: #fbc02d;
    --info-green: #388e3c;
    --bg: #f5f5f5;
    --card-bg: #ffffff;
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: var(--bg);
    color: #333;
    line-height: 1.6;
  }
  .container { max-width: 1200px; margin: 0 auto; padding: 24px; }
  h1 {
    color: var(--fabric-blue);
    border-bottom: 3px solid var(--fabric-blue);
    padding-bottom: 12px;
    margin-bottom: 24px;
    font-size: 1.6em;
  }
  h2 {
    color: var(--fabric-dark);
    margin-top: 32px;
    margin-bottom: 12px;
    font-size: 1.3em;
  }
  .summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
    margin-bottom: 20px;
  }
  .card {
    background: #f5f8fc;
    border-left: 4px solid var(--fabric-blue);
    border-radius: 8px;
    padding: 16px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.12);
    text-align: center;
  }
  .card-label { font-size: 0.85em; color: #666; margin-bottom: 4px; }
  .card-value { font-size: 1.4em; font-weight: 600; }
  .severity-critical .card-value { color: var(--critical-red); }
  .severity-high .card-value { color: var(--high-orange); }
  .severity-medium .card-value { color: var(--medium-amber); }
  .severity-low .card-value { color: var(--low-yellow); }
  .severity-info .card-value { color: var(--info-green); }
  .severity-total .card-value { color: var(--fabric-blue); }
  .meta-bar {
    background: #f5f8fc;
    border-left: 4px solid var(--fabric-blue);
    padding: 10px 16px;
    border-radius: 6px;
    margin-bottom: 20px;
    font-size: 0.9em;
    color: #555;
  }
  .meta-bar strong { color: #333; }
  .cat-summary { margin-bottom: 12px; }
  .badge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 12px;
    font-size: 0.8em;
    font-weight: 600;
    color: #fff;
  }
  .badge.critical { background: var(--critical-red); }
  .badge.high { background: var(--high-orange); }
  .badge.medium { background: var(--medium-amber); }
  .badge.low { background: var(--low-yellow); color: #333; }
  .badge.info { background: var(--info-green); }
  table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 24px;
    background: var(--card-bg);
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0,0,0,0.12);
  }
  th {
    background: var(--fabric-dark);
    color: #fff;
    padding: 10px 14px;
    text-align: left;
    font-size: 0.85em;
  }
  td {
    padding: 10px 14px;
    border-bottom: 1px solid #eee;
    font-size: 0.9em;
    vertical-align: top;
  }
  tr:last-child td { border-bottom: none; }
  tr.finding-critical { border-left: 4px solid var(--critical-red); }
  tr.finding-high { border-left: 4px solid var(--high-orange); }
  tr.finding-medium { border-left: 4px solid var(--medium-amber); }
  tr.finding-low { border-left: 4px solid var(--low-yellow); }
  tr.finding-info { border-left: 4px solid var(--info-green); }
  code {
    background: #e8e8e8;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 0.85em;
  }
  pre.sql {
    background: #1e1e1e;
    color: #d4d4d4;
    padding: 10px 14px;
    border-radius: 6px;
    font-family: 'Cascadia Code', 'Consolas', monospace;
    font-size: 0.82em;
    margin-top: 8px;
    overflow-x: auto;
    white-space: pre-wrap;
  }
  details { margin-top: 6px; }
  details summary { cursor: pointer; color: var(--fabric-blue); font-size: 0.85em; }
  details ul { margin: 6px 0 0 20px; font-size: 0.85em; }
  small { color: #666; }
  .col-level { width: 80px; text-align: center; }
  .filter-badge { cursor: pointer; transition: opacity 0.2s, box-shadow 0.2s; }
  .filter-badge:hover { opacity: 0.85; box-shadow: 0 0 0 2px rgba(0,0,0,0.2); }
  .filter-badge.active { box-shadow: 0 0 0 3px var(--fabric-blue); }
  .sql-details summary { cursor: pointer; color: var(--fabric-blue); font-size: 0.85em; margin-top: 6px; }
  .footer {
    text-align: center;
    margin-top: 40px;
    color: #999;
    font-size: 0.85em;
  }
</style>
</head>
<body>
<script>
document.addEventListener('click', function(e) {
  var badge = e.target.closest('.filter-badge');
  if (!badge) return;
  var level = badge.getAttribute('data-level');
  var catId = badge.getAttribute('data-cat');
  var table = document.querySelector('table[data-cat="' + catId + '"]');
  if (!table) return;
  var wasActive = badge.classList.contains('active');
  // Clear all active badges in this category
  var siblings = badge.parentElement.querySelectorAll('.filter-badge');
  for (var i = 0; i < siblings.length; i++) siblings[i].classList.remove('active');
  var rows = table.querySelectorAll('tbody tr');
  if (wasActive) {
    // Show all rows
    for (var i = 0; i < rows.length; i++) rows[i].style.display = '';
  } else {
    badge.classList.add('active');
    for (var i = 0; i < rows.length; i++) {
      rows[i].style.display = rows[i].getAttribute('data-level') === level ? '' : 'none';
    }
  }
});
</script>
"""
