# 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
#

"""
User-friendly error handling utilities for CloudZero Operations CLI.

This module provides standardized error display and reporting guidance to help
users understand what went wrong and how to get help.
"""

import sys
from datetime import datetime
from typing import Any

from rich.console import Console
from rich.panel import Panel

from src.exceptions import APIError

console = Console()


class CLIError(Exception):
    """Base exception for CLI-specific errors with user-friendly messaging."""

    def __init__(self, message: str, original_error: Exception | None = None, error_code: str | None = None):
        super().__init__(message)
        self.message = message
        self.original_error = original_error
        self.error_code = error_code


def format_api_error(error: Exception, operation: str, debug: bool = False) -> str:
    """
    Format API errors in a user-friendly way.

    Args:
        error: The exception that occurred
        operation: Description of what operation failed (e.g., "loading organizations")
        debug: Whether to include debug details

    Returns:
        Formatted error message
    """
    if isinstance(error, APIError):
        error_msg = f"API Error while {operation}: {str(error)}"

        # Add HTTP status code if available
        if hasattr(error, "status_code") and error.status_code:
            error_msg += f" (HTTP {error.status_code})"

        # Add server response if available
        if hasattr(error, "server_response") and error.server_response:
            import json

            if isinstance(error.server_response, dict):
                # Pretty format JSON response
                server_response_str = json.dumps(error.server_response, indent=2)
                error_msg += f"\nServer Response: {server_response_str}"
            else:
                # Raw text response
                error_msg += f"\nServer Response: {error.server_response}"
    else:
        error_msg = f"Unexpected error while {operation}: {str(error)}"

    if debug:
        error_msg += f"\nError type: {type(error).__name__}"
        if hasattr(error, "__traceback__"):
            import traceback

            error_msg += f"\nTraceback: {traceback.format_exc()}"

    return error_msg


def display_user_friendly_error(
    title: str,
    message: str,
    error: Exception | None = None,
    operation: str | None = None,
    debug: bool = False,
    exit_code: int = 1,
) -> None:
    """
    Display a user-friendly error message with reporting guidance.

    Args:
        title: Short title describing the error
        message: Main error message to display
        error: Optional exception that caused the error
        operation: Optional description of what operation failed
        debug: Whether to show additional debug details (raw requests, tracebacks, etc.)
        exit_code: Exit code to use (0 means don't exit)
    """
    # Create the main error content
    error_content = []

    # Add the main message
    error_content.append(f"[bold red]❌ {title}[/bold red]")
    error_content.append("")
    error_content.append(f"[yellow]{message}[/yellow]")

    # Add technical details if available - ALWAYS show the full error details
    if error:
        error_content.append("")
        # Show comprehensive error info by default (no debug flag needed for basic details)
        formatted_error = format_api_error(error, operation, debug=False) if operation else str(error)

        error_content.append("[bold white]Error Details:[/bold white]")
        error_content.append(f"[white]{formatted_error}[/white]")

        # Only add extra debug info when --debug is used
        if debug:
            error_content.append("")
            error_content.append("[dim]Additional Debug Information:[/dim]")

            # Add error type
            error_content.append(f"[dim]Error type: {type(error).__name__}[/dim]")

            # Add traceback if available
            if hasattr(error, "__traceback__"):
                import traceback

                error_content.append(f"[dim]Traceback:\n{traceback.format_exc()}[/dim]")

    # Add reporting guidance
    error_content.append("")
    error_content.append("[bold cyan]🔧 Need Help?[/bold cyan]")
    error_content.append("1. Check your internet connection and authentication with [bold]czops auth test[/bold]")
    if not debug:
        error_content.append("2. Try running the command with [bold]--debug[/bold] to see additional technical details")
    error_content.append("3. Report this issue in the [bold]#cz-tools[/bold] Slack channel with:")
    error_content.append("   • The exact command you ran")
    error_content.append("   • The full error message above")
    if not debug:
        error_content.append("   • Output from running the command with [bold]--debug[/bold] if requested")

    # Create and display the error panel
    panel_content = "\n".join(error_content)

    console.print()
    console.print(
        Panel(
            panel_content,
            title="[bold red]CloudZero CLI Error[/bold red]",
            title_align="left",
            border_style="red",
            padding=(1, 2),
            width=min(100, console.width or 80),
        )
    )
    console.print()

    # Exit if requested
    if exit_code != 0:
        sys.exit(exit_code)


