"""Unstructured x Codeflash — Security Audit Report

Four-tab standalone report covering supply chain and build pipeline security
findings identified during the performance engagement:
  1. Summary          — hero metrics, executive summary, audit scope, CTA
  2. Critical & High  — the 21 most urgent findings
  3. Medium & Low     — 18 remaining findings
  4. By Category      — category breakdown with horizontal bars
"""

import json
import re
from pathlib import Path

from dash import Dash, Input, Output, clientside_callback, html
from theme import (
    ACCENT,
    AMBER,
    BG,
    BLUE,
    CARD,
    CARD_BG,
    CARD_BORDER,
    FONT,
    GRAY,
    GREEN,
    LIGHT_GRAY,
    LIGHT_RED,
    MONO,
    RED,
    SLATE,
    WHITE,
)

# ── Data ────────────────────────────────────────────────────────────────────
_DATA = json.loads((Path(__file__).parent / "security_data.json").read_text())

FINDINGS = _DATA["findings"]
SUMMARY = _DATA["summary"]
AUDIT_META = _DATA.get("audit_metadata", {})
CORE_PRODUCT_BASE = _DATA["core_product_base"]
GITHUB_WORKFLOWS_BASE = _DATA["github_workflows_base"]

SEVERITY_COLORS = {
    "critical": RED,
    "high": "#f97316",  # orange
    "medium": AMBER,
    "low": BLUE,
    "info": GRAY,
}

SEVERITY_BG = {
    "critical": LIGHT_RED,
    "high": "rgba(249,115,22,0.12)",
    "medium": "rgba(251,191,36,0.12)",
    "low": "rgba(96,165,250,0.12)",
    "info": "rgba(161,161,170,0.12)",
}

STATUS_COLORS = {
    "fixed": "#34d399",  # emerald-400 (distinct from severity green)
    "partially-fixed": "#c084fc",  # purple-400 (avoids orange/amber overlap)
    "open": "#f87171",  # red-400 (open = still a problem)
    "active": "#22d3ee",  # cyan-400 (distinct from severity blue)
}

_TAB_BTN_STYLE = {
    "padding": "10px 24px",
    "border": "none",
    "borderRadius": "8px",
    "cursor": "pointer",
    "fontSize": "14px",
    "fontWeight": "600",
    "fontFamily": f"'{FONT}', system-ui, -apple-system, sans-serif",
    "background": "transparent",
    "color": GRAY,
    "transition": "all 0.2s",
}

_TAB_BTN_ACTIVE = {**_TAB_BTN_STYLE, "background": RED, "color": WHITE}


# ── Helpers ──────────────────────────────────────────────────────────────────


def section(title, subtitle=None):
    children = [
        html.H2(
            title,
            style={
                "fontSize": "22px",
                "fontWeight": "700",
                "color": SLATE,
                "margin": "0",
                "fontFamily": FONT,
                "letterSpacing": "-0.01em",
            },
        )
    ]
    if subtitle:
        children.append(
            html.P(
                subtitle,
                style={
                    "fontSize": "14px",
                    "color": GRAY,
                    "margin": "6px 0 0",
                    "lineHeight": "1.5",
                },
            )
        )
    return html.Div(children, style={"margin": "56px 0 24px"})


def card(children, **kw):
    style = {**CARD}
    for k, v in kw.items():
        style[k] = v
    return html.Div(children, style=style)


SEVERITY_ICONS = {
    "critical": "\u25cf",  # filled circle
    "high": "\u25b2",  # filled triangle
    "medium": "\u25c6",  # filled diamond
    "low": "\u25cb",  # open circle
    "info": "\u2139",  # info symbol
}


def severity_badge(severity):
    icon = SEVERITY_ICONS.get(severity, "")
    return html.Span(
        [
            html.Span(
                icon,
                style={"marginRight": "5px", "fontSize": "9px"},
            ),
            severity.upper(),
        ],
        style={
            "fontSize": "11px",
            "fontWeight": "700",
            "color": SEVERITY_COLORS.get(severity, GRAY),
            "background": SEVERITY_BG.get(severity, "transparent"),
            "padding": "3px 10px",
            "borderRadius": "999px",
            "letterSpacing": "0.05em",
            "display": "inline-flex",
            "alignItems": "center",
        },
    )


