import json
import subprocess

import typer

BACKEND_CONTAINER = "sixtysix-backend"


def _fetch_accounts() -> list[dict]:
    """Query the backend container for the list of broker accounts."""
    result = subprocess.run(
        ["docker", "exec", BACKEND_CONTAINER, "python", "-m", "interfaces.cli.info", "accounts"],
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        typer.echo(
            typer.style("Failed to fetch accounts from backend. Is the container running?", fg=typer.colors.RED),
            err=True,
        )
        raise typer.Exit(1)
    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError:
        typer.echo(typer.style("Unexpected response from backend.", fg=typer.colors.RED), err=True)
        raise typer.Exit(1)


def _resolve_account(account: str) -> int:
    """Resolve an account alias to an account ID.

    Accepts a numeric ID directly (no backend query), an exact alias match, or
    a broker name. Broker-name matching fails with a clear error when multiple
    accounts share the same broker — use the alias or numeric ID in that case.
    """
    # Numeric ID — pass through without querying the backend.
    try:
        return int(account)
    except ValueError:
        pass

    lower = account.strip().lower()
    accounts = _fetch_accounts()

    # 1. Exact alias match (unambiguous).
    for a in accounts:
        if (a.get("alias") or "").lower() == lower:
            return a["id"]

    # 2. Broker name match — may be ambiguous when multiple accounts share a broker.
    broker_matches = [a for a in accounts if a.get("broker", "").lower() == lower]
    if len(broker_matches) == 1:
        return broker_matches[0]["id"]
    if len(broker_matches) > 1:
        typer.echo(
            typer.style(f"Ambiguous account '{account}': multiple accounts share that broker.", fg=typer.colors.RED),
            err=True,
        )
        typer.echo("Use the account alias or numeric ID instead:", err=True)
        for a in broker_matches:
            alias = a.get("alias") or "(no alias)"
            typer.echo(f"  --account '{alias}'  or  --account {a['id']}", err=True)
        raise typer.Exit(1)

    # 3. Not found — show all available accounts.
    typer.echo(typer.style(f"Unknown account '{account}'.", fg=typer.colors.RED), err=True)
    _print_accounts(accounts)
    raise typer.Exit(1)


def _print_accounts(accounts: list[dict]) -> None:
    typer.echo("Available accounts:")
    for a in accounts:
        alias = a.get("alias") or "(no alias)"
        typer.echo(f"  id={a['id']}  broker={a.get('broker', '')}  alias={alias}")


def run(
    strategy: str,
    symbols: str,
    account: str,
    timeframe: str = "1h",
    days: int = 365,
    limit: int = 15000,
    capital: float = 10000.0,
    position_size: float = 0.95,
    sizing_mode: str = "percent_equity",
    commission: float = 0.0,
    slippage: float = 0.0,
    params: str = "{}",
    alias: str = "",
    no_save: bool = False,
    json_output: bool = False,
    verbose: bool = False,
) -> None:
    """Run a backtest on specified symbols with a trading strategy."""
    account_id = _resolve_account(account)
    py_args = [
        "-m", "interfaces.cli.backtest",
        "-s", strategy,
        "-S", symbols,
        "-t", timeframe,
        "-d", str(days),
        "--capital", f"{capital:.2f}",
        "--position-size", f"{position_size:.4f}",
        "--sizing-mode", sizing_mode,
        "--commission", f"{commission:.6f}",
        "--slippage", f"{slippage:.6f}",
        "--params", params,
        "--account-id", str(account_id),
    ]
    if alias:
        py_args += ["--alias", alias]
    if no_save:
        py_args.append("--no-save")
    if json_output:
        py_args.append("--json")
    if verbose:
        py_args.append("-v")

    typer.echo(f"Running backtest: {strategy} on {symbols}")
    typer.echo(f"Timeframe: {timeframe}, Days: {days}, Account: {account} (id={account_id})")
    typer.echo()

    result = subprocess.run(["docker", "exec", BACKEND_CONTAINER, "python"] + py_args)
    if result.returncode != 0:
        raise typer.Exit(result.returncode)


def accounts() -> None:
    """List all broker accounts configured in the backend."""
    _print_accounts(_fetch_accounts())


def strategies() -> None:
    """List available strategies."""
    result = subprocess.run([
        "docker", "exec", BACKEND_CONTAINER,
        "python", "-m", "interfaces.cli.backtest", "--list-strategies",
    ])
    if result.returncode != 0:
        raise typer.Exit(result.returncode)


def params_cmd(strategy_name: str) -> None:
    """Show configurable parameters for a specific strategy."""
    result = subprocess.run(
        [
            "docker", "exec", BACKEND_CONTAINER,
            "python", "-m", "interfaces.cli.info", "strategy-params",
            "--strategy", strategy_name,
        ],
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        typer.echo(typer.style("Failed to get strategy params", fg=typer.colors.RED), err=True)
        raise typer.Exit(1)

    try:
        data = json.loads(result.stdout)
    except json.JSONDecodeError:
        typer.echo(result.stdout)
        return

    display_name = data.get("display_name", strategy_name)
    typer.echo()
    typer.echo(f"{display_name} Parameters:")
    typer.echo("-" * 60)

    configurable_params = data.get("configurable_params", [])
    if not configurable_params:
        typer.echo("No configurable parameters")
        return

    for p in configurable_params:
        ptype = p.get("type", "")
        if ptype == "color":
            continue
        name = p.get("name", "")
        value = p.get("value")
        label = p.get("label")
        typer.echo(f"  --{name}")
        typer.echo(f"      Label:   {label}")
        typer.echo(f"      Type:    {ptype}")
        typer.echo(f"      Default: {value}")
        if p.get("min_value") is not None:
            typer.echo(f"      Min:     {p['min_value']}")
        if p.get("max_value") is not None:
            typer.echo(f"      Max:     {p['max_value']}")
        typer.echo()

    typer.echo("Usage example:")
    typer.echo(f"  sixtysix backtest run -s {strategy_name} -S AAPL --params '{{\"pivot_len\": 15}}'")
