# Copyright (c) CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com

"""Healthcheck display module for connection health status visualization.

This module provides a provider-agnostic UI for displaying connection healthcheck
results. It supports AWS today and is designed to accommodate future cloud providers
(Azure, GCP, etc.) with minimal changes.
"""

from datetime import datetime
from typing import Any

from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text

from src.utils.connections import build_cur_s3_path

console = Console()

# =============================================================================
# Constants - Provider-Agnostic Design
# =============================================================================

# Status styles: (icon, color)
STATUS_STYLES: dict[str, tuple[str, str]] = {
    "healthy": ("OK", "green"),
    "degraded": ("WARN", "yellow"),
    "unhealthy": ("FAIL", "red"),
    "warning": ("WARN", "yellow"),
    "unknown": ("?", "dim"),
}

# AWS service categories for permission grouping
AWS_SERVICE_CATEGORIES: dict[str, str | list[str]] = {
    "S3": "s3:",
    "Cost Explorer": "ce:",
    "CUR": "cur:",
    "Organizations": "organizations:",
    "CloudWatch": "cloudwatch:",
    "IAM": "iam:",
    "EC2": "ec2:",
    "STS": "sts:",
    "Billing": ["budgets:", "aws-portal:", "billing:"],
}


# =============================================================================
# Helper Functions
# =============================================================================


def get_status_indicator(status: str) -> tuple[str, str]:
    """Get status indicator text and color for a given status.

    Args:
        status: Health status string (healthy, degraded, unhealthy, etc.)

    Returns:
        Tuple of (indicator_text, color_style)
    """
    status_lower = status.lower() if status else "unknown"
    return STATUS_STYLES.get(status_lower, STATUS_STYLES["unknown"])


def get_status_icon(status: str) -> tuple[str, str]:
    """Get emoji icon and color for a status (for compact displays).

    Args:
        status: Health status string

    Returns:
        Tuple of (emoji_icon, color_style)
    """
    status_lower = status.lower() if status else "unknown"
    icons = {
        "healthy": ("✓", "green"),
        "degraded": ("!", "yellow"),
        "unhealthy": ("✗", "red"),
        "warning": ("!", "yellow"),
        "unknown": ("?", "dim"),
    }
    return icons.get(status_lower, icons["unknown"])


def get_service_categories(provider: str) -> dict[str, str | list[str]]:
    """Get service categories for permission grouping based on provider.

    Args:
        provider: Cloud provider name (currently aws only)

    Returns:
        Dictionary mapping service names to permission prefixes
    """
    return AWS_SERVICE_CATEGORIES


def categorize_permissions(permissions: list[str], provider: str = "aws") -> dict[str, list[str]]:
    """Group permissions by service category.

    Args:
        permissions: List of permission strings
        provider: Cloud provider for category mapping

    Returns:
        Dictionary mapping service names to lists of permissions
    """
    categories = get_service_categories(provider)
    result: dict[str, list[str]] = {name: [] for name in categories}
    result["Other"] = []

    for perm in permissions:
        if not perm:
            continue
        perm_lower = perm.lower()
        categorized = False

        for service_name, prefixes in categories.items():
            if isinstance(prefixes, str):
                prefixes = [prefixes]
            for prefix in prefixes:
                if perm_lower.startswith(prefix.lower()):
                    result[service_name].append(perm)
                    categorized = True
                    break
            if categorized:
                break

        if not categorized:
            result["Other"].append(perm)

    # Remove empty categories
    return {k: v for k, v in result.items() if v}


def get_category_status(
    category_perms: list[str],
    verified: list[str],
    missing_required: list[str],
    missing_optional: list[str],
) -> tuple[str, str]:
    """Determine the status of a permission category.

    Args:
        category_perms: All permissions in this category
        verified: List of verified permissions
        missing_required: List of missing required permissions
        missing_optional: List of missing optional permissions

    Returns:
        Tuple of (status_text, color_style)
    """
    # Check if any required permissions in this category are missing
    category_missing_req = [p for p in category_perms if p in missing_required]
    category_missing_opt = [p for p in category_perms if p in missing_optional]

    if category_missing_req:
        return "FAIL", "red"
    elif category_missing_opt:
        return "WARN", "yellow"
    else:
        return "OK", "green"


