"""Base utilities for command modules."""

from collections.abc import Callable
from functools import wraps
from typing import Any, Concatenate, ParamSpec, TypeVar

import typer
from rich.console import Console
from rich.progress import Progress, SpinnerColumn, TextColumn

from ..config import validate_trading_config
from ..context import AppContext

console = Console()
error_console = Console(stderr=True)

P = ParamSpec("P")
R = TypeVar("R")


def trading_command(func: Callable[Concatenate[typer.Context, P], R]) -> Callable[Concatenate[typer.Context, P], R]:
    """Decorator for trading commands that require authentication."""

    @wraps(func)
    def wrapper(ctx: typer.Context, *args: P.args, **kwargs: P.kwargs) -> R:
        app_ctx: AppContext = ctx.obj
        validate_trading_config(app_ctx.config)
        try:
            return func(ctx, *args, **kwargs)
        except typer.Exit:
            raise
        except Exception as e:
            console.print(f"[red]Error:[/red] {e}", highlight=False)
            raise typer.Exit(code=1) from None

    return wrapper


def with_progress(message: str) -> Callable[[Callable[P, R]], Callable[P, R]]:
    """Decorator to add progress spinner to function."""

    def decorator(func: Callable[P, R]) -> Callable[P, R]:
        @wraps(func)
        def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
            with Progress(
                SpinnerColumn(),
                TextColumn("[progress.description]{task.description}"),
                console=console,
                transient=True,
            ) as progress:
                progress.add_task(message, total=None)
                return func(*args, **kwargs)

        return wrapper

    return decorator


def safe_command(func: Callable[Concatenate[typer.Context, P], R]) -> Callable[Concatenate[typer.Context, P], R]:
    """Decorator for commands with error handling."""

    @wraps(func)
    def wrapper(ctx: typer.Context, *args: P.args, **kwargs: P.kwargs) -> R:
        try:
            return func(ctx, *args, **kwargs)
        except typer.Exit:
            raise
        except Exception as e:
            console.print(f"[red]Error:[/red] {e}", highlight=False)
            raise typer.Exit(code=1) from None

    return wrapper


def parse_leverage(leverage_str: str) -> int:
    """Parse leverage string (e.g., '5x', '10') to integer."""
    leverage_str = leverage_str.lower().rstrip("x")
    try:
        leverage = int(leverage_str)
        if leverage < 1 or leverage > 50:
            raise ValueError(f"Leverage must be between 1 and 50, got {leverage}")
        return leverage
    except ValueError as e:
        if "invalid literal" in str(e):
            raise ValueError(f"Invalid leverage format: {leverage_str}. Use format like '5x' or '10'") from e
        raise


def parse_percentage(percentage_str: str) -> float:
    """Parse percentage string (e.g., '100%', '50') to float."""
    percentage_str = percentage_str.rstrip("%")
    try:
        percentage = float(percentage_str)
        if percentage <= 0 or percentage > 100:
            raise ValueError(f"Percentage must be between 0.1 and 100, got {percentage}")
        return percentage
    except ValueError as e:
        if "could not convert" in str(e):
            raise ValueError(f"Invalid percentage format: {percentage_str}. Use format like '100%' or '50'") from e
        raise


def parse_side(side: str) -> bool:
    """Parse side string to boolean (True for buy/long, False for sell/short)."""
    side_lower = side.lower()
    if side_lower in ["buy", "b", "long"]:
        return True
    elif side_lower in ["sell", "s", "short"]:
        return False
    else:
        raise ValueError(f"Invalid side: '{side}'. Must be 'buy', 'sell', 'long', or 'short'")


def parse_order_response(result: dict[str, Any]) -> tuple[bool, str]:
    """Parse order response and return (success, message)."""
    if result.get("status") != "ok":
        return False, f"API error: {result.get('status', 'unknown')}"

    response = result.get("response", {})
    data = response.get("data", {})
    statuses = data.get("statuses", [])

    if not statuses:
        return False, "No order status returned"

    messages = []
    has_success = False
    has_error = False

    for status in statuses:
        if "error" in status:
            has_error = True
            error_msg = status["error"]
            messages.append(f"Order rejected: {error_msg}")
        elif "filled" in status:
            has_success = True
            filled = status["filled"]
            if isinstance(filled, dict):
                size = filled.get("totalSz", "N/A")
                price = filled.get("avgPx", "N/A")
                oid = filled.get("oid", "N/A")
                messages.append(f"Order filled: {size} @ ${price} (ID: {oid})")
            else:
                messages.append(f"Order filled: {filled}")
        elif "resting" in status:
            has_success = True
            resting = status["resting"]
            if isinstance(resting, dict):
                oid = resting.get("oid", "N/A")
                messages.append(f"Order placed successfully (ID: {oid})")
            else:
                messages.append(f"Order placed: {resting}")
        else:
            messages.append(f"Unknown status: {status}")

    if has_error:
        return False, "; ".join(messages)
    elif has_success:
        return True, "; ".join(messages)
    else:
        return False, "Unknown order status"


def validate_order_size(size: float, price: float) -> tuple[bool, str]:
    """Validate order size meets minimum requirements."""
    order_value = size * price
    min_value = 10.0

    if order_value < min_value:
        return False, f"Order value ${order_value:.2f} is below minimum ${min_value:.2f}"

    return True, ""
