"""Rendering functions for selftest command output."""

from __future__ import annotations

import json
from collections.abc import Mapping, Sequence
from typing import Any

from rich import box
from rich.console import Console
from rich.table import Table


class _RichStyles:
    """Rich console style constants."""

    ACCENT = "bold cyan"
    SECONDARY = "magenta"
    SUCCESS = "green"
    EMPHASIS = "bold"
    DETAIL = "white"


def _healthcheck_status_label(value: str | None) -> str:
    """Convert status value to uppercase label."""
    mapping = {"pass": "PASS", "fail": "FAIL", "warning": "WARNING"}
    if not value:
        return "WARNING"
    return mapping.get(value.lower(), value.upper())


def _stringify_healthcheck_detail(value: Any) -> str:
    """Convert any value to a string representation for healthcheck display."""
    if value is None:
        return "-"
    if isinstance(value, str):
        return value
    if isinstance(value, Mapping):
        items = [f"{key}={value[key]}" for key in sorted(value)]
        return ", ".join(items) if items else "-"
    if isinstance(value, Sequence) and not isinstance(value, str | bytes):
        items = [_stringify_healthcheck_detail(item) for item in value]
        return ", ".join(item for item in items if item and item != "-") or "-"
    return str(value)


def _format_healthcheck_context_detail(context_data: Mapping[str, Any]) -> str:
    """Format context diagnostic details into a summary string."""
    parts: list[str] = []
    if context_data.get("fallback_attempted"):
        resolved = context_data.get("fallback_success")
        parts.append("fallback=" + ("resolved" if resolved else "failed"))
    recoverable = context_data.get("recoverable_categories") or []
    if recoverable:
        parts.append("recoverable=" + ",".join(sorted(recoverable)))
    unrecoverable = context_data.get("unrecoverable_categories") or []
    if unrecoverable:
        parts.append("unrecoverable=" + ",".join(sorted(unrecoverable)))
    notes = context_data.get("notes") or []
    if notes:
        parts.append("notes=" + ",".join(notes))
    return "; ".join(parts) if parts else "-"


def _format_healthcheck_online_detail(online_data: Mapping[str, Any]) -> str:
    """Format online diagnostic details into a summary string."""
    attempts = online_data.get("attempts") if isinstance(online_data, Mapping) else None
    if isinstance(attempts, Mapping) and attempts:
        attempt_parts = [
            f"{label}:{_healthcheck_status_label(status)}"
            for label, status in sorted(attempts.items())
        ]
        return ", ".join(attempt_parts)
    details = online_data.get("details") if isinstance(online_data, Mapping) else None
    return _stringify_healthcheck_detail(details)


def _process_tool_attempt_entry(
    label: str,
    entry: Mapping[str, Any],
    parts: list[str],
) -> str:
    """Process a single tool attempt entry and return its status label."""
    attempt_status = _healthcheck_status_label(entry.get("status"))

    modes = entry.get("modes")
    if isinstance(modes, Mapping) and modes:
        mode_parts = [
            f"{mode}:{_healthcheck_status_label(mode_entry.get('status'))}"
            for mode, mode_entry in sorted(modes.items())
        ]
        if mode_parts:
            parts.append(f"{label} modes=" + ", ".join(mode_parts))

    detail = entry.get("details")
    if detail:
        parts.append(f"{label} detail=" + _stringify_healthcheck_detail(detail))

    return f"{label}:{attempt_status}"


def _format_healthcheck_tool_detail(tool_summary: Mapping[str, Any]) -> str:
    """Format tool diagnostic details into a summary string."""
    parts: list[str] = []
    attempts = tool_summary.get("attempts")
    if isinstance(attempts, Mapping) and attempts:
        attempt_parts = []
        for label, entry in sorted(attempts.items()):
            attempt_label = _process_tool_attempt_entry(label, entry, parts)
            attempt_parts.append(attempt_label)
        if attempt_parts:
            parts.insert(0, "attempts=" + ", ".join(attempt_parts))

    details = tool_summary.get("details")
    if details:
        parts.append(_stringify_healthcheck_detail(details))

    return "; ".join(parts) if parts else "-"