def status_badge(status):
    return html.Span(
        status.upper(),
        style={
            "fontSize": "11px",
            "fontWeight": "700",
            "color": STATUS_COLORS.get(status, GRAY),
            "background": "transparent",
            "border": f"1px solid {STATUS_COLORS.get(status, GRAY)}",
            "padding": "2px 10px",
            "borderRadius": "999px",
            "letterSpacing": "0.05em",
        },
    )


_REPO_URLS = {
    "core-product": "https://github.com/Unstructured-IO/core-product/pull",
    "github-workflows": "https://github.com/Unstructured-IO/github-workflows/pull",
    "platform-libs": "https://github.com/Unstructured-IO/platform-libs/pull",
    "unstructured": "https://github.com/Unstructured-IO/unstructured/pull",
    "unstructured-inference": "https://github.com/Unstructured-IO/unstructured-inference/pull",
}


def _linkify_fixed_by(text, repo):
    """Turn 'Unstructured (PR #1465)' into text with clickable PR links."""
    # Find all #NNNN references
    parts = re.split(r"(#\d+)", text)
    result = []
    for part in parts:
        m = re.match(r"#(\d+)", part)
        if m:
            pr_num = m.group(1)
            # Determine base URL from repo field
            base = None
            for key, url in _REPO_URLS.items():
                if key in repo:
                    base = url
                    break
            if base:
                result.append(
                    html.A(
                        part,
                        href=f"{base}/{pr_num}",
                        target="_blank",
                        rel="noopener noreferrer",
                        style={
                            "color": GREEN,
                            "fontWeight": "600",
                            "textDecoration": "underline",
                            "cursor": "pointer",
                        },
                    )
                )
            else:
                result.append(
                    html.Span(
                        part, style={"color": GREEN, "fontWeight": "600"}
                    )
                )
        else:
            result.append(
                html.Span(part, style={"color": GREEN, "fontWeight": "600"})
            )
    return result


def _hero_metric(value, label, color):
    return html.Div(
        [
            html.Div(
                value,
                style={
                    "fontSize": "42px",
                    "fontWeight": "800",
                    "color": color,
                    "lineHeight": "1",
                },
            ),
            html.Div(
                label,
                style={
                    "fontSize": "14px",
                    "fontWeight": "600",
                    "color": SLATE,
                    "marginTop": "8px",
                },
            ),
        ],
        style={
            "background": CARD_BG,
            "borderRadius": "16px",
            "padding": "32px 20px",
            "textAlign": "center",
            "flex": "1",
            "minWidth": "140px",
            "border": f"1px solid {CARD_BORDER}",
        },
    )


def _scope_card(value, label, detail):
    return html.Div(
        [
            html.Div(
                value,
                style={
                    "fontSize": "28px",
                    "fontWeight": "800",
                    "color": ACCENT,
                    "lineHeight": "1",
                },
            ),
            html.Div(
                label,
                style={
                    "fontSize": "14px",
                    "fontWeight": "700",
                    "color": SLATE,
                    "marginTop": "8px",
                },
            ),
            html.Div(
                detail,
                style={
                    "fontSize": "12px",
                    "color": GRAY,
                    "marginTop": "4px",
                },
            ),
        ],
        style={
            "background": CARD_BG,
            "borderRadius": "12px",
            "padding": "24px 20px",
            "textAlign": "center",
            "flex": "1",
            "minWidth": "180px",
            "border": f"1px solid {CARD_BORDER}",
        },
    )


