"""Centralized error handling for Hikaflow CLI.

Provides actionable error messages that tell users what to DO,
not just what went WRONG.
"""

from __future__ import annotations

import functools
import json
import logging
from typing import Callable

import typer
from rich.console import Console

console = Console()
logger = logging.getLogger("hikaflow")

# Map common error conditions to actionable remediation messages
_REMEDIATION = {
    "ConnectionError": (
        "Cannot connect to the Hikaflow API.",
        "Check your network connection and run: hikaflow doctor",
    ),
    # ConnectError (httpx) inherits from ConnectionError, handled via MRO fallback
    "TimeoutError": (
        "Request to Hikaflow API timed out.",
        "Check your connection or try again. Run: hikaflow doctor",
    ),
    "FileNotFoundError": (
        "File not found.",
        "Check the file path exists and is readable.",
    ),
    "JSONDecodeError": (
        "Invalid JSON data.",
        "The file may be corrupted. Try re-capturing or re-downloading.",
    ),
    "PermissionError": (
        "Permission denied.",
        "Check file permissions. Credentials file should be owner-readable only (chmod 600).",
    ),
}

_HTTP_REMEDIATION = {
    400: (
        "Invalid request.",
        "Check your input parameters. Run: hikaflow doctor",
    ),
    401: (
        "Authentication expired or invalid.",
        "Run: hikaflow login",
    ),
    403: (
        "Permission denied for this resource.",
        "Check your project access with: hikaflow whoami",
    ),
    404: (
        "Resource not found.",
        "Verify the ID is correct and the resource exists.",
    ),
    409: (
        "Resource conflict.",
        "The resource may already exist or was modified concurrently. Refresh and retry.",
    ),
    413: (
        "Payload too large.",
        "Reduce the size of your request (e.g., fewer files, smaller session chunks).",
    ),
    422: (
        "Validation error.",
        "Check your input format. The API rejected the request data. Run: hikaflow doctor",
    ),
    429: (
        "Rate limit exceeded.",
        "Wait a moment and try again.",
    ),
    500: (
        "Hikaflow API internal error.",
        "Try again in a few seconds. If persistent, check https://status.hikaflow.com",
    ),
    502: (
        "Hikaflow API is temporarily unavailable.",
        "Try again in a few seconds.",
    ),
    503: (
        "Hikaflow API is under maintenance.",
        "Try again in a few minutes.",
    ),
    504: (
        "Hikaflow API gateway timeout.",
        "The server took too long to respond. Try again in a few seconds.",
    ),
}


def handle_cli_errors(func: Callable) -> Callable:
    """Decorator that wraps CLI commands with actionable error handling.

    Catches common exceptions and displays user-friendly error messages
    with remediation steps.

    Usage:
        @app.command()
        @handle_cli_errors
        def my_command():
            ...
    """

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except KeyboardInterrupt:
            console.print("\n[dim]Interrupted.[/]")
            raise typer.Exit(130)
        except SystemExit:
            raise
        except typer.Exit:
            raise
        except Exception as e:
            # Check if JSON mode is active via typer context
            json_mode = False
            for a in args:
                ctx = getattr(a, "obj", None) if isinstance(a, typer.Context) else None
                if ctx and isinstance(ctx, dict):
                    json_mode = ctx.get("json_mode", False)
                    break
            _handle_exception(e, json_mode=json_mode)
            raise typer.Exit(1)

    return wrapper


def _handle_exception(exc: Exception, *, json_mode: bool = False) -> None:
    """Display a user-friendly error message for the given exception."""
    exc_type = type(exc).__name__
    logger.debug("Handling %s: %s", exc_type, exc)

    # Check for HTTP status errors (httpx or requests)
    status_code = getattr(exc, "status_code", None)
    if status_code is None:
        response = getattr(exc, "response", None)
        if response is not None:
            status_code = getattr(response, "status_code", None)

    if status_code and status_code in _HTTP_REMEDIATION:
        message, detail = _HTTP_REMEDIATION[status_code]
        if json_mode:
            print(json.dumps({"error": message, "detail": detail, "status_code": status_code}))
        else:
            console.print(f"[red]{message}[/]")
            console.print(f"  [dim]{detail}[/]")
        return

    # Check for known exception types
    if exc_type in _REMEDIATION:
        message, detail = _REMEDIATION[exc_type]
        if json_mode:
            print(json.dumps({"error": message, "detail": detail}))
        else:
            console.print(f"[red]{message}[/]")
            console.print(f"  [dim]{detail}[/]")
        return

    # Check parent classes
    for parent_name, (message, detail) in _REMEDIATION.items():
        for cls in type(exc).__mro__:
            if cls.__name__ == parent_name:
                if json_mode:
                    print(json.dumps({"error": message, "detail": detail}))
                else:
                    console.print(f"[red]{message}[/]")
                    console.print(f"  [dim]{detail}[/]")
                return

    # Generic fallback
    if json_mode:
        print(json.dumps({"error": str(exc)}))
    else:
        console.print(f"[red]Error: {exc}[/]")
        console.print("  [dim]Try: hikaflow doctor[/]")