def highlight_difference(value: Any, active_value: Any, is_unsupported: bool = False) -> Text:
    """Create text with difference highlighting for comparison tables.

    Args:
        value: The value to display
        active_value: The reference value from active item
        is_unsupported: Whether this CUR is unsupported/incompatible

    Returns:
        Rich Text object with appropriate styling
    """
    str_value = str(value) if value else "-"
    str_active = str(active_value) if active_value else "-"

    text = Text()
    is_different = str_value != str_active and str_value != "-"

    if is_unsupported:
        text.append(str_value, style="red")
        text.append(" !", style="bold red")
    elif is_different:
        text.append(str_value, style="yellow")
        text.append(" *", style="bold yellow")
    else:
        text.append(str_value, style="white")

    return text


def get_billing_data_path(check: dict[str, Any], provider: str = "aws") -> str:
    """Construct the full billing data path from check details.

    Handles both CUR-API-discovered CURs and explicitly-configured CURs
    (where report_name is null and the path comes from cur_data bucket/path).

    Args:
        check: The cur_and_data_collection check dictionary
        provider: Cloud provider name

    Returns:
        Full path string (e.g., s3://bucket/prefix/report/)
    """
    details = check.get("details", {})
    if not isinstance(details, dict):
        return "N/A"

    visible_curs = details.get("visible_curs", [])
    if not isinstance(visible_curs, list):
        return "N/A"

    # Find active CUR
    for cur in visible_curs:
        if isinstance(cur, dict) and cur.get("is_active"):
            raw_config = cur.get("raw_config", {})
            if isinstance(raw_config, dict):
                bucket = raw_config.get("S3Bucket", "")
                prefix = raw_config.get("S3Prefix", "")
                # For explicit configs, don't use the synthetic name as a path component
                is_explicit = raw_config.get("source") == "explicit_configuration"
                name = None if is_explicit else cur.get("name", "")

                if provider.lower() == "aws" and bucket:
                    return build_cur_s3_path(bucket, prefix, name)
    return "N/A"


def format_timestamp(timestamp: str | None) -> str:
    """Format an ISO timestamp to a human-readable string.

    Args:
        timestamp: ISO 8601 timestamp string

    Returns:
        Formatted date/time string or "N/A"
    """
    if not timestamp:
        return "N/A"
    try:
        dt = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
        return dt.strftime("%Y-%m-%d %H:%M UTC")
    except (ValueError, AttributeError):
        return str(timestamp)


def format_timestamp_dual(timestamp: str | None) -> tuple[str, str]:
    """Format an ISO timestamp to both local time and UTC strings.

    Args:
        timestamp: ISO 8601 timestamp string

    Returns:
        Tuple of (local_time_str, utc_time_str) or ("N/A", "N/A")
    """
    if not timestamp:
        return "N/A", "N/A"
    try:
        dt_utc = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
        utc_str = dt_utc.strftime("%Y-%m-%d %H:%M UTC")

        # Convert to local time
        dt_local = dt_utc.astimezone()
        local_str = dt_local.strftime("%Y-%m-%d %H:%M %Z")

        return local_str, utc_str
    except (ValueError, AttributeError):
        return str(timestamp), str(timestamp)


def format_relative_time(timestamp: str | None) -> str:
    """Format a timestamp as relative time (e.g., '2h ago').

    Args:
        timestamp: ISO 8601 timestamp string

    Returns:
        Relative time string or "N/A"
    """
    if not timestamp:
        return "N/A"
    try:
        dt = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
        now = datetime.now(dt.tzinfo)
        delta = now - dt

        hours = delta.total_seconds() / 3600
        if hours < 1:
            minutes = int(delta.total_seconds() / 60)
            return f"{minutes}m ago"
        elif hours < 24:
            return f"{int(hours)}h ago"
        else:
            days = int(hours / 24)
            return f"{days}d ago"
    except (ValueError, AttributeError):
        return str(timestamp)


# =============================================================================
# Panel Creation Functions
# =============================================================================


