"""
Rich formatter per output CLI premium — design v2.

Richiede ``rich`` come dipendenza opzionale:
    pip install geo-optimizer-skill[rich]

Design: dashboard immersivo con gradient, gauge gigante, barra stacked
per breakdown categorie, card dettagliate con micro-bar, e footer motivazionale.
Fallback automatico via :func:`is_rich_available`.
"""

from __future__ import annotations

import io
import os
from urllib.parse import urlparse

from geo_optimizer.cli.scoring_helpers import (
    brand_entity_score as _brand_entity_score,
)
from geo_optimizer.cli.scoring_helpers import (
    content_score as _content_score,
)
from geo_optimizer.cli.scoring_helpers import (
    llms_score as _llms_score,
)
from geo_optimizer.cli.scoring_helpers import (
    meta_score as _meta_score,
)
from geo_optimizer.cli.scoring_helpers import (
    robots_score as _robots_score,
)
from geo_optimizer.cli.scoring_helpers import (
    schema_score as _schema_score,
)
from geo_optimizer.cli.scoring_helpers import (
    signals_score as _signals_score,
)
from geo_optimizer.models.results import AuditResult

try:
    from rich import box
    from rich.align import Align
    from rich.console import Console
    from rich.panel import Panel
    from rich.table import Table
    from rich.text import Text

    RICH_AVAILABLE = True
except ImportError:
    RICH_AVAILABLE = False


# ── Helpers pubblici ──────────────────────────────────────────────────────────


def is_rich_available() -> bool:
    """Verifica se la libreria rich è disponibile."""
    return RICH_AVAILABLE


# ── Palette colori moderna ────────────────────────────────────────────────────

# Colori accessibili WCAG AA su sfondo scuro
_COLORS = {
    "excellent": "#22c55e",  # verde brillante
    "good": "#06b6d4",  # ciano
    "foundation": "#f59e0b",  # ambra
    "critical": "#ef4444",  # rosso
    "accent": "#8b5cf6",  # viola
    "muted": "#64748b",  # grigio ardesia
    "surface": "#1e293b",  # sfondo card
    "dim": "#475569",  # testo secondario
    "brand_1": "#3b82f6",  # blu brand
    "brand_2": "#06b6d4",  # ciano brand
    "brand_3": "#8b5cf6",  # viola brand
}

# Icone per categoria (più espressive delle semplici check/cross)
_CATEGORY_ICONS = {
    "robots": "🤖",
    "llms": "📄",
    "schema": "🔗",
    "meta": "🏷️",
    "content": "📝",
    "signals": "📡",
    "ai_discovery": "🔍",
}

# Bande con descrizioni e icone
_BAND_CONFIG = {
    "excellent": {"icon": "🏆", "label": "EXCELLENT", "desc": "AI-ready — ottimizzazione completa"},
    "good": {"icon": "✅", "label": "GOOD", "desc": "Buona base — pochi miglioramenti"},
    "foundation": {"icon": "⚡", "label": "FOUNDATION", "desc": "Elementi chiave mancanti"},
    "critical": {"icon": "🚨", "label": "CRITICAL", "desc": "Non visibile ai motori AI"},
}


def _band_color(band: str) -> str:
    """Restituisce il colore per la banda."""
    return _COLORS.get(band, _COLORS["critical"])


def _score_color(score: int, max_score: int = 100) -> str:
    """Colore Rich basato sulla percentuale di score."""
    pct = score / max_score if max_score > 0 else 0
    if pct >= 0.85:
        return _COLORS["excellent"]
    if pct >= 0.60:
        return _COLORS["good"]
    if pct >= 0.30:
        return _COLORS["foundation"]
    return _COLORS["critical"]


def _pct_color(pct: float) -> str:
    """Colore per percentuale (0.0 - 1.0)."""
    if pct >= 0.85:
        return _COLORS["excellent"]
    if pct >= 0.60:
        return _COLORS["good"]
    if pct >= 0.30:
        return _COLORS["foundation"]
    return _COLORS["critical"]


# ── ASCII Art grande per lo score ─────────────────────────────────────────────

# Cifre 5 righe alte — stile sottile e moderno
_DIGITS = {
    "0": ["╭━╮", "┃ ┃", "┃ ┃", "┃ ┃", "╰━╯"],
    "1": [" ╻ ", "╺┃ ", " ┃ ", " ┃ ", "╺┻╸"],
    "2": ["╭━╮", "╰━┃", "╭━╯", "┃  ", "╰━━"],
    "3": ["╭━╮", "╰━┃", " ━┃", "╭━┃", "╰━╯"],
    "4": ["╻ ╻", "┃ ┃", "╰━┃", "  ┃", "  ╹"],
    "5": ["╭━━", "┃  ", "╰━╮", "╭━┃", "╰━╯"],
    "6": ["╭━╮", "┃  ", "┣━╮", "┃ ┃", "╰━╯"],
    "7": ["━━╮", "  ┃", " ╻╯", " ┃ ", " ╹ "],
    "8": ["╭━╮", "┃ ┃", "┣━┫", "┃ ┃", "╰━╯"],
    "9": ["╭━╮", "┃ ┃", "╰━┃", "  ┃", "╰━╯"],
}


