"""Market data: prices, coins, orderbook, funding, meta."""

from typing import Annotated, Any

import typer

from ..config import OutputFormat
from ..context import AppContext
from ..output import format_funding, format_orderbook
from ..utils import complete_coin_symbol
from .base import console, safe_command, with_progress

app = typer.Typer(help="Market data", rich_markup_mode="rich")


@app.command("coins")
@safe_command
def data_coins(
    ctx: typer.Context,
) -> None:
    """List all available coins/assets for trading with current prices."""
    app_ctx: AppContext = ctx.obj

    @with_progress("Fetching available coins...")
    def execute() -> Any:
        return app_ctx.client.get_all_mids()

    all_prices = execute()

    main_coins = {}
    other_coins = {}

    for coin, price in all_prices.items():
        if coin.startswith("@"):
            readable_name = app_ctx.client.get_coin_name(coin)
            other_coins[readable_name] = price
        else:
            main_coins[coin] = price

    if app_ctx.formatter.format == OutputFormat.TABLE:
        console.print(f"\n[bold]Available Coins ({len(main_coins)} major coins)[/bold]")
        if main_coins:
            formatted_data = []
            for coin, price in sorted(main_coins.items()):
                formatted_data.append({"Coin": coin, "Current Price": f"${price:,.2f}", "Symbol": coin})
            app_ctx.formatter.print(formatted_data, title="Major Trading Pairs")

        if other_coins and len(other_coins) <= 20:
            console.print(f"\n[dim]Other Available Assets ({len(other_coins)} assets)[/dim]")
            formatted_other = []
            for coin, price in sorted(list(other_coins.items())[:20]):
                formatted_other.append({"Asset": coin, "Price": f"${price:,.6f}" if price < 1 else f"${price:,.2f}"})
            if formatted_other:
                app_ctx.formatter.print(formatted_other)
    else:
        app_ctx.formatter.print(all_prices)


@app.command("price")
@safe_command
def data_prices(
    ctx: typer.Context,
    coins: Annotated[
        list[str] | None,
        typer.Argument(
            help="Coin symbols (e.g., [bold green]BTC ETH SOL[/bold green])", autocompletion=complete_coin_symbol
        ),
    ] = None,
) -> None:
    """Get current mid prices for specified coins."""
    app_ctx: AppContext = ctx.obj

    @with_progress("Fetching prices...")
    def execute() -> Any:
        return app_ctx.client.get_all_mids()

    all_prices = execute()

    if coins:
        coins = [coin.upper() for coin in coins]
        filtered_prices = {coin: price for coin in coins if (price := all_prices.get(coin))}
        if not filtered_prices:
            console.print(f"[red]No prices found for: {', '.join(coins)}[/red]")
            available_coins = [coin for coin in all_prices if not coin.startswith("@")][:10]
            console.print(f"[yellow]Available coins include:[/yellow] {', '.join(available_coins)}")
            raise typer.Exit(code=1) from None
    else:
        filtered_prices = {coin: price for coin, price in all_prices.items() if not coin.startswith("@")}

    if app_ctx.formatter.format == OutputFormat.JSON:
        app_ctx.formatter.print(filtered_prices)
    else:
        formatted_data = []
        for coin, price in sorted(filtered_prices.items()):
            formatted_data.append({"Coin": coin, "Price": f"${price:,.2f}"})
        app_ctx.formatter.print(formatted_data, title="Current Prices")


@app.command("orderbook")
@safe_command
def data_orderbook(
    ctx: typer.Context,
    coin: Annotated[
        str,
        typer.Argument(help="Coin symbol (e.g., [bold green]BTC[/bold green])", autocompletion=complete_coin_symbol),
    ],
    depth: Annotated[int, typer.Option("--depth", "-d", help="Order book depth", min=1, max=50)] = 10,
) -> None:
    """Get L2 orderbook snapshot for a coin."""
    app_ctx: AppContext = ctx.obj

    coin = coin.upper()

    @with_progress(f"Fetching {coin} orderbook...")
    def execute() -> Any:
        return app_ctx.client.get_l2_book(coin)

    orderbook = execute()

    if app_ctx.formatter.format == OutputFormat.JSON:
        app_ctx.formatter.print(orderbook)
    else:
        formatted_orderbook = format_orderbook(orderbook, depth)
        app_ctx.formatter.print(formatted_orderbook, title=f"{coin} Order Book (Top {depth})")


@app.command("funding")
@safe_command
def data_funding(
    ctx: typer.Context,
    coin: Annotated[
        str,
        typer.Argument(help="Coin symbol (e.g., [bold green]BTC[/bold green])", autocompletion=complete_coin_symbol),
    ],
    hours: Annotated[int, typer.Option("--hours", "-h", help="Hours of history to fetch", min=1, max=168)] = 24,
) -> None:
    """Get funding rate history for a coin."""
    app_ctx: AppContext = ctx.obj

    coin = coin.upper()

    @with_progress(f"Fetching {coin} funding history...")
    def execute() -> Any:
        from datetime import datetime, timedelta

        start_time = int((datetime.now() - timedelta(hours=hours)).timestamp() * 1000)
        return app_ctx.client.get_funding_history(coin, start_time)

    funding = execute()

    if app_ctx.formatter.format == OutputFormat.JSON:
        app_ctx.formatter.print(funding)
    else:
        formatted_funding = format_funding(funding)
        if not formatted_funding:
            console.print(f"[yellow]No funding data found for {coin}[/yellow]")
        else:
            app_ctx.formatter.print(formatted_funding, title=f"{coin} Funding History (Last {hours}h)")