def create_header_panel(data: dict[str, Any]) -> Panel:
    """Create the header panel with all connection identifiers.

    Shows: Connection ID, Connection Name, Org ID, Org Name, Provider, Types, Status

    Args:
        data: Full healthcheck response data

    Returns:
        Rich Panel with connection header information
    """
    metadata = data.get("metadata", {})
    if not isinstance(metadata, dict):
        metadata = {}

    # Use stable API metadata fields
    conn_id = data.get("connection_id", "N/A")
    conn_name = metadata.get("connection_name") or "N/A"
    org_id = metadata.get("cz_organization_id") or data.get("cz_organization_id", "N/A")
    org_name = metadata.get("cz_organization_name") or data.get("cz_organization_name") or "N/A"
    provider = metadata.get("cloud_provider", "N/A")
    conn_types = metadata.get("connection_types", [])
    types_str = ", ".join(conn_types) if isinstance(conn_types, list) else (str(conn_types) if conn_types else "N/A")

    # Status information
    status = data.get("status", "unknown")
    score = data.get("overall_score", 0)
    if score is None:
        score = 0
    icon, color = get_status_icon(status)

    # Create two-column grid
    table = Table.grid(padding=(0, 2))
    table.add_column(ratio=3)
    table.add_column(ratio=2)

    # Left side - identifiers
    left = Table.grid(padding=0)
    left.add_column(style="cyan", justify="right", width=18)
    left.add_column(style="white", overflow="fold")

    left.add_row("Connection ID:", str(conn_id))
    left.add_row("Connection Name:", str(conn_name))
    left.add_row("Organization ID:", str(org_id)[:36] + ("..." if len(str(org_id)) > 36 else ""))
    left.add_row("Organization:", str(org_name))

    # Right side - provider, types, status, spend, autolink
    right = Table.grid(padding=0)
    right.add_column(style="cyan", justify="right", width=14)
    right.add_column(style="white")

    right.add_row("Provider:", str(provider).upper() if provider else "N/A")
    right.add_row("Types:", types_str)

    # 30-day spend
    spend = metadata.get("last_30_days_billed_spend")
    if spend is not None:
        try:
            spend_float = float(spend)
            spend_text = Text(f"${spend_float:,.2f}", style="green")
            right.add_row("30-Day Spend:", spend_text)
        except (ValueError, TypeError):
            right.add_row("30-Day Spend:", Text(str(spend), style="green"))

    # Auto-link status
    auto_link_enabled = metadata.get("auto_link_enabled", False)
    auto_link = metadata.get("auto_link", {})
    if auto_link_enabled:
        role_name = auto_link.get("role_name", "N/A") if isinstance(auto_link, dict) else "N/A"
        autolink_text = Text()
        autolink_text.append("Enabled", style="green")
        autolink_text.append(f" ({role_name})", style="dim")
        right.add_row("Auto-Link:", autolink_text)
    else:
        right.add_row("Auto-Link:", Text("Disabled", style="dim"))

    right.add_row("", "")

    # Status badge
    status_text = Text()
    status_text.append(f"{icon} ", style=f"bold {color}")
    status_text.append(f"{status.upper()} ", style=f"bold {color}")
    status_text.append(f"({score:.0f}%)", style=color)
    right.add_row("Status:", status_text)

    table.add_row(left, right)

    # Create main container with timestamp footer
    container = Table.grid(padding=0)
    container.add_column()
    container.add_row(table)

    # Add prominent "Last Updated" timestamp at bottom
    last_updated = metadata.get("last_updated")
    if last_updated:
        local_time, utc_time = format_timestamp_dual(last_updated)
        container.add_row(Text(""))  # Spacer
        updated_text = Text()
        updated_text.append("Last Updated: ", style="bold cyan")
        updated_text.append(local_time, style="bold white")
        updated_text.append("  (", style="dim")
        updated_text.append(utc_time, style="dim")
        updated_text.append(")", style="dim")
        container.add_row(updated_text)

    return Panel(container, title="[bold]CONNECTION HEALTHCHECK[/]", border_style=color, title_align="left")