def _category_row(category, count, total):
    pct = count / total * 100 if total else 0
    return html.Div(
        [
            html.Div(
                category,
                style={
                    "fontSize": "14px",
                    "color": SLATE,
                    "fontWeight": "600",
                    "minWidth": "180px",
                },
            ),
            html.Div(
                style={
                    "flex": "1",
                    "height": "8px",
                    "background": "rgba(255,255,255,0.05)",
                    "borderRadius": "4px",
                    "overflow": "hidden",
                },
                children=[
                    html.Div(
                        style={
                            "width": f"{pct}%",
                            "height": "100%",
                            "background": ACCENT,
                            "borderRadius": "4px",
                        },
                    ),
                ],
            ),
            html.Div(
                str(count),
                style={
                    "fontSize": "14px",
                    "fontWeight": "700",
                    "color": SLATE,
                    "minWidth": "30px",
                    "textAlign": "right",
                },
            ),
        ],
        style={
            "display": "flex",
            "alignItems": "center",
            "gap": "16px",
            "marginBottom": "12px",
        },
    )


def finding_card(f):
    """Render a single finding as a card."""
    sev = f["severity"]
    border_color = SEVERITY_COLORS.get(sev, GRAY)

    # Header: title first (F-pattern), ID secondary, badges right
    header = html.Div(
        [
            html.Div(
                [
                    html.Div(
                        f["title"],
                        style={
                            "fontWeight": "700",
                            "color": SLATE,
                            "fontSize": "17px",
                            "lineHeight": "1.3",
                        },
                    ),
                    html.Span(
                        f["id"],
                        style={
                            "fontFamily": MONO,
                            "fontSize": "12px",
                            "color": LIGHT_GRAY,
                            "marginTop": "4px",
                            "display": "block",
                        },
                    ),
                ],
                style={"flex": "1"},
            ),
            html.Div(
                [
                    severity_badge(sev),
                    status_badge(f["status"]),
                ],
                style={
                    "display": "flex",
                    "gap": "8px",
                    "alignItems": "center",
                },
            ),
        ],
        style={
            "display": "flex",
            "alignItems": "flex-start",
            "gap": "16px",
            "marginBottom": "16px",
            "flexWrap": "wrap",
        },
    )

    # Metadata row
    meta_items = []
    if f.get("repo"):
        meta_items.append(
            html.Span(
                [
                    html.Span("Repo: ", style={"color": LIGHT_GRAY}),
                    html.Span(
                        f["repo"],
                        style={"color": SLATE, "fontWeight": "600"},
                    ),
                ],
            )
        )
    if f.get("category"):
        meta_items.append(
            html.Span(
                [
                    html.Span("Category: ", style={"color": LIGHT_GRAY}),
                    html.Span(
                        f["category"],
                        style={"color": SLATE, "fontWeight": "600"},
                    ),
                ],
            )
        )
    if f.get("duration_exposed"):
        meta_items.append(
            html.Span(
                [
                    html.Span("Exposed: ", style={"color": LIGHT_GRAY}),
                    html.Span(
                        f["duration_exposed"],
                        style={"color": RED, "fontWeight": "600"},
                    ),
                ],
            )
        )
    if f.get("fixed_by"):
        meta_items.append(
            html.Div(
                [
                    html.Span("Fixed by: ", style={"color": LIGHT_GRAY}),
                    *_linkify_fixed_by(f["fixed_by"], f.get("repo", "")),
                ],
                style={"display": "inline"},
            )
        )

    meta = html.Div(
        meta_items,
        style={
            "display": "flex",
            "gap": "24px",
            "flexWrap": "wrap",
            "fontSize": "13px",
            "marginBottom": "16px",
            "paddingBottom": "16px",
            "borderBottom": f"1px solid {CARD_BORDER}",
        },
    )

    # Description
    desc = html.P(
        f["description"],
        style={
            "color": GRAY,
            "fontSize": "14px",
            "lineHeight": "1.7",
            "margin": "0 0 16px",
        },
    )

    # Impact list
    impact = html.Div(
        [
            html.Div(
                "Impact",
                style={
                    "fontSize": "12px",
                    "fontWeight": "700",
                    "color": ACCENT,
                    "textTransform": "uppercase",
                    "letterSpacing": "0.05em",
                    "marginBottom": "8px",
                },
            ),
            html.Ul(
                [
                    html.Li(
                        i,
                        style={
                            "fontSize": "13px",
                            "color": GRAY,
                            "lineHeight": "1.6",
                            "marginBottom": "4px",
                        },
                    )
                    for i in f["impact"]
                ],
                style={
                    "paddingLeft": "20px",
                    "margin": "0",
                },
            ),
        ],
        style={"marginBottom": "16px"},
    )

    children = [header, meta, desc, impact]

    # Files affected
    if f.get("files"):
        files_section = html.Div(
            [
                html.Div(
                    "Affected Files",
                    style={
                        "fontSize": "12px",
                        "fontWeight": "700",
                        "color": ACCENT,
                        "textTransform": "uppercase",
                        "letterSpacing": "0.05em",
                        "marginBottom": "8px",
                    },
                ),
                html.Div(
                    [
                        html.Div(
                            path,
                            style={
                                "fontFamily": MONO,
                                "fontSize": "12px",
                                "color": LIGHT_GRAY,
                                "padding": "4px 0",
                            },
                        )
                        for path in (
                            f["files"]
                            if isinstance(f["files"], list)
                            else [f["files"]]
                        )
                    ],
                ),
            ],
            style={"marginBottom": "16px"},
        )
        children.append(files_section)

    # Context
    if f.get("context"):
        children.append(
            html.P(
                f["context"],
                style={
                    "color": LIGHT_GRAY,
                    "fontSize": "13px",
                    "lineHeight": "1.6",
                    "margin": "0",
                    "fontStyle": "italic",
                },
            )
        )

    return html.Div(
        children,
        style={
            **CARD,
            "marginBottom": "20px",
            "borderLeft": f"4px solid {border_color}",
        },
    )