def _render_big_number(number: int, color: str) -> list[Text]:
    """Renderizza un numero grande in ASCII art (5 righe)."""
    digits = str(number)
    lines = []
    for row in range(5):
        line = Text()
        for i, d in enumerate(digits):
            if i > 0:
                line.append(" ", style="default")
            line.append(_DIGITS[d][row], style=f"bold {color}")
        lines.append(line)
    return lines


# ── Barra stacked orizzontale (breakdown categorie) ──────────────────────────


def _render_stacked_bar(categories: list[tuple[str, int, int]], width: int = 68) -> Text:
    """Barra stacked colorata che mostra il contributo di ogni categoria.

    Ogni segmento è proporzionale al punteggio ottenuto sul totale.
    """
    total_score = sum(score for _, score, _ in categories)
    bar = Text()

    # Colori per segmento
    segment_colors = [
        _COLORS["brand_1"],  # robots - blu
        _COLORS["brand_2"],  # llms - ciano
        _COLORS["accent"],  # schema - viola
        _COLORS["excellent"],  # meta - verde
        _COLORS["foundation"],  # content - ambra
        _COLORS["good"],  # signals - ciano chiaro
        _COLORS["brand_3"],  # ai_discovery - viola chiaro
    ]

    # Calcola la larghezza di ogni segmento
    if total_score == 0:
        bar.append("━" * width, style=f"dim {_COLORS['dim']}")
        return bar

    segments = []
    remaining_width = width
    for i, (_, score, _) in enumerate(categories):
        if i == len(categories) - 1:
            seg_width = remaining_width
        else:
            seg_width = max(1, round(score / total_score * width)) if score > 0 else 0
            remaining_width -= seg_width
        segments.append((seg_width, segment_colors[i % len(segment_colors)]))

    for seg_width, color in segments:
        if seg_width > 0:
            bar.append("━" * seg_width, style=f"bold {color}")

    # Riempi il resto fino a 100 punti
    sum(mx for _, _, mx in categories)
    filled_width = sum(sw for sw, _ in segments)
    empty_width = width - filled_width
    if empty_width > 0:
        bar.append("╌" * empty_width, style=f"{_COLORS['dim']}")

    return bar


def _render_legend(categories: list[tuple[str, int, int]]) -> Text:
    """Legenda compatta per la barra stacked."""
    segment_colors = [
        _COLORS["brand_1"],
        _COLORS["brand_2"],
        _COLORS["accent"],
        _COLORS["excellent"],
        _COLORS["foundation"],
        _COLORS["good"],
        _COLORS["brand_3"],
    ]

    legend = Text()
    for i, (name, score, max_score) in enumerate(categories):
        if i > 0:
            legend.append("  ", style="default")
        color = segment_colors[i % len(segment_colors)]
        legend.append("━━", style=f"bold {color}")
        legend.append(f" {name} ", style="dim")
        legend.append(f"{score}", style=f"bold {color}")
        legend.append(f"/{max_score}", style="dim")
    return legend


# ── Micro progress bar ────────────────────────────────────────────────────────


def _micro_bar(score: int, max_score: int, width: int = 20) -> Text:
    """Barra di progresso compatta con gradiente."""
    pct = score / max_score if max_score > 0 else 0
    filled = int(pct * width)
    empty = width - filled
    color = _score_color(score, max_score)

    bar = Text()
    bar.append("▓" * filled, style=f"{color}")
    bar.append("░" * empty, style=f"{_COLORS['dim']}")
    bar.append(f" {int(pct * 100)}%", style=f"bold {color}")
    return bar


# ── Header branding ──────────────────────────────────────────────────────────

# Logo minimale ma d'impatto
_LOGO_LINES = [
    ("  ╔══╗  ╔══╗  ╔══╗  ", _COLORS["brand_1"]),
    ("  ║ ═╣  ║╔═╝  ║  ║  ", _COLORS["brand_2"]),
    ("  ║ ╔╣  ║╚═╗  ║  ║  ", _COLORS["accent"]),
    ("  ╚══╝  ╚══╝  ╚══╝  ", _COLORS["brand_1"]),
]


# ── Builder card per ogni check ───────────────────────────────────────────────


def _check_status_text(passed: bool) -> Text:
    """Badge status compatto."""
    if passed:
        return Text(" PASS ", style=f"bold white on {_COLORS['excellent']}")
    return Text(" FAIL ", style=f"bold white on {_COLORS['critical']}")


