"""Format API responses into AI-friendly text.

Output is plain text optimized for LLM consumption — structured,
concise, with clear section headers. No Rich markup, no ANSI codes.
"""

from __future__ import annotations

import math
from typing import Any

from eip_mcp.validators import MAX_CODE_SIZE


def _truncate(text: str, limit: int) -> str:
    """Truncate text at a sentence or word boundary, never mid-word."""
    if len(text) <= limit:
        return text
    # Try to find a sentence boundary (. ! ?) before the limit
    for end in (". ", ".\n", "! ", "? "):
        idx = text.rfind(end, 0, limit)
        if idx > limit * 0.5:
            return text[:idx + 1] + " ..."
    # Fall back to last space before limit
    idx = text.rfind(" ", 0, limit)
    if idx > limit * 0.5:
        return text[:idx] + " ..."
    return text[:limit] + "..."

# ---------------------------------------------------------------------------
# Exploit ranking (same algorithm as eip-search CLI)
# ---------------------------------------------------------------------------

_MSF_RANKS: dict[str | None, float] = {
    "excellent": 1000, "great": 900, "good": 800,
    "normal": 700, "manual": 650, "low": 500,
}
_LLM_MOD: dict[str | None, float] = {
    "working_poc": 100, "exploit": 100, "scanner": 50, "tool": 25,
    "writeup": -50, "stub": -100, "trojan": -9999, "suspicious": -5000,
}


def _rank_exploit(e: dict) -> float:
    source = e.get("source", "")
    stars = e.get("github_stars") or 0
    rank = e.get("exploit_rank")
    llm = e.get("llm_classification")
    verified = e.get("verified")

    if source == "metasploit":
        base = _MSF_RANKS.get(rank, 600)
    elif source == "exploitdb":
        base = 500.0 if verified else 300.0
    elif source in ("nomisec", "github"):
        base = math.log10(stars + 1) * 100 + (100 if source == "nomisec" else 50)
    else:
        base = 10.0

    return base + _LLM_MOD.get(llm, 0) + (25 if e.get("has_code") else 0) + (50 if verified else 0)


# ---------------------------------------------------------------------------
# Search results
# ---------------------------------------------------------------------------

def format_search_results(data: dict) -> str:
    """Format search results into a text table."""
    total = data.get("total", 0)
    page = data.get("page", 1)
    total_pages = data.get("total_pages", 0)
    items = data.get("items", [])

    if total == 0:
        return "No results found."

    lines = [f"Found {total:,} vulnerabilities (page {page}/{total_pages}):\n"]

    for v in items:
        cve = v.get("cve_id") or v.get("eip_id", "?")
        sev = (v.get("severity_label") or "?").upper()
        cvss = v.get("cvss_v3_score")
        cvss_str = f"{cvss:.1f}" if cvss is not None else "--"
        epss = v.get("epss_score")
        epss_str = f"{epss*100:.1f}%" if epss is not None else "--"
        exploits = v.get("exploit_count", 0)
        kev = " [KEV]" if v.get("is_kev") else ""
        nuclei = " [NUCLEI]" if v.get("has_nuclei_template") else ""
        title = v.get("title") or "No title"

        lines.append(f"  {cve}  {sev}  CVSS:{cvss_str}  EPSS:{epss_str}  "
                      f"Exploits:{exploits}{kev}{nuclei}")
        lines.append(f"    {title}")
        lines.append("")

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Vulnerability detail
# ---------------------------------------------------------------------------