@app.command("meta")
@safe_command
def data_meta(
    ctx: typer.Context,
    coin: Annotated[
        str,
        typer.Argument(help="Coin symbol or token ID (e.g., [bold green]BTC[/bold green], [cyan]@107[/cyan])"),
    ],
) -> None:
    """Get asset metadata including max leverage and decimals."""
    app_ctx: AppContext = ctx.obj

    coin = coin.upper()

    @with_progress(f"Fetching {coin} metadata...")
    def execute() -> Any:
        return app_ctx.client.get_asset_info(coin)

    asset_info = execute()

    if app_ctx.formatter.format == OutputFormat.JSON:
        app_ctx.formatter.print(asset_info)
    else:
        if asset_info:
            formatted_data = [
                {"Field": "Name", "Value": asset_info.get("name", "N/A")},
                {"Field": "Symbol", "Value": coin},
                {"Field": "Max Leverage", "Value": f"{asset_info.get('maxLeverage', 'N/A')}x"},
                {"Field": "Size Decimals", "Value": asset_info.get("szDecimals", "N/A")},
                {"Field": "Only Isolated", "Value": "Yes" if asset_info.get("onlyIsolated") else "No"},
            ]
            app_ctx.formatter.print(formatted_data, title=f"{coin} Asset Info")
        else:
            console.print(f"[red]Asset info not found for {coin}[/red]")
            raise typer.Exit(code=1) from None


@app.command("asset-ctx")
@safe_command
def data_asset_ctx(
    ctx: typer.Context,
    coin: Annotated[str | None, typer.Argument(help="Coin symbol (optional, shows all if not specified)")] = None,
) -> None:
    """Get asset metadata with market context (volume, funding, open interest)."""
    app_ctx: AppContext = ctx.obj

    if coin:
        coin = coin.upper()

    @with_progress("Fetching asset context data...")
    def execute() -> Any:
        return app_ctx.client.get_meta_and_asset_ctxs()

    data = execute()

    if app_ctx.formatter.format == OutputFormat.JSON:
        if coin:
            meta = data[0] if len(data) > 0 else {}
            asset_ctxs = data[1] if len(data) > 1 else []
            universe = meta.get("universe", [])

            coin_index = None
            for i, asset in enumerate(universe):
                if asset.get("name", "").upper() == coin:
                    coin_index = i
                    break

            if coin_index is not None and coin_index < len(asset_ctxs):
                app_ctx.formatter.print(asset_ctxs[coin_index])
            else:
                console.print(f"[red]Asset context not found for {coin}[/red]")
                raise typer.Exit(code=1) from None
        else:
            app_ctx.formatter.print(data)
    else:
        meta = data[0] if len(data) > 0 else {}
        asset_ctxs = data[1] if len(data) > 1 else []
        universe = meta.get("universe", [])

        if coin:
            coin_index = None
            for i, asset in enumerate(universe):
                if asset.get("name", "").upper() == coin:
                    coin_index = i
                    break

            if coin_index is not None and coin_index < len(asset_ctxs):
                ctx_data = asset_ctxs[coin_index]
                open_interest_base = float(ctx_data.get("openInterest", 0))
                mark_price = float(ctx_data.get("markPx", 0))
                open_interest_usd = open_interest_base * mark_price
                formatted_data = [
                    {"Field": "Coin", "Value": coin},
                    {"Field": "Funding Rate", "Value": f"{float(ctx_data.get('funding', 0)) * 100:.4f}%"},
                    {"Field": "Open Interest", "Value": f"${open_interest_usd:,.2f}"},
                    {"Field": "24h Volume", "Value": f"${float(ctx_data.get('dayNtlVlm', 0)):,.2f}"},
                    {"Field": "Premium", "Value": f"{float(ctx_data.get('premium', 0)) * 100:.4f}%"},
                    {"Field": "Mark Price", "Value": f"${mark_price:,.2f}"},
                ]
                app_ctx.formatter.print(formatted_data, title=f"{coin} Market Context")
            else:
                console.print(f"[red]Asset context not found for {coin}[/red]")
                raise typer.Exit(code=1) from None
        else:
            formatted_data = []
            for i, asset_ctx in enumerate(asset_ctxs[:20]):
                if i < len(universe):
                    coin_name = universe[i].get("name", f"Asset_{i}")
                    open_interest_base = float(asset_ctx.get("openInterest", 0))
                    mark_price = float(asset_ctx.get("markPx", 0))
                    open_interest_usd = open_interest_base * mark_price
                    formatted_data.append(
                        {
                            "Coin": coin_name,
                            "Funding": f"{float(asset_ctx.get('funding', 0)) * 100:.4f}%",
                            "Open Interest": f"${open_interest_usd:,.0f}",
                            "24h Volume": f"${float(asset_ctx.get('dayNtlVlm', 0)):,.0f}",
                        }
                    )
            app_ctx.formatter.print(formatted_data, title="Asset Market Context (Top 20)")