def create_roles_panel(connectivity_check: dict[str, Any], data: dict[str, Any]) -> Panel:
    """Create the active roles panel showing validated role ARNs and billing path.

    Args:
        connectivity_check: The provider_connectivity check dictionary
        data: Full healthcheck response for metadata

    Returns:
        Rich Panel with role ARNs and billing data path
    """
    details = connectivity_check.get("details", {})
    if not isinstance(details, dict):
        details = {}

    metadata = data.get("metadata", {})
    if not isinstance(metadata, dict):
        metadata = {}

    provider = metadata.get("cloud_provider", "aws")
    conn_types = metadata.get("connection_types", [])
    if not isinstance(conn_types, list):
        conn_types = [str(conn_types)] if conn_types else []

    table = Table.grid(padding=0)
    table.add_column(style="cyan", width=16)
    table.add_column(style="white", overflow="fold")

    # Get role information from role_chain
    role_chain = details.get("role_chain", {})
    customer_role = role_chain.get("customer_role_arn", "N/A") if isinstance(role_chain, dict) else "N/A"

    # For AWS, show the customer role ARN
    # Future: differentiate cost vs resource roles if API provides them
    if "COST" in conn_types:
        table.add_row("Cost Role:", Text(str(customer_role), overflow="fold"))
    if "RESOURCE" in conn_types:
        table.add_row("Resource Role:", Text(str(customer_role), overflow="fold"))
    if not conn_types or ("COST" not in conn_types and "RESOURCE" not in conn_types):
        table.add_row("Active Role:", Text(str(customer_role), overflow="fold"))

    # Add billing data path for cost connections
    if "COST" in conn_types:
        # Get billing data path from cur_and_data_collection check
        checks = data.get("checks", [])
        cur_check = {}
        for check in checks:
            if isinstance(check, dict) and check.get("name") == "cur_and_data_collection":
                cur_check = check
                break

        billing_path = get_billing_data_path(cur_check, provider)
        table.add_row("", "")
        table.add_row("Billing Data:", Text(billing_path, style="bold", overflow="fold"))

    status = connectivity_check.get("status", "unknown")
    icon, color = get_status_icon(status)

    return Panel(table, title=f"[{color}]{icon} ACTIVE ROLES[/]", border_style=color, title_align="left")


def create_checks_summary_panel(checks: list[dict[str, Any]]) -> Panel:
    """Create a summary panel showing all healthcheck checks.

    Shows name, status, and message for each check.

    Args:
        checks: List of check dictionaries from healthcheck_result.checks

    Returns:
        Rich Panel with checks summary table
    """
    table = Table(show_header=True, header_style="bold cyan", box=None, padding=(0, 2))
    table.add_column("CHECK", style="white", width=24)
    table.add_column("STATUS", justify="center", width=10)
    table.add_column("MESSAGE", style="dim", overflow="fold")

    overall_status = "healthy"

    for check in checks:
        if not isinstance(check, dict):
            continue

        name = check.get("name", "unknown")
        status = check.get("status", "unknown")
        message = check.get("message", "")

        # Format check name for display
        display_name = name.replace("_", " ").title()

        # Get status indicator
        icon, color = get_status_icon(status)
        status_text = Text()
        status_text.append(f"{icon} ", style=color)
        status_text.append(status.upper(), style=f"bold {color}")

        # Track overall status
        if status.lower() == "unhealthy":
            overall_status = "unhealthy"
        elif status.lower() == "degraded" and overall_status != "unhealthy":
            overall_status = "degraded"

        table.add_row(display_name, status_text, message or "-")

    icon, color = get_status_icon(overall_status)
    return Panel(table, title=f"[{color}]{icon} HEALTHCHECK SUMMARY[/]", border_style=color, title_align="left")


def create_permissions_panel(permissions_check: dict[str, Any], provider: str = "aws") -> Panel:
    """Create the permissions panel with service-based categorization.

    Groups permissions by AWS service and shows OK/WARN/FAIL per category.

    Args:
        permissions_check: The permissions_check dictionary
        provider: Cloud provider for category mapping

    Returns:
        Rich Panel with categorized permissions table
    """
    details = permissions_check.get("details", {})
    if not isinstance(details, dict):
        details = {}

    # Extract permission lists
    required = details.get("required_permissions", [])
    optional = details.get("optional_permissions", [])
    verified = details.get("verified_permissions", [])
    missing_required = details.get("missing_required_permissions", [])
    missing_optional = details.get("missing_optional_permissions", [])

    # Ensure all are lists
    for lst in [required, optional, verified, missing_required, missing_optional]:
        if not isinstance(lst, list):
            lst = []

    all_permissions = list(set(required + optional))
    total_count = len(all_permissions)
    verified_count = len(verified)

    # Categorize all permissions
    categorized = categorize_permissions(all_permissions, provider)
    categorized_verified = categorize_permissions(verified, provider)

    # Create table
    table = Table(show_header=True, header_style="bold cyan", box=None, padding=(0, 2))
    table.add_column("SERVICE", style="white", width=16)
    table.add_column("STATUS", justify="center", width=8)
    table.add_column("PERMISSIONS", style="dim", overflow="fold")

    for service_name, service_perms in sorted(categorized.items()):
        # Determine category status
        status_text, status_color = get_category_status(service_perms, verified, missing_required, missing_optional)

        # Build permissions display
        service_verified = categorized_verified.get(service_name, [])
        service_missing_req = [p for p in service_perms if p in missing_required]
        service_missing_opt = [p for p in service_perms if p in missing_optional]

        perms_text = Text()

        # Show verified permissions (green, truncated)
        if service_verified:
            verified_display = service_verified[:3]
            perms_text.append(", ".join(verified_display), style="green")
            if len(service_verified) > 3:
                perms_text.append(f" +{len(service_verified) - 3}", style="dim green")

        # Show missing required (red)
        if service_missing_req:
            if perms_text:
                perms_text.append(" | ", style="dim")
            perms_text.append("[MISSING: ", style="red")
            perms_text.append(", ".join(service_missing_req[:2]), style="red")
            if len(service_missing_req) > 2:
                perms_text.append(f" +{len(service_missing_req) - 2}", style="dim red")
            perms_text.append("]", style="red")

        # Show missing optional (yellow)
        if service_missing_opt:
            if perms_text:
                perms_text.append(" | ", style="dim")
            perms_text.append("[optional: ", style="yellow")
            perms_text.append(", ".join(service_missing_opt[:2]), style="yellow")
            if len(service_missing_opt) > 2:
                perms_text.append(f" +{len(service_missing_opt) - 2}", style="dim yellow")
            perms_text.append("]", style="yellow")

        status_styled = Text(f"[{status_text}]", style=f"bold {status_color}")
        table.add_row(service_name, status_styled, perms_text)

    status = permissions_check.get("status", "unknown")
    icon, color = get_status_icon(status)
    title = f"[{color}]{icon} PERMISSIONS ({verified_count}/{total_count} verified)[/]"

    return Panel(table, title=title, border_style=color, title_align="left")