# ── Findings split by severity ──────────────────────────────────────────────
# Order categories by what matters most to the audience: supply chain and
# container security work they're already doing, then CI/CD, secrets, code.
_CATEGORY_PRIORITY = {
    "Supply Chain": 0,
    "Docker/Container Security": 1,
    "CI/CD Security": 2,
    "Secrets Management": 3,
    "Code-Level Vulnerability": 4,
    "PKI/Cryptography": 5,
    "Vulnerability Management": 6,
    "Build Reproducibility": 7,
    "Build Pipeline": 8,
    "Positive Control": 9,
}
_SEV_PRIORITY = {"critical": 0, "high": 1, "medium": 2, "low": 3, "info": 4}


def _finding_sort_key(f):
    return (
        _SEV_PRIORITY.get(f["severity"], 9),
        _CATEGORY_PRIORITY.get(f["category"], 9),
    )


_CRITICAL_HIGH = sorted(
    [f for f in FINDINGS if f["severity"] in ("critical", "high")],
    key=_finding_sort_key,
)
_MEDIUM_LOW = sorted(
    [f for f in FINDINGS if f["severity"] not in ("critical", "high")],
    key=_finding_sort_key,
)


# ── Tab content builders ────────────────────────────────────────────────────


def _build_summary_tab():
    """Tab 1: hero metrics, executive summary, scope cards, CTA."""
    return html.Div(
        id="summary-view",
        children=[
            # ── Executive Summary ──
            section("Executive Summary"),
            card(
                [
                    html.P(
                        [
                            "We audited all ",
                            html.Span(
                                "8 Unstructured repositories",
                                style={"fontWeight": "700", "color": SLATE},
                            ),
                            f" end-to-end: {AUDIT_META.get('workflow_files_audited', 69)} CI/CD workflows, "
                            f"{AUDIT_META.get('dockerfiles_audited', 6)} Dockerfiles, "
                            f"and {AUDIT_META.get('action_references_audited', 446)} GitHub Action references. "
                            "The scope covers the same layers you're already hardening \u2014 "
                            "supply chain integrity, container security, CI/CD pipeline permissions, "
                            "and dependency management \u2014 plus code-level vulnerabilities, "
                            "secrets handling, and PKI.",
                        ],
                        style={
                            "color": GRAY,
                            "fontSize": "15px",
                            "lineHeight": "1.7",
                            "margin": "0 0 16px",
                        },
                    ),
                    html.P(
                        [
                            "We found ",
                            html.Span(
                                f"{SUMMARY['total_findings']} findings",
                                style={"fontWeight": "700", "color": SLATE},
                            ),
                            " including ",
                            html.Span(
                                f"{SUMMARY['critical']} critical",
                                style={"fontWeight": "700", "color": RED},
                            ),
                            " and ",
                            html.Span(
                                f"{SUMMARY['high']} high",
                                style={
                                    "fontWeight": "700",
                                    "color": "#f97316",
                                },
                            ),
                            " severity issues. The lockfile-bypass pattern you fixed in core-product "
                            "(PR #1465) still persists in CI steps and Makefiles across the org. "
                            "Supply chain, container, and CI/CD injection issues account for the "
                            "majority \u2014 the same categories where Renovate and Anchore give you "
                            "visibility but not full coverage.",
                        ],
                        style={
                            "color": GRAY,
                            "fontSize": "15px",
                            "lineHeight": "1.7",
                            "margin": "0 0 16px",
                        },
                    ),
                    html.P(
                        [
                            "For a platform processing sensitive documents across regulated industries "
                            "(HIPAA, SOC 2, PCI-DSS), these gaps are material \u2014 especially ahead "
                            "of the next NCC Group assessment cycle.",
                        ],
                        style={
                            "color": GRAY,
                            "fontSize": "15px",
                            "lineHeight": "1.7",
                            "margin": "0",
                        },
                    ),
                ]
            ),
            # ── Audit scope ──
            section("Audit Scope"),
            html.Div(
                style={
                    "display": "flex",
                    "gap": "16px",
                    "flexWrap": "wrap",
                    "marginBottom": "24px",
                },
                children=[
                    _scope_card(
                        "69",
                        "CI/CD Workflows",
                        "Injection, permissions, secrets, runners",
                    ),
                    _scope_card(
                        "6",
                        "Dockerfiles",
                        "Root containers, base images, layer leaks",
                    ),
                    _scope_card(
                        "446",
                        "Action References",
                        "SHA pinning, supply chain, third-party risk",
                    ),
                    _scope_card(
                        "8",
                        "Repositories",
                        "Code, config, infrastructure, PKI",
                    ),
                ],
            ),
            # ── CTA ──
            html.Div(
                style={
                    "marginTop": "56px",
                    "textAlign": "center",
                    "padding": "56px 32px",
                    "background": f"linear-gradient(135deg, rgba(239,68,68,0.06) 0%, {CARD_BG} 40%, {CARD_BG} 60%, rgba(239,68,68,0.06) 100%)",
                    "borderRadius": "16px",
                    "border": f"1px solid {CARD_BORDER}",
                },
                children=[
                    # Loss-framed percentage anchor (Change #4)
                    html.Div(
                        f"{round(SUMMARY['open'] / SUMMARY['total_findings'] * 100)}%",
                        style={
                            "fontSize": "72px",
                            "fontWeight": "800",
                            "color": RED,
                            "lineHeight": "1",
                        },
                    ),
                    html.Div(
                        "of findings remain unresolved",
                        style={
                            "fontSize": "20px",
                            "fontWeight": "600",
                            "color": SLATE,
                            "marginTop": "8px",
                        },
                    ),
                    html.Div(
                        f"{SUMMARY['open']} of {SUMMARY['total_findings']} security issues across {len(SUMMARY.get('by_repo', {}))} repositories",
                        style={
                            "fontSize": "14px",
                            "fontFamily": MONO,
                            "color": LIGHT_GRAY,
                            "marginTop": "8px",
                        },
                    ),
                    # Urgency line (loss framing)
                    html.P(
                        "These span supply chain, CI/CD injection, container, and secrets management "
                        "\u2014 the same categories where one engineer can't cover everything alone.",
                        style={
                            "color": GRAY,
                            "fontSize": "15px",
                            "lineHeight": "1.7",
                            "margin": "24px auto 0",
                            "maxWidth": "560px",
                        },
                    ),
                ],
            ),
        ],
    )


