"""
Rich formatting utilities for PrimeFeat.

Provides reusable formatting helpers for consistent console output.
"""

from typing import Dict, Any, Optional, List
from pathlib import Path
from rich.table import Table
from rich.panel import Panel
from rich.syntax import Syntax
from rich.tree import Tree
from .console import console, error_console, USE_EMOJI


def print_error(
    message: str, details: Optional[str] = None, title: str = "Error"
) -> None:
    """
    Print formatted error message.

    Args:
        message: Main error message
        details: Optional detailed error information
        title: Panel title (default: "Error")
    """
    emoji = "❌ " if USE_EMOJI else ""
    content = f"[error]{message}[/error]"
    if details:
        content += f"\n\n[dim]{details}[/dim]"

    error_console.print(
        Panel(content, title=f"[error]{emoji}{title}[/error]", border_style="red")
    )


def print_warning(
    message: str, details: Optional[str] = None, title: str = "Warning"
) -> None:
    """
    Print formatted warning message.

    Args:
        message: Main warning message
        details: Optional detailed warning information
        title: Panel title (default: "Warning")
    """
    emoji = "⚠️  " if USE_EMOJI else ""
    content = f"[warning]{message}[/warning]"
    if details:
        content += f"\n\n[dim]{details}[/dim]"

    console.print(
        Panel(
            content, title=f"[warning]{emoji}{title}[/warning]", border_style="yellow"
        )
    )


def print_success(message: str) -> None:
    """Print formatted success message."""
    emoji = "✓" if USE_EMOJI else "+"
    console.print(f"[success]{emoji}[/success] {message}")


def print_info(message: str) -> None:
    """Print formatted info message."""
    emoji = "ℹ️ " if USE_EMOJI else "i"
    console.print(f"[info]{emoji}[/info] {message}")


def format_stats_table(
    stats: Dict[str, Any], title: str = "Statistics", show_header: bool = False
) -> Table:
    """
    Create a Rich table for displaying statistics.

    Args:
        stats: Dictionary of stat_name -> value
        title: Table title
        show_header: Whether to show column headers

    Returns:
        Rich Table object
    """
    table = Table(title=title, show_header=show_header)
    table.add_column("Metric", style="key")
    table.add_column("Value", style="stat", justify="right")

    for key, value in stats.items():
        # Format value based on type
        if isinstance(value, float):
            if abs(value) < 0.01 or abs(value) > 1000:
                formatted_value = f"{value:.4e}"
            else:
                formatted_value = f"{value:.4f}"
        elif isinstance(value, int):
            formatted_value = f"{value:,}"
        else:
            formatted_value = str(value)

        table.add_row(key, formatted_value)

    return table


def create_section_panel(content: str, title: str, border_style: str = "cyan") -> Panel:
    """
    Create a Rich panel for major sections.

    Args:
        content: Panel content (can include Rich markup)
        title: Panel title
        border_style: Border color/style

    Returns:
        Rich Panel object
    """
    return Panel(content, title=f"[header]{title}[/header]", border_style=border_style)


def format_pvalue(p_value: float, alpha: float = 0.05) -> str:
    """
    Format p-value with color coding.

    Args:
        p_value: P-value to format
        alpha: Significance threshold

    Returns:
        Formatted string with Rich markup
    """
    if p_value < alpha:
        color = "green bold"
        emoji = " ✓" if USE_EMOJI else ""
    else:
        color = "dim"
        emoji = ""

    if p_value < 0.001:
        formatted = f"[{color}]<0.001{emoji}[/{color}]"
    else:
        formatted = f"[{color}]{p_value:.4f}{emoji}[/{color}]"

    return formatted


def format_percentage(value: float, threshold: float = 0.5) -> str:
    """
    Format percentage with color coding.

    Args:
        value: Value to format (0-1 range)
        threshold: Threshold for color coding

    Returns:
        Formatted string with Rich markup
    """
    if value >= threshold:
        color = "green"
    elif value >= threshold * 0.5:
        color = "yellow"
    else:
        color = "dim"

    return f"[{color}]{value:.1%}[/{color}]"


def display_yaml_config(yaml_path: Path, max_lines: int = 50) -> None:
    """
    Display YAML configuration with syntax highlighting.

    Args:
        yaml_path: Path to YAML file
        max_lines: Maximum number of lines to display
    """
    with open(yaml_path) as f:
        lines = f.readlines()
        yaml_content = "".join(lines[:max_lines])
        if len(lines) > max_lines:
            yaml_content += f"\n... ({len(lines) - max_lines} more lines)"

    syntax = Syntax(yaml_content, "yaml", theme="monokai", line_numbers=True)
    console.print(Panel(syntax, title=f"Configuration: {yaml_path.name}"))