def _is_explicit_config(cur: dict[str, Any]) -> bool:
    """Check if a CUR entry is from explicit configuration (not discovered via AWS CUR API).

    Explicitly-configured CURs have bucket/path set directly in the connection rather than
    being discovered via describe_report_definitions. They appear when report_name is null
    in cur_data (e.g., cross-account CUR exports).

    Args:
        cur: A visible_curs entry from the healthcheck response

    Returns:
        True if this CUR was explicitly configured
    """
    raw_config = cur.get("raw_config", {})
    if not isinstance(raw_config, dict):
        return False
    return raw_config.get("source") == "explicit_configuration"


def _cur_display_name(cur: dict[str, Any]) -> str:
    """Get a human-readable display name for a CUR entry.

    For explicitly-configured CURs (report_name=null), derives a name from
    the bucket/path configuration instead of using "explicit_config".

    Args:
        cur: A visible_curs entry from the healthcheck response

    Returns:
        Display name string
    """
    name = cur.get("name")
    if name and name != "explicit_config":
        return name

    # For explicit configs, derive a name from bucket/path
    raw_config = cur.get("raw_config", {})
    if isinstance(raw_config, dict):
        bucket = raw_config.get("S3Bucket", "")
        prefix = raw_config.get("S3Prefix", "")
        if bucket:
            path_label = prefix.strip("/") if prefix else ""
            return f"{bucket}/{path_label}" if path_label else bucket
    return "Explicit Config"


def _is_compatible_cur(cur: dict[str, Any]) -> bool:
    """Whether a CUR belongs in the main billing overview panel.

    Active CURs and explicit-config CURs are always shown. Discovered (CUR API)
    CURs are shown only when healthy/compatible.
    """
    if cur.get("is_active"):
        return True
    if _is_explicit_config(cur):
        return True
    return bool(cur.get("is_healthy"))