def _build_critical_high_tab():
    """Tab 2: critical and high severity findings."""
    n = len(_CRITICAL_HIGH)
    return html.Div(
        id="critical-high-view",
        style={"display": "none"},
        children=[
            section(
                "Critical & High Findings",
                f"{n} findings \u2014 supply chain, container, CI/CD, and secrets",
            ),
            *[finding_card(f) for f in _CRITICAL_HIGH],
        ],
    )


def _build_medium_low_tab():
    """Tab 3: medium, low, and info severity findings."""
    n = len(_MEDIUM_LOW)
    return html.Div(
        id="medium-low-view",
        style={"display": "none"},
        children=[
            section(
                "Medium & Low Findings",
                f"{n} findings for planned remediation",
            ),
            *[finding_card(f) for f in _MEDIUM_LOW],
        ],
    )


def _build_category_tab():
    """Tab 4: findings breakdown by category with horizontal bars."""
    return html.Div(
        id="category-view",
        style={"display": "none"},
        children=[
            section("Findings by Category"),
            card(
                [
                    _category_row(cat, cnt, SUMMARY["total_findings"])
                    for cat, cnt in sorted(
                        SUMMARY.get("by_category", {}).items(),
                        key=lambda x: x[1],
                        reverse=True,
                    )
                ],
                padding="28px",
            ),
            # ── By repo breakdown ──
            section("Findings by Repository"),
            card(
                [
                    _category_row(repo, cnt, SUMMARY["total_findings"])
                    for repo, cnt in sorted(
                        SUMMARY.get("by_repo", {}).items(),
                        key=lambda x: x[1],
                        reverse=True,
                    )
                ],
                padding="28px",
            ),
        ],
    )