def handle_organization_loading_error(error: Exception, arguments: dict) -> None:
    """
    Handle errors specifically related to loading organization data.

    Args:
        error: The exception that occurred
        arguments: CLI arguments dict to check for debug mode
    """
    debug = arguments.get("--debug", False)

    # Check for specific error types and HTTP status codes to provide targeted guidance
    if isinstance(error, APIError):
        status_code = getattr(error, "status_code", None)

        if status_code == 401:
            title = "Authentication Error"
            message = (
                "Authentication failed (HTTP 401). Please run 'czops auth login' to re-authenticate, "
                "or 'czops auth test --debug' to diagnose authentication issues."
            )

        elif status_code == 403:
            title = "Access Denied"
            message = (
                "Access denied (HTTP 403). Your authentication is valid but you don't have "
                "permission to access organization data. Contact your CloudZero administrator."
            )

        elif status_code == 404:
            # Check if this is specifically an "Organization not found" error
            if "organization not found" in str(error).lower():
                # Show friendly message instead of error for organization not found
                _show_friendly_org_not_found_message(error, arguments)
                return
            else:
                title = "API Endpoint Not Found"
                message = "The API endpoint was not found (HTTP 404). This may indicate a CLI version compatibility issue with the backend API."

        elif status_code == 500:
            title = "Server Error"
            message = "The CloudZero API encountered an internal server error (HTTP 500). This is likely a temporary backend issue."

        elif "validation error" in str(error).lower():
            title = "Data Format Error"
            message = "The API returned data in an unexpected format. This usually means there's a mismatch between the CLI and backend API versions."

        else:
            title = "API Error"
            message = "The CloudZero API returned an error. This could be due to a temporary service issue or a compatibility problem."

    elif "connection" in str(error).lower() or "timeout" in str(error).lower():
        title = "Network Error"
        message = "Unable to connect to the CloudZero API. Please check your internet connection and try again."

    else:
        title = "Organization Loading Failed"
        message = "Failed to load organization data from the CloudZero API. This could be a temporary issue with the backend service."

    display_user_friendly_error(
        title=title, message=message, error=error, operation="loading organizations", debug=debug, exit_code=1
    )


def create_error_context(operation: str, timestamp: datetime | None = None) -> dict[str, Any]:
    """
    Create error context information for debugging.

    Args:
        operation: Description of the operation that failed
        timestamp: Optional timestamp of when the error occurred

    Returns:
        Dictionary with error context information
    """
    if timestamp is None:
        timestamp = datetime.now()

    return {
        "operation": operation,
        "timestamp": timestamp.isoformat(),
        "cli_version": "1.0.0",  # Should be imported from src.__version__
    }


def _show_friendly_org_not_found_message(error: Exception, arguments: dict) -> None:
    """Show a friendly message when an organization is not found."""
    console = Console()

    # Extract organization ID/name from error if possible
    org_query = "the specified organization"
    error_str = str(error)
    if "Organization:" in error_str:
        try:
            org_query = error_str.split("Organization: ")[1].split(",")[0].strip()
        except (IndexError, AttributeError):
            pass

    console.print("\n[yellow]Organization Not Found[/]")
    console.print(f"No organization found with ID or name '[cyan]{org_query}[/]'")

    # Get and show materialization stats
    try:
        from src.api.v4_system import get_materialization_stats

        stats = get_materialization_stats(debug=arguments.get("--debug", False))
        if stats:
            # Show when data was last refreshed
            if timestamp := stats.get("completed_at") or stats.get("last_updated"):
                console.print(f"\n[dim]CloudZero is working with the latest data (last refresh: {timestamp})[/]")

            # Show comprehensive system statistics
            console.print("\n[bold cyan]System Summary:[/]")

            if org_count := stats.get("organizations_with_summaries"):
                console.print(f"  📊 Organizations: [green]{org_count}[/] total")

            if conn_count := stats.get("connections_written"):
                console.print(f"  🔗 Connections: [green]{conn_count:,}[/] total")

            if duration := stats.get("performance", {}).get("total_duration_ms"):
                duration_sec = float(duration) / 1000
                console.print(f"  ⏱️  Last processing: [green]{duration_sec:.1f}s[/]")

            if status := stats.get("status"):
                status_color = "green" if status == "success" else "yellow"
                console.print(f"  ✅ Status: [{status_color}]{status}[/]")

    except Exception:
        # Don't break if stats call fails
        console.print("\n[dim]CloudZero is working with the latest available data[/]")

    console.print("\n[cyan]💡 Try:[/]")
    console.print("  • [white]czops org list[/] - to see all available organizations")
    console.print(f"  • [white]czops org list {org_query}[/] - to search by partial name")
    console.print("  • Check the spelling of the organization name or ID")