def _build_robots_card(result: AuditResult, score: int, max_score: int) -> Panel:
    """Card dettagliata per Robots.txt."""
    content_parts = []

    bar = _micro_bar(score, max_score)
    content_parts.append(bar)
    content_parts.append(Text())

    if not result.robots.found:
        content_parts.append(Text("  File non trovato", style=f"italic {_COLORS['dim']}"))
    else:
        # Info bot con dettaglio
        info = Text()
        info.append(f"  ✓ {len(result.robots.bots_allowed)}", style=f"bold {_COLORS['excellent']}")
        info.append(" allowed", style=_COLORS["dim"])
        if result.robots.bots_blocked:
            info.append(f"   ✗ {len(result.robots.bots_blocked)}", style=f"bold {_COLORS['critical']}")
            info.append(" blocked", style=_COLORS["dim"])
        if result.robots.bots_partial:
            info.append(f"   ◐ {len(result.robots.bots_partial)}", style=f"bold {_COLORS['foundation']}")
            info.append(" partial", style=_COLORS["dim"])
        content_parts.append(info)

        # Citation bots
        citation = Text()
        if result.robots.citation_bots_ok:
            citation.append("  ✓ Citation bots", style=_COLORS["excellent"])
            if result.robots.citation_bots_explicit:
                citation.append(" (explicit)", style=_COLORS["dim"])
        else:
            citation.append("  ✗ Citation bots missing", style=_COLORS["critical"])
        content_parts.append(citation)

    color = _score_color(score, max_score)
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]🤖 Robots.txt[/]",
        title_align="left",
        subtitle=f"[bold {color}]{score}[/][dim]/{max_score}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_llms_card(result: AuditResult, score: int, max_score: int) -> Panel:
    """Card dettagliata per llms.txt."""
    content_parts = []

    bar = _micro_bar(score, max_score)
    content_parts.append(bar)
    content_parts.append(Text())

    if not result.llms.found:
        content_parts.append(Text("  File non trovato", style=f"italic {_COLORS['dim']}"))
    else:
        # Dettagli struttura
        features = []
        if result.llms.has_h1:
            features.append(("H1", True))
        else:
            features.append(("H1", False))
        if result.llms.has_sections:
            features.append(("Sections", True))
        else:
            features.append(("Sections", False))
        if result.llms.has_links:
            features.append(("Links", True))
        else:
            features.append(("Links", False))
        if result.llms.has_full:
            features.append(("llms-full.txt", True))
        else:
            features.append(("llms-full.txt", False))

        feat_text = Text("  ")
        for label, present in features:
            if present:
                feat_text.append(f"✓ {label}", style=_COLORS["excellent"])
            else:
                feat_text.append(f"✗ {label}", style=_COLORS["dim"])
            feat_text.append("  ", style="default")
        content_parts.append(feat_text)

        # Word count
        wc = Text()
        wc.append(f"  ~{result.llms.word_count:,} parole", style=_COLORS["dim"])
        if result.llms.sections_count:
            wc.append(f"  •  {result.llms.sections_count} sezioni", style=_COLORS["dim"])
        content_parts.append(wc)

    color = _score_color(score, max_score)
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]📄 llms.txt[/]",
        title_align="left",
        subtitle=f"[bold {color}]{score}[/][dim]/{max_score}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_schema_card(result: AuditResult, score: int, max_score: int) -> Panel:
    """Card dettagliata per Schema JSON-LD."""
    content_parts = []

    bar = _micro_bar(score, max_score)
    content_parts.append(bar)
    content_parts.append(Text())

    if not result.schema.found_types:
        content_parts.append(Text("  Nessuno schema trovato", style=f"italic {_COLORS['dim']}"))
    else:
        # Schema trovati come tag inline
        types_text = Text("  ")
        for i, schema_type in enumerate(result.schema.found_types[:6]):
            if i > 0:
                types_text.append("  ", style="default")
            types_text.append(f" {schema_type} ", style=f"bold {_COLORS['accent']} on #2e1065")
        content_parts.append(types_text)

        # Feature check
        schema_features = []
        if result.schema.has_faq:
            schema_features.append("FAQPage")
        if result.schema.has_article:
            schema_features.append("Article")
        if result.schema.has_organization:
            schema_features.append("Organization")
        if result.schema.has_website:
            schema_features.append("WebSite")
        if result.schema.has_sameas:
            schema_features.append("sameAs")

        if schema_features:
            feat = Text()
            feat.append("  ✓ ", style=_COLORS["excellent"])
            feat.append(" • ".join(schema_features), style=_COLORS["dim"])
            content_parts.append(feat)

        # Richness
        if result.schema.schema_richness_score > 0:
            rich_text = Text()
            rich_text.append(f"  Richness: {result.schema.schema_richness_score}/3", style=_COLORS["dim"])
            rich_text.append(f"  (avg {result.schema.avg_attributes_per_schema:.0f} attr)", style=_COLORS["dim"])
            content_parts.append(rich_text)

    color = _score_color(score, max_score)
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]🔗 Schema JSON-LD[/]",
        title_align="left",
        subtitle=f"[bold {color}]{score}[/][dim]/{max_score}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_meta_card(result: AuditResult, score: int, max_score: int) -> Panel:
    """Card dettagliata per Meta Tags."""
    content_parts = []

    bar = _micro_bar(score, max_score)
    content_parts.append(bar)
    content_parts.append(Text())

    # Griglia meta tag 2x2
    checks = [
        ("Title", result.meta.has_title),
        ("Description", result.meta.has_description),
        ("Canonical", result.meta.has_canonical),
        ("Open Graph", result.meta.has_og_title),
    ]
    row1 = Text("  ")
    for label, present in checks[:2]:
        icon = "✓" if present else "✗"
        color_tag = _COLORS["excellent"] if present else _COLORS["critical"]
        row1.append(f"{icon} {label}", style=color_tag)
        row1.append("     ", style="default")
    content_parts.append(row1)

    row2 = Text("  ")
    for label, present in checks[2:]:
        icon = "✓" if present else "✗"
        color_tag = _COLORS["excellent"] if present else _COLORS["critical"]
        row2.append(f"{icon} {label}", style=color_tag)
        row2.append("  ", style="default")
    content_parts.append(row2)

    # Anteprima title (se presente)
    if result.meta.title_text:
        title_preview = result.meta.title_text[:50]
        if len(result.meta.title_text) > 50:
            title_preview += "…"
        preview = Text()
        preview.append(f'  "{title_preview}"', style=f"italic {_COLORS['dim']}")
        content_parts.append(preview)

    color = _score_color(score, max_score)
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]🏷️  Meta Tags[/]",
        title_align="left",
        subtitle=f"[bold {color}]{score}[/][dim]/{max_score}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_content_card(result: AuditResult, score: int, max_score: int) -> Panel:
    """Card dettagliata per Content Quality."""
    content_parts = []

    bar = _micro_bar(score, max_score)
    content_parts.append(bar)
    content_parts.append(Text())

    # Metriche principali
    metrics = Text("  ")
    metrics.append(f"{result.content.word_count:,}", style=f"bold {_COLORS['brand_2']}")
    metrics.append(" parole", style=_COLORS["dim"])
    metrics.append("  •  ", style=_COLORS["dim"])
    metrics.append(f"{result.content.heading_count}", style=f"bold {_COLORS['brand_2']}")
    metrics.append(" headings", style=_COLORS["dim"])
    if result.content.numbers_count:
        metrics.append("  •  ", style=_COLORS["dim"])
        metrics.append(f"{result.content.numbers_count}", style=f"bold {_COLORS['brand_2']}")
        metrics.append(" stats", style=_COLORS["dim"])
    content_parts.append(metrics)

    # Feature check compatti
    features = [
        ("H1", result.content.has_h1),
        ("Hierarchy", result.content.has_heading_hierarchy),
        ("Lists", result.content.has_lists_or_tables),
        ("Front-load", result.content.has_front_loading),
        ("Ext. links", result.content.has_links),
    ]
    feat_text = Text("  ")
    for label, present in features:
        if present:
            feat_text.append(f"✓ {label}", style=_COLORS["excellent"])
        else:
            feat_text.append(f"✗ {label}", style=_COLORS["dim"])
        feat_text.append("  ", style="default")
    content_parts.append(feat_text)

    color = _score_color(score, max_score)
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]📝 Content Quality[/]",
        title_align="left",
        subtitle=f"[bold {color}]{score}[/][dim]/{max_score}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_signals_card(result: AuditResult, score: int, max_score: int) -> Panel:
    """Card compatta per Signals + AI Discovery combinati."""
    if not result.signals:
        return Panel(Text("No signals data"), title="Signals", border_style="dim")
    content_parts = []

    bar = _micro_bar(score, max_score)
    content_parts.append(bar)
    content_parts.append(Text())

    # Signals
    signals_items = [
        ("Lang attr", result.signals.has_lang),
        ("RSS feed", result.signals.has_rss),
        ("Freshness", result.signals.has_freshness),
    ]
    sig_text = Text("  ")
    for label, present in signals_items:
        if present:
            sig_text.append(f"✓ {label}", style=_COLORS["excellent"])
        else:
            sig_text.append(f"✗ {label}", style=_COLORS["dim"])
        sig_text.append("  ", style="default")
    content_parts.append(sig_text)

    # Lang value se presente
    if result.signals.has_lang and result.signals.lang_value:
        lang_text = Text()
        lang_text.append(f'  lang="{result.signals.lang_value}"', style=f"italic {_COLORS['dim']}")
        content_parts.append(lang_text)

    color = _score_color(score, max_score)
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]📡 Signals[/]",
        title_align="left",
        subtitle=f"[bold {color}]{score}[/][dim]/{max_score}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_ai_discovery_card(result: AuditResult) -> Panel | None:
    """Card per AI Discovery endpoints."""
    ai = result.ai_discovery
    if not ai.endpoints_found and not ai.has_well_known_ai:
        # Mostra solo se c'è qualcosa o se il punteggio è > 0
        pass

    content_parts = []

    # Punteggio AI Discovery
    from geo_optimizer.core.scoring import _score_ai_discovery

    score = _score_ai_discovery(ai)
    max_score = 6

    bar = _micro_bar(score, max_score)
    content_parts.append(bar)
    content_parts.append(Text())

    endpoints = [
        ("/.well-known/ai.txt", ai.has_well_known_ai),
        ("/ai/summary.json", ai.has_summary),
        ("/ai/faq.json", ai.has_faq),
        ("/ai/service.json", ai.has_service),
    ]
    for path, present in endpoints:
        line = Text("  ")
        if present:
            line.append("✓ ", style=_COLORS["excellent"])
            line.append(path, style=f"bold {_COLORS['dim']}")
        else:
            line.append("✗ ", style=_COLORS["critical"])
            line.append(path, style=_COLORS["dim"])
        content_parts.append(line)

    color = _score_color(score, max_score)
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]🔍 AI Discovery[/]",
        title_align="left",
        subtitle=f"[bold {color}]{score}[/][dim]/{max_score}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_brand_entity_card(result: AuditResult, score: int, max_score: int) -> Panel:
    """Card dettagliata per Brand & Entity Signals."""
    content_parts = []

    bar = _micro_bar(score, max_score)
    content_parts.append(bar)
    content_parts.append(Text())

    be = result.brand_entity

    # Coerenza brand name
    coherence = Text("  ")
    if be.brand_name_consistent:
        coherence.append("✓ Brand name coerente", style=_COLORS["excellent"])
    else:
        coherence.append("✗ Brand name incoerente", style=_COLORS["critical"])
    if be.names_found:
        coherence.append(f"  ({', '.join(be.names_found[:3])})", style=_COLORS["dim"])
    content_parts.append(coherence)

    # Knowledge Graph pillars
    kg = Text("  ")
    if be.kg_pillar_count > 0:
        kg.append(f"✓ {be.kg_pillar_count}/4 KG pillars", style=_COLORS["excellent"])
        pillars = []
        if be.has_wikipedia:
            pillars.append("Wikipedia")
        if be.has_wikidata:
            pillars.append("Wikidata")
        if be.has_linkedin:
            pillars.append("LinkedIn")
        if be.has_crunchbase:
            pillars.append("Crunchbase")
        kg.append(f"  ({', '.join(pillars)})", style=_COLORS["dim"])
    else:
        kg.append("✗ No Knowledge Graph links", style=_COLORS["dim"])
    content_parts.append(kg)

    # About, Contact, Geo
    signals_text = Text("  ")
    items = [
        ("About page", be.has_about_link),
        ("Contact info", be.has_contact_info),
        ("Geo schema", be.has_geo_schema or be.has_hreflang),
    ]
    for label, present in items:
        if present:
            signals_text.append(f"✓ {label}", style=_COLORS["excellent"])
        else:
            signals_text.append(f"✗ {label}", style=_COLORS["dim"])
        signals_text.append("  ", style="default")
    content_parts.append(signals_text)

    # Topic authority: FAQ + articoli recenti
    if be.faq_depth > 0 or be.has_recent_articles:
        topic = Text("  ")
        if be.faq_depth > 0:
            topic.append(f"{be.faq_depth} FAQ", style=f"bold {_COLORS['brand_2']}")
        if be.has_recent_articles:
            if be.faq_depth > 0:
                topic.append("  •  ", style=_COLORS["dim"])
            topic.append("Articles with dateModified", style=_COLORS["dim"])
        content_parts.append(topic)

    color = _score_color(score, max_score)
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]🏢 Brand & Entity[/]",
        title_align="left",
        subtitle=f"[bold {color}]{score}[/][dim]/{max_score}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_cdn_card(result: AuditResult) -> Panel | None:
    """Card per CDN AI Crawler Access."""
    cdn = result.cdn_check
    if not cdn.checked:
        return None

    content_parts = []

    if cdn.cdn_detected:
        header = Text()
        header.append("  CDN: ", style=_COLORS["dim"])
        header.append(cdn.cdn_detected.upper(), style=f"bold {_COLORS['brand_1']}")
        content_parts.append(header)

    # Bot results come tabella compatta
    for bot in cdn.bot_results:
        line = Text("  ")
        if not bot["blocked"] and not bot["challenge_detected"]:
            line.append("✓ ", style=_COLORS["excellent"])
        else:
            line.append("✗ ", style=_COLORS["critical"])
        line.append(f"{bot['bot']}", style="bold")
        line.append(f"  HTTP {bot['status']}", style=_COLORS["dim"])
        if bot["challenge_detected"]:
            line.append("  (challenge)", style=_COLORS["foundation"])
        elif bot["blocked"]:
            line.append("  (blocked)", style=_COLORS["critical"])
        content_parts.append(line)

    color = _COLORS["excellent"] if not cdn.any_blocked else _COLORS["critical"]
    status = "PASS" if not cdn.any_blocked else "BLOCKED"

    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]🛡️  CDN Crawler Access[/]",
        title_align="left",
        subtitle=f"[bold {color}]{status}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_js_card(result: AuditResult) -> Panel | None:
    """Card per JS Rendering Check."""
    js = result.js_rendering
    if not js.checked:
        return None

    content_parts = []

    metrics = Text()
    metrics.append(f"  {js.raw_word_count:,}", style=f"bold {_COLORS['brand_2']}")
    metrics.append(" parole in HTML", style=_COLORS["dim"])
    metrics.append(f"  •  {js.raw_heading_count}", style=f"bold {_COLORS['brand_2']}")
    metrics.append(" headings", style=_COLORS["dim"])
    content_parts.append(metrics)

    if js.framework_detected:
        fw = Text()
        fw.append("  Framework: ", style=_COLORS["dim"])
        fw.append(js.framework_detected, style=f"bold {_COLORS['accent']}")
        content_parts.append(fw)

    if js.has_empty_root:
        content_parts.append(Text("  ⚠ Container SPA vuoto rilevato", style=_COLORS["foundation"]))
    if js.has_noscript_content:
        content_parts.append(Text("  ℹ Fallback <noscript> presente", style=_COLORS["dim"]))

    color = _COLORS["excellent"] if not js.js_dependent else _COLORS["critical"]
    status = "PASS" if not js.js_dependent else "JS-DEPENDENT"

    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]⚙️  JS Rendering[/]",
        title_align="left",
        subtitle=f"[bold {color}]{status}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_webmcp_card(result: AuditResult) -> Panel | None:
    """Card per WebMCP Readiness Check (#233)."""
    wm = result.webmcp
    if not wm.checked:
        return None

    content_parts = []

    # Badge readiness level
    level_colors = {
        "advanced": _COLORS["excellent"],
        "ready": _COLORS["good"],
        "basic": _COLORS["foundation"],
        "none": _COLORS["dim"],
    }
    level_icons = {
        "advanced": "🚀",
        "ready": "✅",
        "basic": "⚡",
        "none": "—",
    }
    level_color = level_colors.get(wm.readiness_level, _COLORS["dim"])
    level_icon = level_icons.get(wm.readiness_level, "—")

    header = Text()
    header.append(f"  {level_icon} ", style="default")
    header.append(wm.readiness_level.upper(), style=f"bold {level_color}")
    content_parts.append(header)
    content_parts.append(Text())

    # Segnali WebMCP nativi
    webmcp_items = [
        ("registerTool() API", wm.has_register_tool),
        ("toolname attributes", wm.has_tool_attributes),
    ]
    for label, present in webmcp_items:
        line = Text("  ")
        if present:
            line.append(f"✓ {label}", style=_COLORS["excellent"])
            if label == "toolname attributes" and wm.tool_count:
                line.append(f" ({wm.tool_count})", style=_COLORS["dim"])
        else:
            line.append(f"✗ {label}", style=_COLORS["dim"])
        content_parts.append(line)

    # Segnali agent-readiness
    agent_items = [
        ("potentialAction", wm.has_potential_action),
        ("Labeled forms", wm.has_labeled_forms),
        ("OpenAPI spec", wm.has_openapi),
    ]
    for label, present in agent_items:
        line = Text("  ")
        if present:
            line.append(f"✓ {label}", style=_COLORS["excellent"])
            if label == "potentialAction" and wm.potential_actions:
                line.append(f" ({', '.join(wm.potential_actions[:3])})", style=_COLORS["dim"])
            elif label == "Labeled forms" and wm.labeled_forms_count:
                line.append(f" ({wm.labeled_forms_count})", style=_COLORS["dim"])
        else:
            line.append(f"✗ {label}", style=_COLORS["dim"])
        content_parts.append(line)

    color = level_color
    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]🤖 WebMCP Readiness[/]",
        title_align="left",
        subtitle=f"[bold {color}]{wm.readiness_level.upper()}[/]",
        subtitle_align="right",
        border_style=color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