# ── App ──────────────────────────────────────────────────────────────────────

app = Dash(
    __name__,
    meta_tags=[
        {"name": "viewport", "content": "width=device-width, initial-scale=1"},
        {
            "property": "og:title",
            "content": "Unstructured x Codeflash \u2014 Security Audit",
        },
    ],
    suppress_callback_exceptions=True,
)
app.title = "Unstructured x Codeflash \u2014 Security Audit"

app.index_string = """<!DOCTYPE html>
<html>
<head>
    {%metas%}
    <title>{%title%}</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet">
    {%favicon%}
    {%css%}
</head>
<body>
    {%app_entry%}
    <footer>
        {%config%}
        {%scripts%}
        {%renderer%}
    </footer>
</body>
</html>"""

app.layout = html.Div(
    style={
        "background": BG,
        "minHeight": "100vh",
        "fontFamily": FONT,
        "position": "relative",
    },
    children=[
        # ── Hero ──
        html.Div(
            style={
                "background": f"linear-gradient(135deg, {BG} 0%, #131a24 50%, {BG} 100%)",
                "padding": "60px 24px 52px",
                "textAlign": "center",
                "borderBottom": f"1px solid {CARD_BORDER}",
                "position": "relative",
                "zIndex": "1",
            },
            children=[
                html.Div(
                    style={
                        "display": "flex",
                        "alignItems": "center",
                        "justifyContent": "center",
                        "gap": "20px",
                        "marginBottom": "24px",
                    },
                    children=[
                        html.Img(
                            src="/assets/codeflash.svg",
                            style={"height": "32px"},
                        ),
                        html.Span(
                            "\u00d7",
                            style={
                                "fontSize": "24px",
                                "fontWeight": "300",
                                "color": LIGHT_GRAY,
                            },
                        ),
                        html.Img(
                            src="/assets/unstructured_logo.jpg",
                            style={
                                "height": "36px",
                                "borderRadius": "6px",
                            },
                        ),
                    ],
                ),
                html.H1(
                    "Security Audit",
                    style={
                        "color": WHITE,
                        "fontSize": "36px",
                        "fontWeight": "800",
                        "margin": "0",
                        "letterSpacing": "-0.02em",
                        "fontFamily": FONT,
                    },
                ),
                html.P(
                    "Comprehensive security audit across 8 repositories \u2014 supply chain, CI/CD, "
                    "container security, code-level vulnerabilities, secrets management, and PKI",
                    style={
                        "color": GRAY,
                        "fontSize": "17px",
                        "margin": "12px auto 0",
                        "maxWidth": "700px",
                    },
                ),
                html.Div(
                    style={
                        "marginTop": "24px",
                        "display": "flex",
                        "justifyContent": "center",
                        "gap": "24px",
                        "flexWrap": "wrap",
                    },
                    children=[
                        html.Span(
                            "April 2026",
                            style={"color": LIGHT_GRAY, "fontSize": "13px"},
                        ),
                        html.Span("|", style={"color": LIGHT_GRAY}),
                        html.Span(
                            f"{AUDIT_META.get('repos_audited', 8)} repos audited",
                            style={"color": LIGHT_GRAY, "fontSize": "13px"},
                        ),
                        html.Span("|", style={"color": LIGHT_GRAY}),
                        html.Span(
                            f"{SUMMARY['total_findings']} findings",
                            style={"color": LIGHT_GRAY, "fontSize": "13px"},
                        ),
                        html.Span("|", style={"color": LIGHT_GRAY}),
                        html.Span(
                            f"{SUMMARY['open']} open",
                            style={"color": LIGHT_GRAY, "fontSize": "13px"},
                        ),
                    ],
                ),
            ],
        ),
        # ── Content ──
        html.Div(
            style={
                "maxWidth": "960px",
                "margin": "0 auto",
                "padding": "0 24px 80px",
                "position": "relative",
                "zIndex": "1",
            },
            children=[
                # ── Summary metrics ──
                html.Div(
                    style={
                        "display": "flex",
                        "gap": "16px",
                        "flexWrap": "wrap",
                        "marginTop": "-40px",
                        "position": "relative",
                        "zIndex": "1",
                    },
                    children=[
                        _hero_metric(
                            str(SUMMARY["critical"]), "Critical", RED
                        ),
                        _hero_metric(str(SUMMARY["high"]), "High", "#f97316"),
                        _hero_metric(str(SUMMARY["medium"]), "Medium", AMBER),
                        _hero_metric(str(SUMMARY["low"]), "Low", BLUE),
                        _hero_metric(
                            str(SUMMARY["open"]),
                            "Open",
                            AMBER,
                        ),
                    ],
                ),
                # ── Tab bar ──
                html.Div(
                    style={
                        "display": "flex",
                        "justifyContent": "center",
                        "margin": "40px 0 8px",
                    },
                    children=[
                        html.Div(
                            style={
                                "display": "inline-flex",
                                "background": CARD_BG,
                                "borderRadius": "12px",
                                "padding": "4px",
                                "border": f"1px solid {CARD_BORDER}",
                            },
                            children=[
                                html.Button(
                                    "Summary",
                                    id="btn-summary",
                                    n_clicks=1,
                                    style=_TAB_BTN_ACTIVE,
                                ),
                                html.Button(
                                    f"Critical & High ({len(_CRITICAL_HIGH)})",
                                    id="btn-crit-high",
                                    n_clicks=0,
                                    style=_TAB_BTN_STYLE,
                                ),
                                html.Button(
                                    f"Medium & Low ({len(_MEDIUM_LOW)})",
                                    id="btn-med-low",
                                    n_clicks=0,
                                    style=_TAB_BTN_STYLE,
                                ),
                                html.Button(
                                    "By Category",
                                    id="btn-category",
                                    n_clicks=0,
                                    style=_TAB_BTN_STYLE,
                                ),
                            ],
                        ),
                    ],
                ),
                # ═══════════════════════════════════════════════════════════════
                # TAB 1: SUMMARY
                # ═══════════════════════════════════════════════════════════════
                _build_summary_tab(),
                # ═══════════════════════════════════════════════════════════════
                # TAB 2: CRITICAL & HIGH
                # ═══════════════════════════════════════════════════════════════
                _build_critical_high_tab(),
                # ═══════════════════════════════════════════════════════════════
                # TAB 3: MEDIUM & LOW
                # ═══════════════════════════════════════════════════════════════
                _build_medium_low_tab(),
                # ═══════════════════════════════════════════════════════════════
                # TAB 4: BY CATEGORY
                # ═══════════════════════════════════════════════════════════════
                _build_category_tab(),
                # ── Footer (always visible) ──
                html.Div(
                    style={
                        "textAlign": "center",
                        "marginTop": "64px",
                        "paddingTop": "24px",
                        "borderTop": f"1px solid {CARD_BORDER}",
                    },
                    children=[
                        html.Div(
                            style={
                                "display": "flex",
                                "alignItems": "center",
                                "justifyContent": "center",
                                "gap": "10px",
                                "marginBottom": "4px",
                            },
                            children=[
                                html.Img(
                                    src="/assets/codeflash.svg",
                                    style={"height": "16px"},
                                ),
                                html.Span(
                                    "\u00d7",
                                    style={
                                        "fontSize": "13px",
                                        "color": LIGHT_GRAY,
                                    },
                                ),
                                html.Img(
                                    src="/assets/unstructured_logo.jpg",
                                    style={
                                        "height": "20px",
                                        "borderRadius": "3px",
                                    },
                                ),
                            ],
                        ),
                        html.P(
                            "Security Audit \u2014 April 2026",
                            style={
                                "color": LIGHT_GRAY,
                                "fontSize": "13px",
                                "margin": "0",
                            },
                        ),
                    ],
                ),
            ],
        ),
    ],
)