def _build_curs_overview_table(curs: list[dict[str, Any]], active_cur: dict[str, Any]) -> Table:
    """Build the horizontal CUR comparison table.

    Args:
        curs: CURs to render as columns (in display order, active first if present)
        active_cur: Reference CUR for comparison highlighting

    Returns:
        Rich Table with FIELD column + one column per CUR
    """
    table = Table(show_header=True, header_style="bold cyan", box=None, padding=(0, 1))
    table.add_column("FIELD", style="cyan", width=16)

    for cur in curs:
        display_name = _cur_display_name(cur)
        is_active = cur.get("is_active", False)
        col_title = f"{display_name} *" if is_active else display_name
        col_style = "on grey0" if is_active else None
        table.add_column(
            col_title, overflow="fold", style=col_style, header_style="bold cyan on grey0" if is_active else "bold cyan"
        )

    def _s3_location(c: dict) -> str:
        raw = c.get("raw_config", {})
        if not isinstance(raw, dict):
            return "-"
        bucket = raw.get("S3Bucket", "")
        prefix = raw.get("S3Prefix")
        if not bucket:
            return "-"
        report_name = None if _is_explicit_config(c) else c.get("name", "")
        return build_cur_s3_path(bucket, prefix, report_name)

    def _cur_api_field(c: dict, field: str, default: str = "-") -> str:
        if _is_explicit_config(c):
            return "N/A"
        return c.get("raw_config", {}).get(field, default)

    def _billing_report_format(c: dict) -> str:
        health_details = c.get("health_details")
        if isinstance(health_details, dict):
            value = health_details.get("billing_report_format")
            if value:
                return value
        cur_format = c.get("raw_config", {}).get("Format") if isinstance(c.get("raw_config"), dict) else None
        if cur_format == "Parquet":
            return "aws_parquet"
        if cur_format == "textORcsv":
            return "aws"
        return "-"

    fields: list[tuple[str, Any]] = [
        ("Status", lambda c: c.get("status", "unknown").upper()),
        ("Source", lambda c: "Explicit" if _is_explicit_config(c) else "CUR API"),
        ("Accessible", lambda c: "YES" if c.get("is_accessible") else "NO"),
        (
            "Compatible",
            lambda c: "N/A" if _is_explicit_config(c) else ("YES" if c.get("is_healthy") else "NO"),
        ),
        ("Format", lambda c: _cur_api_field(c, "Format")),
        ("Billing Format", _billing_report_format),
        ("Time Unit", lambda c: _cur_api_field(c, "TimeUnit")),
        ("Compression", lambda c: _cur_api_field(c, "Compression")),
        ("S3 Bucket", lambda c: c.get("raw_config", {}).get("S3Bucket", "-")),
        ("S3 Prefix", lambda c: c.get("raw_config", {}).get("S3Prefix") or "-"),
        ("S3 Location", _s3_location),
        ("S3 Region", lambda c: _cur_api_field(c, "S3Region")),
        (
            "Schema",
            lambda c: (
                "N/A"
                if _is_explicit_config(c)
                else str(len(c.get("raw_config", {}).get("AdditionalSchemaElements", []))) + " elements"
            ),
        ),
        (
            "Refresh",
            lambda c: (
                "N/A"
                if _is_explicit_config(c)
                else ("Yes" if c.get("raw_config", {}).get("RefreshClosedReports") else "No")
            ),
        ),
        (
            "Versioning",
            lambda c: (
                "N/A"
                if _is_explicit_config(c)
                else ("NEW" if c.get("raw_config", {}).get("ReportVersioning") == "CREATE_NEW_REPORT" else "OVERWRITE")
            ),
        ),
        (
            "Note",
            lambda c: (
                (c.get("health_details", {}).get("note") or c.get("health_details", {}).get("reason") or "-")
                if isinstance(c.get("health_details"), dict)
                else "-"
            ),
        ),
        (
            "Last Drop",
            lambda c: format_relative_time(
                (c.get("cur_stats") or {}).get("cur_drop_datetime") if isinstance(c.get("cur_stats"), dict) else None
            ),
        ),
        (
            "Last Collection",
            lambda c: format_relative_time(
                (c.get("data_collection") or {}).get("last_cur_drop")
                if isinstance(c.get("data_collection"), dict)
                else None
            ),
        ),
        (
            "Files",
            lambda c: (
                str((c.get("data_collection") or {}).get("report_count", 0) or 0)
                if isinstance(c.get("data_collection"), dict)
                else "0"
            ),
        ),
    ]

    color_coded_fields = {"Compatible", "Accessible", "Status"}

    for field_name, get_value in fields:
        row_values = [field_name]
        active_value = get_value(active_cur)

        for cur in curs:
            value = get_value(cur)
            is_unsupported = not cur.get("is_healthy", False) and not _is_explicit_config(cur)

            is_active = cur.get("is_active", False)
            bg = " on grey0" if is_active else ""

            if field_name in color_coded_fields:
                if value == "YES" or value == "HEALTHY":
                    style = f"bold green{bg}" if is_active else "green"
                elif value == "NO" or value == "UNHEALTHY":
                    style = f"bold red{bg}" if is_active else "red"
                elif value == "N/A":
                    style = f"dim{bg}" if is_active else "dim"
                else:
                    style = f"bold yellow{bg}" if is_active else "yellow"
                row_values.append(Text(str(value), style=style))
            elif is_active:
                row_values.append(Text(str(value), style=f"bold white{bg}"))
            else:
                row_values.append(highlight_difference(value, active_value, is_unsupported))

        table.add_row(*row_values)

    return table