def create_chain_tree(chains_dict: Dict[str, Any], subset_name: str = "chains") -> Tree:
    """
    Create a tree structure for displaying chain hierarchy.

    Args:
        chains_dict: Dictionary of chain_name -> config
        subset_name: Name of the subset/group

    Returns:
        Rich Tree object
    """
    tree = Tree(f"[header]Loading {subset_name}[/header]")

    for label, config in chains_dict.items():
        if isinstance(config, dict) and "path" in config:
            path = config["path"]
            tree.add(f"[parameter]{label}[/parameter] → [filename]{path}[/filename]")
        else:
            tree.add(f"[parameter]{label}[/parameter]")

    return tree


def format_computation_summary(
    method: str,
    n_samples: int,
    cache_hit: bool = False,
    additional_info: Optional[Dict[str, Any]] = None,
) -> Panel:
    """
    Create a summary panel for computation operations.

    Args:
        method: Computation method name
        n_samples: Number of samples
        cache_hit: Whether result was from cache
        additional_info: Optional additional information to display

    Returns:
        Rich Panel object
    """
    emoji_check = "✓" if USE_EMOJI else "+"
    emoji_cache = "💾" if USE_EMOJI else "*"

    content = f"[key]Method:[/key] [value]{method}[/value]\n"
    content += f"[key]Samples:[/key] [value]{n_samples:,}[/value]"

    if cache_hit:
        content += (
            f"\n[success]{emoji_check} Using cached results {emoji_cache}[/success]"
        )

    if additional_info:
        for key, value in additional_info.items():
            content += f"\n[key]{key}:[/key] [value]{value}[/value]"

    return Panel(
        content, title="[header]Computation Summary[/header]", border_style="cyan"
    )


def create_results_table(
    results: Dict[str, Any],
    title: str = "Results",
    highlight_key: Optional[str] = None,
    highlight_threshold: Optional[float] = None,
) -> Table:
    """
    Create a formatted results table.

    Args:
        results: Dictionary of result_name -> value
        title: Table title
        highlight_key: Key to apply threshold highlighting to
        highlight_threshold: Threshold for highlighting

    Returns:
        Rich Table object
    """
    table = Table(title=title, show_header=True)
    table.add_column("Metric", style="key")
    table.add_column("Value", style="value", justify="right")

    for key, value in results.items():
        # Apply highlighting if specified
        if key == highlight_key and highlight_threshold is not None:
            if isinstance(value, float) and value < highlight_threshold:
                value_str = (
                    f"[success]{value:.4f} ✓[/success]"
                    if USE_EMOJI
                    else f"[success]{value:.4f}[/success]"
                )
            else:
                value_str = f"{value:.4f}"
        elif isinstance(value, float):
            if abs(value) < 0.01 or abs(value) > 1000:
                value_str = f"{value:.4e}"
            else:
                value_str = f"{value:.4f}"
        elif isinstance(value, int):
            value_str = f"{value:,}"
        else:
            value_str = str(value)

        table.add_row(key, value_str)

    return table


# =============================================================================
# Mathematical/Scientific Formatting with Unicode
# =============================================================================


def format_mean_std(
    mean: float, std: float, precision: int = 3, use_unicode: bool = True
) -> str:
    """
    Format mean ± std with optional Unicode plus-minus symbol.

    Args:
        mean: Mean value
        std: Standard deviation
        precision: Decimal precision (default: 3)
        use_unicode: Use ± symbol if True, else '+/-' (default: True)

    Returns:
        Formatted string like "0.965 ± 0.004" or "0.965 +/- 0.004"

    Examples:
        >>> format_mean_std(0.9649, 0.0042)
        "0.965 ± 0.004"
        >>> format_mean_std(2.1e-9, 1.5e-11, precision=2)
        "2.10e-09 ± 1.50e-11"
    """
    pm_symbol = "±" if use_unicode else "+/-"

    # Use scientific notation if values are very small or large
    if abs(mean) < 0.001 or abs(mean) > 10000:
        return f"{mean:.{precision}e} {pm_symbol} {std:.{precision}e}"
    else:
        return f"{mean:.{precision}f} {pm_symbol} {std:.{precision}f}"


def format_param_name(name: str, use_unicode: bool = True) -> str:
    """
    Convert common parameter names to Unicode notation with subscripts.

    Args:
        name: Parameter name (e.g., 'A_s', 'n_s', 'omega_b')
        use_unicode: Use Unicode subscripts if True (default: True)

    Returns:
        Formatted parameter name with Unicode subscripts

    Examples:
        >>> format_param_name('A_s')
        'Aₛ'
        >>> format_param_name('omega_b')
        'ωᵦ'
        >>> format_param_name('H0')
        'H₀'
    """
    if not use_unicode:
        return name

    # Cosmological parameters common in PrimeFeat
    replacements = {
        "A_s": "Aₛ",
        "As": "Aₛ",
        "n_s": "nₛ",
        "ns": "nₛ",
        "omega_b": "ωᵦ",
        "omegab": "ωᵦ",
        "omega_cdm": "ωcdm",
        "omegacdm": "ωcdm",
        "Omega_m": "Ωₘ",
        "Omega_b": "Ωᵦ",
        "tau_reio": "τreio",
        "tau": "τ",
        "H_0": "H₀",
        "H0": "H₀",
        "sigma_8": "σ₈",
        "sigma8": "σ₈",
    }

    # Try exact match first
    if name in replacements:
        return replacements[name]

    # Handle delta_N patterns (common in PrimeFeat bins)
    if name.startswith("delta_"):
        try:
            num = name.split("_")[1]
            # Convert to subscript digits
            subscript_map = str.maketrans("0123456789", "₀₁₂₃₄₅₆₇₈₉")
            return f"δ{num.translate(subscript_map)}"
        except (IndexError, ValueError):
            pass

    return name