def _create_healthcheck_table() -> Table:
    """Create the healthcheck summary table with columns."""
    table = Table(title="Healthcheck Summary", box=box.SIMPLE_HEAVY)
    table.add_column("Check", style=_RichStyles.ACCENT)
    table.add_column("Context", style=_RichStyles.SECONDARY)
    table.add_column("Tool", style=_RichStyles.SUCCESS)
    table.add_column("Status", style=_RichStyles.EMPHASIS)
    table.add_column("Details", style=_RichStyles.DETAIL)
    return table


def _add_healthcheck_offline_row(table: Table, report: dict[str, Any]) -> None:
    """Add the offline check row to the healthcheck table."""
    offline_entry = report.get("offline_check", {})
    offline_status = _healthcheck_status_label(offline_entry.get("status"))
    offline_detail = _stringify_healthcheck_detail(offline_entry.get("details"))
    table.add_row("Offline checks", "-", "-", offline_status, offline_detail)


def _determine_context_status(context_data: Mapping[str, Any]) -> str:
    """Determine the status label for a context."""
    context_success = context_data.get("success")
    offline_mode = context_data.get("offline_mode")
    if offline_mode and context_success:
        return "warning"
    elif context_success:
        return "pass"
    else:
        return "fail"


def _add_healthcheck_context_rows(
    table: Table,
    context_name: str,
    context_data: Mapping[str, Any],
) -> None:
    """Add context, online, and tool rows for a single context."""
    context_status = _determine_context_status(context_data)
    context_detail = _format_healthcheck_context_detail(context_data)
    context_status_label = _healthcheck_status_label(context_status)
    table.add_row("Context", context_name, "-", context_status_label, context_detail)

    online_summary = context_data.get("online", {})
    online_status_label = _healthcheck_status_label(online_summary.get("status"))
    online_detail = _format_healthcheck_online_detail(online_summary)
    table.add_row("Online", context_name, "-", online_status_label, online_detail or "-")

    tools = context_data.get("tools", {})
    for tool_name, tool_summary in sorted(tools.items()):
        tool_status_label = _healthcheck_status_label(tool_summary.get("status"))
        detail_text = _format_healthcheck_tool_detail(tool_summary)
        table.add_row("Tool", context_name, tool_name, tool_status_label, detail_text)


def _collect_healthcheck_critical_failures(
    context_name: str,
    context_data: Mapping[str, Any],
) -> list[str]:
    """Collect critical failure messages for a context."""
    failures: list[str] = []
    context_status = _determine_context_status(context_data)
    context_status_label = _healthcheck_status_label(context_status)

    if context_status_label == "FAIL":
        failures.append(f"{context_name}: context failure")

    unrecoverable = context_data.get("unrecoverable_categories") or []
    if unrecoverable:
        failures.append(f"{context_name}: unrecoverable={','.join(sorted(unrecoverable))}")

    return failures


def render_healthcheck_summary(report: dict[str, Any], stdout_console: Console) -> None:
    """Render a comprehensive healthcheck summary table and JSON report."""
    table = _create_healthcheck_table()
    _add_healthcheck_offline_row(table, report)

    critical_failures: list[str] = []
    for context_name, context_data in sorted(report.get("contexts", {}).items()):
        _add_healthcheck_context_rows(table, context_name, context_data)
        critical_failures.extend(_collect_healthcheck_critical_failures(context_name, context_data))

    if critical_failures:
        table.add_row(
            "Critical failures",
            "-",
            "-",
            "FAIL",
            "; ".join(critical_failures),
        )

    stdout_console.print()
    stdout_console.print("Machine-readable summary:")
    stdout_console.print(json.dumps(report, indent=2, separators=(",", ": "), sort_keys=True))
    stdout_console.print()
    stdout_console.print(table)