def create_billing_overview_panel(cur_check: dict[str, Any]) -> Panel | None:
    """Create the billing data overview panel for the active CUR and any compatible CURs.

    Discovered CURs that are incompatible/unhealthy are excluded — render those
    separately with `create_incompatible_curs_panel`. Explicit-config CURs are
    treated as compatible (compatibility doesn't apply to them).

    Args:
        cur_check: The cur_and_data_collection check dictionary

    Returns:
        Rich Panel, or None if no compatible CURs to show
    """
    details = cur_check.get("details", {})
    if not isinstance(details, dict):
        return None

    visible_curs = details.get("visible_curs", [])
    if not isinstance(visible_curs, list) or len(visible_curs) == 0:
        return None

    compatible_curs = [c for c in visible_curs if isinstance(c, dict) and _is_compatible_cur(c)]
    if len(compatible_curs) == 0:
        return None

    # Sort: active CUR first, then alphabetical
    sorted_curs = sorted(compatible_curs, key=lambda c: (not c.get("is_active", False), c.get("name") or ""))
    active_cur = next((c for c in sorted_curs if c.get("is_active")), sorted_curs[0])

    table = _build_curs_overview_table(sorted_curs, active_cur)

    legend = Text()
    legend.append("* = Active CUR  ", style="dim")
    legend.append("*", style="bold yellow")
    legend.append(" = Differs from active", style="dim")

    combined = Table.grid(padding=0)
    combined.add_column()
    combined.add_row(table)
    combined.add_row(Text(""))
    combined.add_row(legend)

    total_curs = details.get("total_curs_found", len(visible_curs))
    healthy_curs = sum(1 for c in visible_curs if c.get("status", "").lower() == "healthy")

    check_status = cur_check.get("status", "unknown")
    check_icon, check_color = get_status_icon(check_status)

    return Panel(
        combined,
        title=f"[{check_color}]{check_icon} BILLING DATA OVERVIEW ({healthy_curs}/{total_curs} healthy)[/]",
        border_style=check_color,
        title_align="left",
    )


def create_incompatible_curs_panel(cur_check: dict[str, Any]) -> Panel | None:
    """Create a panel listing discovered CURs that are incompatible/unhealthy.

    Returned only when there is at least one such CUR. Active CUR is used solely
    as a comparison reference for difference highlighting.

    Args:
        cur_check: The cur_and_data_collection check dictionary

    Returns:
        Rich Panel of incompatible CURs, or None if there are none
    """
    details = cur_check.get("details", {})
    if not isinstance(details, dict):
        return None

    visible_curs = details.get("visible_curs", [])
    if not isinstance(visible_curs, list) or len(visible_curs) == 0:
        return None

    incompatible = [c for c in visible_curs if isinstance(c, dict) and not _is_compatible_cur(c)]
    if len(incompatible) == 0:
        return None

    sorted_incompatible = sorted(incompatible, key=lambda c: c.get("name") or "")

    # Use the global active CUR (if any) as the comparison reference
    active_cur = next(
        (c for c in visible_curs if isinstance(c, dict) and c.get("is_active")),
        sorted_incompatible[0],
    )

    table = _build_curs_overview_table(sorted_incompatible, active_cur)

    legend = Text()
    legend.append("!", style="bold red")
    legend.append(" = Not supported  ", style="dim")
    legend.append("*", style="bold yellow")
    legend.append(" = Differs from active CUR", style="dim")

    combined = Table.grid(padding=0)
    combined.add_column()
    combined.add_row(table)
    combined.add_row(Text(""))
    combined.add_row(legend)

    return Panel(
        combined,
        title=f"[red]✗ INCOMPATIBLE CURS ({len(sorted_incompatible)})[/]",
        border_style="red",
        title_align="left",
    )