def format_vuln_detail(data: dict) -> str:
    """Format full vulnerability detail as structured text."""
    cve = data.get("cve_id") or data.get("eip_id", "?")
    sev = (data.get("severity_label") or "unknown").upper()
    title = data.get("title") or "No title"
    desc = data.get("description") or "No description available."
    cvss = data.get("cvss_v3_score")
    cvss_vec = data.get("cvss_v3_vector") or ""
    epss = data.get("epss_score")
    epss_pctl = data.get("epss_percentile")
    is_kev = data.get("is_kev", False)
    kev_date = (data.get("kev_added_at") or "")[:10]
    published = (data.get("cve_published_at") or "")[:10]
    cwes = data.get("cwe_ids") or []
    attack_vec = data.get("attack_vector") or ""
    vuln_type = data.get("vuln_type") or ""

    lines = [
        f"{'='*60}",
        f"{cve}  [{sev}]{'  [KEV]' if is_kev else ''}",
        f"{'='*60}",
        f"Title: {title}",
        "",
    ]

    # Scores
    scores = []
    if cvss is not None:
        scores.append(f"CVSS: {cvss:.1f}  {cvss_vec}")
    if epss is not None:
        pctl = f" ({epss_pctl*100:.1f}th percentile)" if epss_pctl else ""
        scores.append(f"EPSS: {epss*100:.1f}%{pctl}")
    if scores:
        lines.extend(scores)
        lines.append("")

    # Metadata
    meta = []
    if attack_vec:
        meta.append(f"Attack Vector: {attack_vec}")
    if vuln_type:
        meta.append(f"Vuln Type: {vuln_type}")
    if cwes:
        meta.append(f"CWE: {', '.join(cwes)}")
    if published:
        meta.append(f"Published: {published}")
    if is_kev and kev_date:
        meta.append(f"KEV Added: {kev_date}")
    if meta:
        lines.append(" | ".join(meta))
        lines.append("")

    lines.append("DESCRIPTION:")
    lines.append(_truncate(desc, 500))
    lines.append("")

    # Affected products
    products = data.get("affected_products") or []
    if products:
        lines.append(f"AFFECTED PRODUCTS ({len(products)}):")
        for p in products[:10]:
            vendor = p.get("vendor") or "?"
            product = p.get("product") or "?"
            vs = p.get("version_start") or "*"
            ve = p.get("version_end") or "*"
            eco = f" [{p['ecosystem']}]" if p.get("ecosystem") else ""
            lines.append(f"  - {vendor}/{product}  {vs} - {ve}{eco}")
        if len(products) > 10:
            lines.append(f"  ... and {len(products) - 10} more")
        lines.append("")

    # Exploits (ranked and grouped)
    exploits = data.get("exploits") or []
    if exploits:
        lines.append(_format_exploit_groups(exploits))
    else:
        lines.append("EXPLOITS: None")
        lines.append("")

    # Nuclei templates
    nuclei = data.get("nuclei_templates") or []
    if nuclei:
        lines.append(format_nuclei_templates(nuclei, header=True))

    # Alt identifiers
    alts = data.get("alt_identifiers") or []
    if alts:
        lines.append("ALTERNATE IDs:")
        for a in alts:
            lines.append(f"  - {a.get('type', '?')}: {a.get('value', '?')}")
        lines.append("")

    # References
    refs = data.get("references") or []
    if refs:
        lines.append(f"REFERENCES ({len(refs)}):")
        for r in refs[:8]:
            rtype = f"[{r.get('type', '')}] " if r.get("type") else ""
            lines.append(f"  - {rtype}{r.get('url', '')}")
        if len(refs) > 8:
            lines.append(f"  ... and {len(refs) - 8} more")
        lines.append("")

    return "\n".join(lines)