def format_chi2(
    chi2: float, dof: Optional[int] = None, use_unicode: bool = True
) -> str:
    """
    Format chi-squared statistic with optional degrees of freedom.

    Args:
        chi2: Chi-squared value
        dof: Degrees of freedom (optional)
        use_unicode: Use χ² symbol if True, else 'chi^2' (default: True)

    Returns:
        Formatted string like "χ² = 24.56" or "χ² = 24.56 (dof = 18)"

    Examples:
        >>> format_chi2(24.56)
        "χ² = 24.56"
        >>> format_chi2(24.56, 18)
        "χ² = 24.56 (dof = 18)"
    """
    symbol = "χ²" if use_unicode else "chi^2"
    result = f"{symbol} = {chi2:.2f}"
    if dof is not None:
        result += f" (dof = {dof})"
    return result


def format_range(
    low: float, high: float, units: str = "", use_unicode: bool = True
) -> str:
    """
    Format range with element-of symbol (∈).

    Args:
        low: Lower bound
        high: Upper bound
        units: Optional units string
        use_unicode: Use ∈ symbol if True, else 'in' (default: True)

    Returns:
        Formatted range string like "∈ [0.001, 0.23] Mpc⁻¹"

    Examples:
        >>> format_range(0.001, 0.23, "Mpc⁻¹")
        "∈ [0.001, 0.23] Mpc⁻¹"
        >>> format_range(0, 1, use_unicode=False)
        "in [0, 1]"
    """
    symbol = "∈" if use_unicode else "in"

    # Format numbers based on magnitude
    if abs(low) < 0.001 or abs(high) > 10000:
        range_str = f"[{low:.3e}, {high:.3e}]"
    else:
        range_str = f"[{low:.3g}, {high:.3g}]"

    result = f"{symbol} {range_str}"
    if units:
        result += f" {units}"

    return result


def format_scientific_value(
    value: float,
    error: Optional[float] = None,
    precision: int = 3,
    use_unicode: bool = True,
) -> str:
    """
    Format scientific value with optional error in consistent notation.

    Args:
        value: Main value
        error: Optional uncertainty
        precision: Decimal precision
        use_unicode: Use Unicode symbols (default: True)

    Returns:
        Formatted string, e.g., "2.10 × 10⁻⁹ ± 1.5 × 10⁻¹¹"

    Examples:
        >>> format_scientific_value(2.1e-9, 1.5e-11)
        "2.10 × 10⁻⁹ ± 1.5 × 10⁻¹¹"
    """
    times_symbol = "×" if use_unicode else "x"
    pm_symbol = "±" if use_unicode else "+/-"

    # Format value
    if abs(value) < 0.001 or abs(value) > 10000:
        # Use scientific notation
        exp = int(f"{value:.{precision}e}".split("e")[1])
        mantissa = value / (10**exp)

        # Convert exponent to superscript if using unicode
        if use_unicode and exp != 0:
            # Handle negative sign
            exp_str = str(abs(exp))
            superscript_map = str.maketrans("0123456789", "⁰¹²³⁴⁵⁶⁷⁸⁹")
            exp_str = exp_str.translate(superscript_map)
            if exp < 0:
                exp_str = "⁻" + exp_str
            else:
                exp_str = "⁺" + exp_str if exp > 0 else ""

            result = f"{mantissa:.{precision}f} {times_symbol} 10{exp_str}"
        else:
            result = f"{mantissa:.{precision}f}e{exp:+d}"

        # Add error if provided
        if error is not None:
            error_mantissa = error / (10**exp)
            if use_unicode:
                result += f" {pm_symbol} {error_mantissa:.{precision}f} {times_symbol} 10{exp_str}"
            else:
                result += f" {pm_symbol} {error_mantissa:.{precision}f}e{exp:+d}"
    else:
        # Regular notation
        result = f"{value:.{precision}f}"
        if error is not None:
            result += f" {pm_symbol} {error:.{precision}f}"

    return result


__all__ = [
    "print_error",
    "print_warning",
    "print_success",
    "print_info",
    "format_stats_table",
    "create_section_panel",
    "format_pvalue",
    "format_percentage",
    "display_yaml_config",
    "create_chain_tree",
    "format_computation_summary",
    "create_results_table",
    "format_mean_std",
    "format_param_name",
    "format_chi2",
    "format_range",
    "format_scientific_value",
]