def create_connectivity_issues_panel(connectivity_check: dict[str, Any]) -> Panel | None:
    """Create the connectivity issues panel (only shown when problems exist).

    Shows role chain details and error information when connectivity fails.

    Args:
        connectivity_check: The provider_connectivity check dictionary

    Returns:
        Rich Panel with error details, or None if no issues
    """
    status = connectivity_check.get("status", "unknown")
    if status.lower() == "healthy":
        return None

    details = connectivity_check.get("details", {})
    if not isinstance(details, dict):
        details = {}

    message = connectivity_check.get("message", "")

    table = Table.grid(padding=0)
    table.add_column(style="red", overflow="fold")

    # Show warning/error message
    if message:
        table.add_row(Text(f"WARNING: {message}", style="bold red"))
        table.add_row(Text(""))

    # Show role chain details
    role_chain = details.get("role_chain", {})
    if isinstance(role_chain, dict):
        initial = role_chain.get("initial_account", "?")
        reactor = role_chain.get("reactor_account", "?")
        customer = role_chain.get("customer_account", "?")

        chain_text = Text("Chain: ")
        chain_text.append(str(initial), style="dim")
        chain_text.append(" -> ", style="dim")
        chain_text.append(str(reactor), style="dim")
        chain_text.append(" -> ", style="dim")

        if status.lower() in ["unhealthy", "degraded"]:
            chain_text.append(f"[FAILED: {customer}]", style="bold red")
        else:
            chain_text.append(str(customer), style="dim")

        table.add_row(chain_text)

        # Show customer role ARN
        customer_role = role_chain.get("customer_role_arn")
        if customer_role:
            table.add_row(Text(f"Role: {customer_role}", style="dim", overflow="fold"))

    icon, color = get_status_icon(status)
    return Panel(table, title=f"[{color}]{icon} CONNECTIVITY ISSUES[/]", border_style=color, title_align="left")


# =============================================================================
# Main Display Function
# =============================================================================


def display_healthcheck(data: dict[str, Any], connection: dict[str, Any] | None = None) -> None:
    """Display healthcheck results in the new panel layout.

    Panel order (priority):
    1. Header - Connection identifiers and status
    2. Active Roles - Role ARNs and billing data path
    3. Permissions - Service-categorized permissions
    4. Billing Config - Active billing data details (cost connections)
    5. Billing Comparison - Side-by-side CUR comparison (if multiple)
    6. Connectivity Issues - Only shown when problems detected

    Args:
        data: Full healthcheck response data
        connection: Optional connection data with org/account info
    """
    console.print()

    # Get all checks
    checks_list = data.get("checks", [])
    checks: dict[str, dict] = {}
    for check in checks_list:
        if isinstance(check, dict) and "name" in check:
            checks[check["name"]] = check

    # Metadata comes directly from API response
    metadata = data.get("metadata")
    if not isinstance(metadata, dict):
        metadata = {}
        data["metadata"] = metadata

    # Enrich metadata with connection data for fields the healthcheck API doesn't provide
    if connection:
        # Organization info - healthcheck metadata often lacks this
        if not metadata.get("cz_organization_id"):
            metadata["cz_organization_id"] = connection.get("cz_organization_id")
            data["cz_organization_id"] = connection.get("cz_organization_id")
        if not metadata.get("cz_organization_name"):
            metadata["cz_organization_name"] = connection.get("cz_organization_name")
            data["cz_organization_name"] = connection.get("cz_organization_name")
        # Connection name fallback
        if not metadata.get("connection_name") and not metadata.get("account_name"):
            metadata["connection_name"] = connection.get("connection_name")
        # Provider fallback
        if not metadata.get("cloud_provider"):
            metadata["cloud_provider"] = connection.get("provider") or connection.get("cloud_provider", "aws")

    provider = metadata.get("cloud_provider", "aws")
    conn_types = metadata.get("connection_types", [])
    if not isinstance(conn_types, list):
        conn_types = [conn_types] if conn_types else []

    # 1. Header Panel (always shown)
    console.print(create_header_panel(data))
    console.print()

    # 2. Checks Summary Panel (always shown)
    if checks_list:
        console.print(create_checks_summary_panel(checks_list))
        console.print()

    # 3. Active Roles Panel (always shown)
    connectivity_check = checks.get("provider_connectivity", {})
    console.print(create_roles_panel(connectivity_check, data))
    console.print()

    # 4. Permissions Panel (always shown)
    permissions_check = checks.get("permissions_check", {})
    console.print(create_permissions_panel(permissions_check, provider))
    console.print()

    # 5. Billing Data Overview Panel (cost connections only)
    cur_check = checks.get("cur_and_data_collection", {})
    if "COST" in conn_types:
        billing_panel = create_billing_overview_panel(cur_check)
        if billing_panel:
            console.print(billing_panel)
            console.print()

        incompatible_panel = create_incompatible_curs_panel(cur_check)
        if incompatible_panel:
            console.print(incompatible_panel)
            console.print()

    # 7. Connectivity Issues Panel (only if problems)
    issues_panel = create_connectivity_issues_panel(connectivity_check)
    if issues_panel:
        console.print(issues_panel)
        console.print()