def _format_exploit_groups(exploits: list[dict]) -> str:
    """Group and rank exploits into display sections."""
    # Separate by category
    modules = []
    verified = []
    pocs = []
    suspicious = []

    for e in exploits:
        llm = e.get("llm_classification")
        if llm in ("trojan", "suspicious"):
            suspicious.append(e)
        elif e.get("source") == "metasploit":
            modules.append(e)
        elif e.get("source") == "exploitdb" and e.get("verified"):
            verified.append(e)
        else:
            pocs.append(e)

    # Sort each group by rank
    for group in (modules, verified, pocs, suspicious):
        group.sort(key=_rank_exploit, reverse=True)

    lines = [f"EXPLOITS ({len(exploits)} total):"]

    if modules:
        lines.append("  METASPLOIT MODULES:")
        for e in modules:
            eid = e.get("id", "?")
            rank = e.get("exploit_rank") or ""
            rank_str = f"  Rank: {rank}" if rank else ""
            lines.append(f"    - [id={eid}] {e.get('source_id', '?')}  [ruby]{rank_str}")
            if e.get("source_url"):
                lines.append(f"      {e['source_url']}")
            _append_analysis_summary(lines, e, indent=6)

    if verified:
        lines.append("  VERIFIED (ExploitDB):")
        for e in verified:
            eid = e.get("id", "?")
            lang = e.get("language") or ""
            lines.append(f"    - [id={eid}] {e.get('source_id', '?')}  [{lang}]  verified")
            if e.get("source_url"):
                lines.append(f"      {e['source_url']}")
            _append_analysis_summary(lines, e, indent=6)

    if pocs:
        shown = pocs[:10]
        lines.append("  PROOF OF CONCEPT:")
        for e in shown:
            eid = e.get("id", "?")
            stars = e.get("github_stars")
            star_str = f"★{stars}" if stars is not None else ""
            src = e.get("source", "")
            lang = e.get("language") or ""
            llm = e.get("llm_classification") or ""
            name = e.get("source_id") or f"exploit-{eid}"
            lines.append(f"    - [id={eid}] {star_str:>6}  {src:<11} {name}  [{lang}] {llm}")
            if e.get("source_url"):
                lines.append(f"      {e['source_url']}")
            _append_analysis_summary(lines, e, indent=6)
        if len(pocs) > 10:
            lines.append(f"    ... and {len(pocs) - 10} more PoCs")

    if suspicious:
        lines.append("  *** SUSPICIOUS / TROJAN ***:")
        for e in suspicious:
            eid = e.get("id", "?")
            name = e.get("source_id") or f"exploit-{eid}"
            llm = (e.get("llm_classification") or "").upper()
            lines.append(f"    - [id={eid}] WARNING: {name}  [{llm}] — flagged by AI analysis")
            _append_trojan_detail(lines, e, indent=6)

    lines.append("")
    lines.append("  Use get_exploit_code with the exploit id to view source code.")
    return "\n".join(lines)


def _append_analysis_summary(lines: list[str], exploit: dict, *, indent: int = 6) -> None:
    """Append a compact analysis summary line if LLM analysis is available."""
    analysis = exploit.get("llm_analysis")
    if not analysis:
        return
    pad = " " * indent
    parts = []
    if analysis.get("attack_type"):
        parts.append(analysis["attack_type"])
    if analysis.get("complexity"):
        parts.append(f"complexity:{analysis['complexity']}")
    if analysis.get("reliability"):
        parts.append(f"reliability:{analysis['reliability']}")
    if analysis.get("requires_auth") is True:
        parts.append("requires-auth")
    if analysis.get("target_software"):
        sw = analysis["target_software"]
        if len(sw) > 50:
            sw = sw[:47] + "..."
        parts.append(f"target:{sw}")
    if parts:
        lines.append(f"{pad}AI: {' | '.join(parts)}")
    mitre = analysis.get("mitre_techniques")
    if mitre:
        techniques = ", ".join(str(t) for t in mitre[:4])
        if len(mitre) > 4:
            techniques += f" (+{len(mitre)-4} more)"
        lines.append(f"{pad}MITRE: {techniques}")


def _append_trojan_detail(lines: list[str], exploit: dict, *, indent: int = 6) -> None:
    """Append detailed trojan analysis including deception indicators."""
    analysis = exploit.get("llm_analysis")
    if not analysis:
        return
    pad = " " * indent
    summary = analysis.get("summary")
    if summary:
        if len(summary) > 200:
            summary = summary[:197] + "..."
        lines.append(f"{pad}Summary: {summary}")
    indicators = analysis.get("deception_indicators")
    if indicators:
        lines.append(f"{pad}Deception indicators:")
        for indicator in indicators:
            lines.append(f"{pad}  - {indicator}")
    mitre = analysis.get("mitre_techniques")
    if mitre:
        lines.append(f"{pad}MITRE: {', '.join(str(t) for t in mitre)}")