def _build_negative_signals_card(result: AuditResult) -> Panel | None:
    """Card per Negative Signals Detection (v4.3)."""
    ns = result.negative_signals
    if not ns.checked:
        return None

    content_parts = []

    # Badge severity
    sev_colors = {
        "clean": _COLORS["excellent"],
        "low": _COLORS["foundation"],
        "medium": _COLORS["foundation"],
        "high": _COLORS["critical"],
    }
    sev_icons = {"clean": "✅", "low": "⚡", "medium": "⚠️", "high": "🚨"}
    sev_color = sev_colors.get(ns.severity, _COLORS["dim"])

    header = Text()
    header.append(f"  {sev_icons.get(ns.severity, '—')} ", style="default")
    header.append(
        f"{ns.signals_found} negative signal{'s' if ns.signals_found != 1 else ''}",
        style=f"bold {sev_color}",
    )
    content_parts.append(header)
    content_parts.append(Text())

    # Dettagli per ogni segnale
    checks = [
        ("CTA overload", ns.cta_density_high, f"{ns.cta_count} CTAs" if ns.cta_count else ""),
        (
            "Popup/modal",
            ns.has_popup_signals,
            ", ".join(ns.popup_indicators[:3]) if ns.popup_indicators else "",
        ),
        ("Thin content", ns.is_thin_content, ""),
        (
            "Broken links",
            ns.has_broken_links,
            f"{ns.broken_links_count} empty hrefs" if ns.broken_links_count else "",
        ),
        (
            "Keyword stuffing",
            ns.has_keyword_stuffing,
            f"'{ns.stuffed_word}' {ns.stuffed_density}%" if ns.stuffed_word else "",
        ),
        ("Author signal", ns.has_author_signal, ""),  # invertito: True = buono
        (
            "Boilerplate",
            ns.boilerplate_high,
            f"{int(ns.boilerplate_ratio * 100)}%" if ns.boilerplate_ratio else "",
        ),
        ("Mixed signals", ns.has_mixed_signals, ns.mixed_signal_detail),
    ]

    for label, is_negative, detail in checks:
        line = Text("  ")
        if label == "Author signal":
            # Invertito: has_author = buono
            if is_negative:
                line.append(f"✓ {label}", style=_COLORS["excellent"])
            else:
                line.append(f"✗ No {label.lower()}", style=_COLORS["critical"])
        else:
            if is_negative:
                line.append(f"✗ {label}", style=_COLORS["critical"])
                if detail:
                    line.append(f"  ({detail})", style=_COLORS["dim"])
            else:
                line.append(f"✓ {label}", style=_COLORS["excellent"])
        content_parts.append(line)

    t = Table(show_header=False, box=None, expand=True, padding=0)
    t.add_column(ratio=1)
    for part in content_parts:
        t.add_row(part)

    return Panel(
        t,
        title="[bold]⚠️  Negative Signals[/]",
        title_align="left",
        subtitle=f"[bold {sev_color}]{ns.severity.upper()}[/]",
        subtitle_align="right",
        border_style=sev_color,
        box=box.ROUNDED,
        padding=(1, 2),
    )


