"""Order management: limit orders and cancellation."""

from typing import Annotated, Any, Literal, cast

import typer

from ..config import OutputFormat
from ..context import AppContext
from ..utils import complete_coin_symbol
from .base import (
    console,
    parse_leverage,
    parse_order_response,
    parse_side,
    trading_command,
    validate_order_size,
    with_progress,
)

app = typer.Typer(help="Order management", rich_markup_mode="rich")


@app.command("limit")
@trading_command
def limit_order(
    ctx: typer.Context,
    side: Annotated[str, typer.Argument(help="Side: [green]long[/green] or [red]short[/red]")],
    coin: Annotated[
        str,
        typer.Argument(help="Coin symbol (e.g., [bold green]BTC[/bold green])", autocompletion=complete_coin_symbol),
    ],
    leverage: Annotated[str, typer.Argument(help="Leverage (e.g., [cyan]5x[/cyan], [cyan]10[/cyan])")],
    price: Annotated[float, typer.Argument(help="Limit price", min=0.0001)],
    margin: Annotated[float, typer.Argument(help="Margin in USD (e.g., [yellow]1000[/yellow])", min=10)],
    tif: Annotated[
        str,
        typer.Option(
            "--tif",
            help="Time in force: [cyan]Gtc[/cyan] (Good till cancel), [yellow]Ioc[/yellow] (Immediate or cancel), [magenta]Alo[/magenta] (Add liquidity only)",
        ),
    ] = "Gtc",
    reduce_only: Annotated[
        bool, typer.Option("--reduce-only", help="[yellow]Reduce only order[/yellow] (won't increase position)")
    ] = False,
) -> None:
    """Place a limit order with leverage and margin."""
    app_ctx: AppContext = ctx.obj

    coin = coin.upper()
    is_buy = parse_side(side)
    leverage_int = parse_leverage(leverage)

    if tif not in ["Gtc", "Ioc", "Alo"]:
        console.print(f"[red]Invalid TIF:[/red] '{tif}'. Must be 'Gtc', 'Ioc', or 'Alo'")
        raise typer.Exit(code=1) from None

    position_size = app_ctx.client.calculate_position_size(coin, margin, leverage_int)

    size_valid, size_error = validate_order_size(position_size, price)
    if not size_valid:
        console.print(f"[red]Invalid order size:[/red] {size_error}")
        console.print(f"[yellow]Tip:[/yellow] Increase margin to at least {10.0 / price:.6f} {coin}")
        raise typer.Exit(code=1) from None

    if ctx.meta.get("verbose"):
        console.print("\n[bold]Limit Order Details:[/bold]")
        console.print(f"  Coin: [cyan]{coin}[/cyan]")
        console.print(f"  Side: {'[green]LONG[/green]' if is_buy else '[red]SHORT[/red]'}")
        console.print(f"  Size: [yellow]{position_size}[/yellow]")
        console.print(f"  Price: [yellow]${price:,.4f}[/yellow]")
        console.print(f"  Leverage: [yellow]{leverage_int}x[/yellow]")
        console.print(f"  Margin: [yellow]${margin:,.2f}[/yellow]")
        console.print(f"  TIF: [cyan]{tif}[/cyan]")
        if reduce_only:
            console.print("  [yellow]Reduce only: Yes[/yellow]")
        console.print()

    if leverage_int:
        app_ctx.client.update_leverage(coin, leverage_int)

    @with_progress(f"Placing limit {'buy' if is_buy else 'sell'} order for {position_size} {coin}...")
    def execute() -> Any:
        return app_ctx.client.place_order(
            coin=coin,
            is_buy=is_buy,
            size=position_size,
            limit_px=price,
            reduce_only=reduce_only,
            tif=cast(Literal["Gtc", "Ioc", "Alo"], tif),
        )

    result = execute()

    if app_ctx.formatter.format == OutputFormat.JSON:
        app_ctx.formatter.print(result)
    else:
        success, message = parse_order_response(result)
        if success:
            console.print(f"[green]✓[/green] Limit order: {message}")
        else:
            console.print(f"[red]✗[/red] Limit order failed: {message}")
            raise typer.Exit(code=1) from None


@app.command("cancel")
@trading_command
def cancel_orders(
    ctx: typer.Context,
    coin: Annotated[
        str,
        typer.Argument(help="Coin symbol (e.g., [bold green]BTC[/bold green])", autocompletion=complete_coin_symbol),
    ],
    order_id: Annotated[int | None, typer.Argument(help="Order ID to cancel (optional for all orders)")] = None,
    all_orders: Annotated[bool, typer.Option("--all", help="Cancel all orders for this coin")] = False,
) -> None:
    """Cancel specific order or all orders for a coin."""
    app_ctx: AppContext = ctx.obj

    coin = coin.upper()

    if order_id and all_orders:
        console.print("[red]Cannot specify both order ID and --all flag[/red]")
        raise typer.Exit(code=1) from None

    if not order_id and not all_orders:
        console.print("[red]Must specify either order ID or --all flag[/red]")
        raise typer.Exit(code=1) from None

    if all_orders:

        @with_progress(f"Canceling all {coin} orders...")
        def execute() -> Any:
            return app_ctx.client.cancel_all_orders(coin)

        result = execute()

        if app_ctx.formatter.format == OutputFormat.JSON:
            app_ctx.formatter.print(result)
        else:
            success, message = parse_order_response(result)
            if success:
                console.print(f"[green]✓[/green] All {coin} orders canceled")
            else:
                console.print(f"[red]✗[/red] Failed to cancel {coin} orders: {message}")
                raise typer.Exit(code=1) from None
    else:

        @with_progress(f"Canceling {coin} order {order_id}...")
        def execute() -> Any:
            if order_id is None:
                raise ValueError("Order ID cannot be None for single order cancellation")
            return app_ctx.client.cancel_order(coin, order_id)

        result = execute()

        if app_ctx.formatter.format == OutputFormat.JSON:
            app_ctx.formatter.print(result)
        else:
            success, message = parse_order_response(result)
            if success:
                console.print(f"[green]✓[/green] Order {order_id} canceled")
            else:
                console.print(f"[red]✗[/red] Failed to cancel order {order_id}: {message}")
                raise typer.Exit(code=1) from None