# ---------------------------------------------------------------------------
# Nuclei templates
# ---------------------------------------------------------------------------

def format_nuclei_templates(templates: list[dict], *, header: bool = False) -> str:
    """Format Nuclei template info with dorks."""
    lines = []
    if header:
        lines.append(f"NUCLEI TEMPLATES ({len(templates)}):")

    for t in templates:
        tid = t.get("template_id", "?")
        name = t.get("name", "")
        sev = t.get("severity", "")
        verified = "verified" if t.get("verified") else "unverified"
        author = t.get("author", "")
        tags = ", ".join(t.get("tags") or [])

        lines.append(f"  Template: {tid}  [{sev}] [{verified}]")
        if name:
            lines.append(f"  Name: {name}")
        if author:
            lines.append(f"  Author: {author}")
        if tags:
            lines.append(f"  Tags: {tags}")
        if t.get("description"):
            lines.append(f"  Description: {_truncate(t['description'], 200)}")
        if t.get("impact"):
            lines.append(f"  Impact: {t['impact']}")
        if t.get("remediation"):
            lines.append(f"  Remediation: {t['remediation']}")

        shodan = t.get("shodan_query")
        fofa = t.get("fofa_query")
        google = t.get("google_query")
        if shodan or fofa or google:
            lines.append("  Recon Queries:")
            if shodan:
                lines.append(f"    Shodan:  {shodan}")
            if fofa:
                lines.append(f"    FOFA:    {fofa}")
            if google:
                lines.append(f"    Google:  {google}")

        lines.append(f"  Run: nuclei -t {tid} -u https://target.com")
        lines.append("")

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Exploit code
# ---------------------------------------------------------------------------

def format_exploit_code(code: str, file_path: str) -> str:
    """Format exploit source code, capped for AI context."""
    if len(code) > MAX_CODE_SIZE:
        truncated = code[:MAX_CODE_SIZE]
        return (f"File: {file_path}\n"
                f"(Truncated to {MAX_CODE_SIZE // 1024}KB — original is {len(code) // 1024}KB)\n\n"
                f"{truncated}\n\n... [TRUNCATED]")
    return f"File: {file_path}\n\n{code}"


def format_exploit_files(files: list[dict], exploit_id: int) -> str:
    """Format file listing for an exploit."""
    if not files:
        return f"No code files found for exploit {exploit_id}."
    lines = [f"Files in exploit {exploit_id} ({len(files)} files):\n"]
    for f in files:
        size = f.get("size", 0)
        if size >= 1024:
            size_str = f"{size / 1024:.1f} KB"
        else:
            size_str = f"{size} B"
        lines.append(f"  {size_str:>10}  {f.get('path', '?')}")
    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Stats & Health
# ---------------------------------------------------------------------------

def format_stats(data: dict) -> str:
    """Format platform statistics."""
    return (
        "Exploit Intelligence Platform Statistics:\n"
        f"  Total Vulnerabilities: {data.get('total_vulns', 0):,}\n"
        f"  Published:             {data.get('published', 0):,}\n"
        f"  With AI Titles:        {data.get('with_title', 0):,}\n"
        f"  With CVSS Scores:      {data.get('with_cvss', 0):,}\n"
        f"  With EPSS Scores:      {data.get('with_epss', 0):,}\n"
        f"  Critical Severity:     {data.get('critical_count', 0):,}\n"
        f"  CISA KEV Entries:      {data.get('kev_total', 0):,}\n"
        f"\n"
        f"  Vulns with Exploits:   {data.get('total_with_exploits', 0):,}\n"
        f"  Total Exploits:        {data.get('total_exploits', 0):,}\n"
        f"  With Nuclei Templates: {data.get('with_nuclei', 0):,}\n"
        f"\n"
        f"  Vendors Tracked:       {data.get('total_vendors', 0):,}\n"
        f"  Exploit Authors:       {data.get('total_authors', 0):,}\n"
        f"\n"
        f"  Last Updated: {(data.get('last_updated') or '?')[:19].replace('T', ' ')}"
    )