# ── Main formatter ────────────────────────────────────────────────────────────


def format_audit_rich(result: AuditResult) -> str:
    """Formatta AuditResult con design dashboard immersivo.

    Layout:
    1. Header branding con logo gradient
    2. Info panel con URL e HTTP status
    3. Score gauge gigante con numero ASCII art
    4. Barra stacked breakdown categorie
    5. Check card dettagliate (7 categorie)
    6. Card opzionali (CDN, JS Rendering)
    7. Raccomandazioni con priorità
    8. Footer motivazionale

    Ritorna stringa con codici ANSI per output terminale colorato.
    """
    from geo_optimizer import __version__

    _no_color = "NO_COLOR" in os.environ
    buf = io.StringIO()
    console = Console(file=buf, width=80, force_terminal=True, no_color=_no_color)

    # ── 1. Header branding ───────────────────────────────────────
    console.print()
    for line_text, color in _LOGO_LINES:
        console.print(Align.center(Text(line_text, style=f"bold {color}")))
    console.print(Align.center(Text("O P T I M I Z E R", style=f"bold {_COLORS['dim']}")))
    console.print()

    # ── 2. Info panel ────────────────────────────────────────────
    urlparse(result.url).hostname or result.url
    info = Text()
    info.append("  🌐  ", style="default")
    info.append(result.url, style=f"bold {_COLORS['brand_2']} underline")
    info.append("\n  ⚡  ", style="default")
    info.append(f"HTTP {result.http_status}", style="bold")
    info.append(f"  •  {result.page_size:,} bytes", style=_COLORS["dim"])

    console.print(
        Panel(
            info,
            box=box.ROUNDED,
            border_style=_COLORS["brand_1"],
            subtitle=f"[{_COLORS['dim']}]v{__version__}[/]",
            subtitle_align="right",
            padding=(0, 1),
        )
    )

    # ── 3. Score gauge gigante ───────────────────────────────────
    main_color = _band_color(result.band)
    band_cfg = _BAND_CONFIG.get(result.band, _BAND_CONFIG["critical"])

    console.print()

    # Numero grande ASCII art
    big_lines = _render_big_number(result.score, main_color)
    for line in big_lines:
        # Aggiungi " / 100" accanto alla riga centrale
        console.print(Align.center(line))

    # Sottotitolo score
    score_sub = Text()
    score_sub.append("/ 100", style=f"bold {_COLORS['dim']}")
    console.print(Align.center(score_sub))
    console.print()

    # Barra score principale (gradient)
    main_width = 60
    main_filled = int(result.score * main_width / 100)
    main_empty = main_width - main_filled
    main_bar = Text()
    main_bar.append("█" * main_filled, style=f"bold {main_color}")
    main_bar.append("░" * main_empty, style=_COLORS["dim"])
    console.print(Align.center(main_bar))

    # Band label con icona e descrizione
    band_text = Text()
    band_text.append(f"{band_cfg['icon']}  ", style="default")
    band_text.append(band_cfg["label"], style=f"bold {main_color}")
    band_text.append(f"  —  {band_cfg['desc']}", style=_COLORS["dim"])
    console.print(Align.center(band_text))
    console.print()

    # ── 4. Breakdown stacked bar ─────────────────────────────────
    r_score = _robots_score(result)
    l_score = _llms_score(result)
    s_score = _schema_score(result)
    m_score = _meta_score(result)
    c_score = _content_score(result)
    sig_score = _signals_score(result)
    be_score = _brand_entity_score(result)
    from geo_optimizer.core.scoring import _score_ai_discovery

    ai_score = _score_ai_discovery(result.ai_discovery) if result.ai_discovery else 0

    categories = [
        ("Robots", r_score, 18),
        ("llms.txt", l_score, 18),
        ("Schema", s_score, 16),
        ("Meta", m_score, 14),
        ("Content", c_score, 12),
        ("Signals", sig_score, 6),
        ("AI Disc.", ai_score, 6),
        ("Brand", be_score, 10),
    ]

    stacked = _render_stacked_bar(categories, width=68)
    legend = _render_legend(categories)

    breakdown_content = Table(show_header=False, box=None, expand=True, padding=0)
    breakdown_content.add_column(ratio=1)
    breakdown_content.add_row(Align.center(stacked))
    breakdown_content.add_row(Text())
    breakdown_content.add_row(Align.center(legend))

    console.print(
        Panel(
            breakdown_content,
            title="[bold]📊 Score Breakdown[/]",
            title_align="left",
            border_style=_COLORS["brand_1"],
            box=box.ROUNDED,
            padding=(1, 2),
        )
    )

    # ── 5. Check card dettagliate ────────────────────────────────
    console.print()
    console.print(_build_robots_card(result, r_score, 18))
    console.print(_build_llms_card(result, l_score, 18))
    console.print(_build_schema_card(result, s_score, 16))
    console.print(_build_meta_card(result, m_score, 14))
    console.print(_build_content_card(result, c_score, 12))
    console.print(_build_signals_card(result, sig_score, 6))
    console.print(_build_ai_discovery_card(result))
    console.print(_build_brand_entity_card(result, be_score, 10))

    # ── 6. Card opzionali ────────────────────────────────────────
    cdn_card = _build_cdn_card(result)
    if cdn_card:
        console.print(cdn_card)

    js_card = _build_js_card(result)
    if js_card:
        console.print(js_card)

    webmcp_card = _build_webmcp_card(result)
    if webmcp_card:
        console.print(webmcp_card)

    neg_card = _build_negative_signals_card(result)
    if neg_card:
        console.print(neg_card)

    # ── 7. Raccomandazioni ───────────────────────────────────────
    if result.recommendations:
        rec_parts = []
        for i, rec in enumerate(result.recommendations, 1):
            rec_line = Text()
            rec_line.append(f"  {i}. ", style=f"bold {_COLORS['foundation']}")
            rec_line.append(rec, style="default")
            rec_parts.append(rec_line)

        rec_table = Table(show_header=False, box=None, expand=True, padding=0)
        rec_table.add_column(ratio=1)
        for part in rec_parts:
            rec_table.add_row(part)

        console.print()
        console.print(
            Panel(
                rec_table,
                title="[bold]💡 Raccomandazioni[/]",
                title_align="left",
                border_style=_COLORS["foundation"],
                box=box.ROUNDED,
                padding=(1, 2),
            )
        )

    # ── 8. Footer ────────────────────────────────────────────────
    console.print()
    footer = Text()
    footer.append("  GEO Optimizer", style=f"bold {_COLORS['brand_1']}")
    footer.append(f"  v{__version__}", style=_COLORS["dim"])
    footer.append("  •  ", style=_COLORS["dim"])
    footer.append("github.com/Auriti-Labs/geo-optimizer-skill", style=f"{_COLORS['dim']} underline")
    console.print(Align.center(footer))

    # Messaggio motivazionale basato sulla banda
    console.print()
    motiv_messages = {
        "excellent": "Il tuo sito è pronto per i motori AI. Continua così! 🚀",
        "good": "Buon lavoro! Pochi ritocchi per raggiungere l'eccellenza.",
        "foundation": "Le basi ci sono. Segui le raccomandazioni per scalare.",
        "critical": "Inizia dalle raccomandazioni — ogni punto conta.",
    }
    motiv = motiv_messages.get(result.band, "")
    if motiv:
        console.print(Align.center(Text(motiv, style=f"italic {_COLORS['dim']}")))

    console.print()
    return buf.getvalue()