# ── Tab toggle callback ─────────────────────────────────────────────────────

clientside_callback(
    """
    function(sum_c, ch_c, ml_c, cat_c) {
        sum_c = sum_c || 0;
        ch_c = ch_c || 0;
        ml_c = ml_c || 0;
        cat_c = cat_c || 0;
        var base = {
            "padding": "10px 24px", "border": "none", "borderRadius": "8px",
            "cursor": "pointer", "fontSize": "14px", "fontWeight": "600",
            "fontFamily": "'Inter', system-ui, -apple-system, sans-serif",
            "transition": "all 0.2s"
        };
        var active = Object.assign({}, base, {"background": "#ef4444", "color": "#ffffff"});
        var inactive = Object.assign({}, base, {"background": "transparent", "color": "#a1a1aa"});
        var show = {"display": "block"};
        var hide = {"display": "none"};
        var mx = Math.max(sum_c, ch_c, ml_c, cat_c);
        if (cat_c === mx && cat_c > 0)
            return [hide, hide, hide, show, inactive, inactive, inactive, active];
        if (ml_c === mx && ml_c > 0)
            return [hide, hide, show, hide, inactive, inactive, active, inactive];
        if (ch_c === mx && ch_c > 0)
            return [hide, show, hide, hide, inactive, active, inactive, inactive];
        return [show, hide, hide, hide, active, inactive, inactive, inactive];
    }
    """,
    Output("summary-view", "style"),
    Output("critical-high-view", "style"),
    Output("medium-low-view", "style"),
    Output("category-view", "style"),
    Output("btn-summary", "style"),
    Output("btn-crit-high", "style"),
    Output("btn-med-low", "style"),
    Output("btn-category", "style"),
    Input("btn-summary", "n_clicks"),
    Input("btn-crit-high", "n_clicks"),
    Input("btn-med-low", "n_clicks"),
    Input("btn-category", "n_clicks"),
)

server = app.server

if __name__ == "__main__":
    app.run(debug=True, port=8052)