def format_health(data: dict) -> str:
    """Format health check response."""
    status = data.get("status", "unknown")
    db = data.get("database", "unknown")
    ingestion = data.get("ingestion", {})

    lines = [f"API Status: {status}", f"Database: {db}", "", "Ingestion Sources:"]
    for source, ts in sorted(ingestion.items()):
        ts_short = (ts or "?")[:19].replace("T", " ")
        lines.append(f"  {source:<12} {ts_short}")
    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Smart tool formatters
# ---------------------------------------------------------------------------

def format_stack_audit(results: dict[str, dict]) -> str:
    """Format audit_stack results grouped by technology."""
    lines = ["STACK AUDIT RESULTS", "=" * 40, ""]

    total_findings = 0
    for tech, data in results.items():
        items = data.get("items", [])
        total = data.get("total", 0)
        lines.append(f"--- {tech.upper()} ({total} exploitable CVEs) ---")

        if not items:
            lines.append("  No exploitable vulnerabilities found.")
            lines.append("")
            continue

        for v in items[:10]:
            cve = v.get("cve_id") or v.get("eip_id", "?")
            sev = (v.get("severity_label") or "?").upper()
            cvss = v.get("cvss_v3_score")
            cvss_str = f"{cvss:.1f}" if cvss is not None else "--"
            epss = v.get("epss_score")
            epss_str = f"{epss*100:.1f}%" if epss is not None else "--"
            kev = " [KEV]" if v.get("is_kev") else ""
            exploits = v.get("exploit_count", 0)
            title = v.get("title") or "No title"
            lines.append(f"  {cve}  {sev}  CVSS:{cvss_str}  EPSS:{epss_str}  "
                          f"Exploits:{exploits}{kev}")
            lines.append(f"    {title}")
            total_findings += 1

        if total > 10:
            lines.append(f"  ... and {total - 10} more")
        lines.append("")

    lines.append(f"Total: {total_findings} findings shown across {len(results)} technologies")
    return "\n".join(lines)


def format_finding(data: dict, target: str | None, notes: str | None) -> str:
    """Format a pentest report finding from vulnerability data."""
    cve = data.get("cve_id") or data.get("eip_id", "?")
    title = data.get("title") or "Untitled Vulnerability"
    sev = (data.get("severity_label") or "unknown").upper()
    cvss = data.get("cvss_v3_score")
    cvss_vec = data.get("cvss_v3_vector") or ""
    epss = data.get("epss_score")
    desc = data.get("description") or "No description available."
    is_kev = data.get("is_kev", False)
    cwes = data.get("cwe_ids") or []
    exploits = data.get("exploits") or []
    products = data.get("affected_products") or []
    refs = data.get("references") or []

    lines = [
        f"# {cve}: {title}",
        "",
        f"**Severity:** {sev}",
        f"**CVSS v3 Score:** {f'{cvss:.1f}  ({cvss_vec})' if cvss is not None else 'N/A'}",
        f"**EPSS Score:** {f'{epss*100:.1f}% probability of exploitation' if epss is not None else 'N/A'}",
        f"**CISA KEV:** {'Yes — confirmed actively exploited in the wild' if is_kev else 'No'}",
        f"**CWE:** {', '.join(cwes) if cwes else 'N/A'}",
        "",
    ]

    if target:
        lines.append(f"**Affected Target:** {target}")
        lines.append("")

    lines.append("## Description")
    lines.append("")
    lines.append(_truncate(desc, 800))
    lines.append("")

    lines.append("## Affected Products")
    lines.append("")
    if products:
        for p in products[:5]:
            v = p.get("vendor") or "?"
            pr = p.get("product") or "?"
            lines.append(f"- {v}/{pr}")
        if len(products) > 5:
            lines.append(f"- ... and {len(products) - 5} more")
    else:
        lines.append("N/A")
    lines.append("")

    lines.append("## Exploit Availability")
    lines.append("")
    if exploits:
        msf = [e for e in exploits if e.get("source") == "metasploit"]
        edb = [e for e in exploits if e.get("source") == "exploitdb" and e.get("verified")]
        lines.append(f"{len(exploits)} public exploit(s) identified.")
        lines.append("")
        if msf:
            for e in msf:
                url = f" — {e['source_url']}" if e.get("source_url") else ""
                lines.append(f"- **Metasploit:** {e.get('source_id', '?')}  (rank: {e.get('exploit_rank', '?')}){url}")
        if edb:
            for e in edb:
                url = f" — {e['source_url']}" if e.get("source_url") else ""
                lines.append(f"- **ExploitDB (verified):** {e.get('source_id', '?')}{url}")
        if not msf and not edb:
            lines.append(f"- {len(exploits)} public PoC(s) available on GitHub/nomi-sec")
    else:
        lines.append("No public exploits identified.")
    lines.append("")

    # MITRE ATT&CK techniques
    all_techniques = set()
    for e in exploits:
        analysis = e.get("llm_analysis") or {}
        for t in analysis.get("mitre_techniques") or []:
            all_techniques.add(str(t))
    lines.append("## MITRE ATT&CK Techniques")
    lines.append("")
    if all_techniques:
        for t in sorted(all_techniques):
            lines.append(f"- {t}")
    else:
        lines.append("N/A")
    lines.append("")

    lines.append("## References")
    lines.append("")
    if refs:
        for r in refs[:5]:
            lines.append(f"- {r.get('url', '?')}")
        if len(refs) > 5:
            lines.append(f"- ... and {len(refs) - 5} more")
    else:
        lines.append("N/A")
    lines.append("")

    if notes:
        lines.append("## Tester Notes")
        lines.append("")
        lines.append(notes)
        lines.append("")

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Exploit browse
# ---------------------------------------------------------------------------

def format_exploit_search(data: dict) -> str:
    """Format exploit browse/search results with analysis data."""
    total = data.get("total", 0)
    page = data.get("page", 1)
    total_pages = data.get("total_pages", 0)
    items = data.get("items", [])

    if total == 0:
        return "No exploits found matching the filters."

    lines = [f"Found {total:,} exploits (page {page}/{total_pages}):\n"]
    for e in items:
        eid = e.get("id", "?")
        stars = e.get("github_stars")
        star_str = f"★{stars}" if stars is not None else ""
        src = e.get("source", "?")
        lang = e.get("language") or ""
        llm = e.get("llm_classification") or ""
        name = e.get("source_id") or f"exploit-{eid}"
        cve = e.get("cve_id") or "no-CVE"
        sev = (e.get("severity_label") or "?").upper()
        cvss = e.get("cvss_v3_score")
        cvss_str = f"CVSS:{cvss:.1f}" if cvss is not None else ""

        lines.append(f"  [id={eid}] {star_str:>6}  {src:<12} {name}")
        lines.append(f"         {cve}  {sev}  {cvss_str}  [{lang}] {llm}")
        if e.get("source_url"):
            lines.append(f"         {e['source_url']}")

        # Show analysis inline when available
        analysis = e.get("llm_analysis")
        if analysis:
            parts = []
            if analysis.get("attack_type"):
                parts.append(analysis["attack_type"])
            if analysis.get("complexity"):
                parts.append(analysis["complexity"])
            if analysis.get("reliability"):
                parts.append(analysis["reliability"])
            if analysis.get("requires_auth") is True:
                parts.append("requires-auth")
            if parts:
                lines.append(f"         AI: {' | '.join(parts)}")
            # For trojans, show deception detail
            if llm in ("trojan", "suspicious"):
                indicators = analysis.get("deception_indicators")
                if indicators:
                    for ind in indicators[:2]:
                        lines.append(f"         !! {ind}")
        lines.append("")

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Authors
# ---------------------------------------------------------------------------

def format_authors_list(data: dict) -> str:
    """Format authors index."""
    total = data.get("total", 0)
    items = data.get("items", [])

    if total == 0:
        return "No authors found."

    lines = [f"Exploit Authors ({total:,} total):\n"]
    for a in items:
        handle = f" (@{a['handle']})" if a.get("handle") else ""
        lines.append(f"  {a['name']:30}  {a['exploit_count']:>4} exploits{handle}")

    return "\n".join(lines)


def format_author_detail(data: dict) -> str:
    """Format author profile."""
    name = data.get("name", "?")
    handle = data.get("handle")
    count = data.get("exploit_count", 0)
    since = (data.get("first_seen_at") or "?")[:10]
    exploits = data.get("exploits", [])

    lines = [
        f"Author: {name}" + (f" (@{handle})" if handle else ""),
        f"Exploits: {count}  |  Active since: {since}",
        "",
    ]

    if exploits:
        lines.append("Exploits:")
        for e in exploits:
            eid = e.get("id", "?")
            stars = e.get("github_stars")
            star_str = f"★{stars}" if stars is not None else ""
            cve = e.get("cve_id") or "no-CVE"
            name_str = e.get("source_id") or f"exploit-{eid}"
            llm = e.get("llm_classification") or ""
            lines.append(f"  [id={eid}] {star_str:>6}  {cve}  {name_str}  {llm}")
            if e.get("source_url"):
                lines.append(f"    {e['source_url']}")
    else:
        lines.append("No exploits found.")

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# CWE
# ---------------------------------------------------------------------------

def format_cwe_list(data: dict) -> str:
    """Format CWE index."""
    items = data.get("items", [])
    if not items:
        return "No CWE data available."

    lines = [f"CWE Categories ({data.get('total', len(items))} with vulnerabilities):\n"]
    for c in items[:30]:
        label = c.get("short_label") or c.get("name", "?")[:40]
        lines.append(f"  {c['cwe_id']:>8}  {c['vuln_count']:>6} vulns  {label}")

    if len(items) > 30:
        lines.append(f"  ... and {len(items) - 30} more")

    return "\n".join(lines)


def format_cwe_detail(data: dict) -> str:
    """Format CWE detail."""
    lines = [
        f"{data['cwe_id']}: {data['name']}",
    ]
    if data.get("short_label"):
        lines.append(f"Short label: {data['short_label']}")
    if data.get("likelihood"):
        lines.append(f"Exploit likelihood: {data['likelihood']}")
    lines.append(f"Vulnerabilities: {data.get('vuln_count', 0):,}")

    parent = data.get("parent_cwe")
    if parent:
        lines.append(f"Parent: {parent['cwe_id']} ({parent['name']})")

    if data.get("description"):
        lines.append(f"\nDescription:\n{_truncate(data['description'], 500)}")

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Vendors
# ---------------------------------------------------------------------------

def format_products_list(data: dict) -> str:
    """Format products for a vendor."""
    vendor = data.get("vendor", "?")
    items = data.get("items", [])
    if not items:
        return f"No products found for vendor '{vendor}'."

    lines = [f"Products for {vendor} ({data.get('total', len(items))} products):\n"]
    for p in items:
        lines.append(f"  {p['product']:40}  {p['vuln_count']:>5} vulns")

    lines.append(f"\nUse these product names with search_vulnerabilities(vendor='{vendor}', product='...')")
    return "\n".join(lines)


def format_vendors_list(data: dict) -> str:
    """Format vendors index."""
    items = data.get("items", [])
    if not items:
        return "No vendor data available."

    lines = [f"Top Vendors ({data.get('total', len(items))} total):\n"]
    for v in items[:30]:
        lines.append(f"  {v['vendor']:30}  {v['vuln_count']:>5} vulns")

    if len(items) > 30:
        lines.append(f"  ... and {len(items) - 30} more")

    return "\n".join(lines)
