from importlib.metadata import PackageNotFoundError, version
from typing import Annotated, Optional

import typer

try:
    _version = version("sixtysix")
except PackageNotFoundError:
    _version = "dev"

app = typer.Typer(
    name="sixtysix",
    help=(
        "SixtySix - Deploy your trading backend.\n\n"
        "Deploy locally with Docker or to a cloud provider.\n"
        "Configure your broker API keys through the UI at sixtysix.pro after deployment."
    ),
    no_args_is_help=True,
)


def _version_callback(value: bool) -> None:
    if value:
        typer.echo(f"sixtysix version {_version}")
        raise typer.Exit()


@app.callback()
def main(
    version: Annotated[
        Optional[bool],
        typer.Option("--version", "-V", callback=_version_callback, is_eager=True, help="Show version and exit."),
    ] = None,
) -> None:
    pass

cloud_app = typer.Typer(help="Manage cloud deployment.")
backtest_app = typer.Typer(help="Run backtests on trading strategies. Results are saved to the database and visible in the UI.")
create_app = typer.Typer(help="Scaffold new strategies and indicators from templates.")

app.add_typer(cloud_app, name="cloud")
app.add_typer(backtest_app, name="backtest")
app.add_typer(create_app, name="create")


@app.command(name="version")
def version_cmd() -> None:
    """Print the version number."""
    typer.echo(f"sixtysix version {_version}")


@app.command()
def login() -> None:
    """Authenticate with your SixtySix account."""
    from .auth import login as _login
    _login()


@app.command()
def start() -> None:
    """Pull the latest image and start the SixtySix backend container."""
    from .docker import start as _start
    _start()


@app.command()
def stop() -> None:
    """Stop and remove the backend container."""
    from .docker import stop as _stop
    _stop()


@app.command()
def status() -> None:
    """Show container status."""
    from .docker import status as _status
    _status()


@app.command()
def logs(
    lines: int = typer.Option(50, "--lines", "-n", help="Number of lines to show"),
    follow: bool = typer.Option(False, "--follow", "-f", help="Follow log output"),
) -> None:
    """View container logs."""
    from .docker import logs as _logs
    _logs(lines=lines, follow=follow)


@app.command()
def restart() -> None:
    """Restart the backend container."""
    from .docker import restart as _restart
    _restart()


@app.command()
def update() -> None:
    """Pull the latest image and restart the container."""
    from .docker import update as _update
    _update()


# Cloud subcommands

@cloud_app.command(name="deploy")
def cloud_deploy() -> None:
    """Deploy backend to a cloud provider."""
    from .cloud import deploy
    deploy()


@cloud_app.command(name="status")
def cloud_status() -> None:
    """Show cloud server status."""
    from .cloud import cloud_status as _status
    _status()


@cloud_app.command(name="logs")
def cloud_logs_cmd(
    lines: int = typer.Option(50, "--lines", "-n", help="Number of lines to show"),
    follow: bool = typer.Option(False, "--follow", "-f", help="Follow log output"),
) -> None:
    """View container logs from cloud server."""
    from .cloud import cloud_logs
    cloud_logs(lines=lines, follow=follow)


@cloud_app.command(name="restart")
def cloud_restart() -> None:
    """Restart the container on cloud server."""
    from .cloud import cloud_restart as _restart
    _restart()


@cloud_app.command(name="update")
def cloud_update() -> None:
    """Pull the latest image and restart the container on cloud server."""
    from .cloud import cloud_update as _update
    _update()


@cloud_app.command(name="ssh")
def cloud_ssh() -> None:
    """SSH into the cloud server."""
    from .cloud import cloud_ssh as _ssh
    _ssh()


@cloud_app.command(name="destroy")
def cloud_destroy() -> None:
    """Delete the Hetzner VPS and all data on it."""
    from .cloud import cloud_destroy as _destroy
    _destroy()


# Backtest subcommands

@backtest_app.command(name="run")
def backtest_run(
    strategy: str = typer.Option(..., "--strategy", "-s", help="Strategy name (required)"),
    symbols: str = typer.Option(..., "--symbols", "-S", help="Comma-separated symbols (required)"),
    timeframe: str = typer.Option("1h", "--timeframe", "-t", help="Timeframe (1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w)"),
    days: int = typer.Option(365, "--days", "-d", help="Number of days of data"),
    limit: int = typer.Option(15000, "--limit", "-l", help="Max candles per symbol"),
    capital: float = typer.Option(10000.0, "--capital", help="Initial capital"),
    position_size: float = typer.Option(0.95, "--position-size", help="Position size (0.0-1.0)"),
    sizing_mode: str = typer.Option("percent_equity", "--sizing-mode", help="Sizing mode"),
    commission: float = typer.Option(0.0, "--commission", help="Commission per trade"),
    slippage: float = typer.Option(0.0, "--slippage", help="Slippage per trade"),
    params: str = typer.Option("{}", "--params", help="Strategy params as JSON"),
    alias: str = typer.Option("", "--alias", help="Batch alias (name in UI)"),
    account: str = typer.Option(..., "--account", "-a", help="Broker account: ibkr, binance, alpaca, demo, or a numeric account ID"),
    no_save: bool = typer.Option(False, "--no-save", help="Don't save to database"),
    json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
    verbose: bool = typer.Option(False, "--verbose", "-v", help="Verbose output"),
) -> None:
    """Run a backtest on specified symbols with a trading strategy.

    Uses the SAME code as the web backtest page - requires broker worker running.
    Results are saved to the database and can be viewed in the UI at /backtest.

    Examples:

      sixtysix backtest run -s ha_pullback -S AAPL,TSLA,NVDA -t 1h -a ibkr

      sixtysix backtest run -s ha_pullback -S AAPL,MSFT,NVDA -t 1h -d 1826 -a alpaca

      sixtysix backtest run -s pivot_confluence -S SPY -t 1h -a demo
    """
    from .backtest import run
    run(
        strategy=strategy,
        symbols=symbols,
        account=account,
        timeframe=timeframe,
        days=days,
        limit=limit,
        capital=capital,
        position_size=position_size,
        sizing_mode=sizing_mode,
        commission=commission,
        slippage=slippage,
        params=params,
        alias=alias,
        no_save=no_save,
        json_output=json_output,
        verbose=verbose,
    )


@backtest_app.command(name="accounts")
def backtest_accounts() -> None:
    """List broker accounts configured in the backend."""
    from .backtest import accounts
    accounts()


@backtest_app.command(name="strategies")
def backtest_strategies() -> None:
    """List available strategies."""
    from .backtest import strategies
    strategies()


@backtest_app.command(name="params")
def backtest_params(
    strategy_name: str = typer.Argument(..., help="Strategy name"),
) -> None:
    """Show configurable parameters for a specific strategy."""
    from .backtest import params_cmd
    params_cmd(strategy_name)


# Create subcommands

@create_app.command(name="strategy")
def create_strategy(
    name: str = typer.Argument(..., help="Strategy name (e.g. 'my_strategy' or 'MyStrategy')"),
    output_dir: str = typer.Option(
        None, "--output", "-o",
        help="Output directory. Defaults to ~/.sixtysix/data/strategies/",
    ),
) -> None:
    """Scaffold a new strategy from a template.

    Examples:

      sixtysix create strategy my_crossover

      sixtysix create strategy MomentumBreakout

      sixtysix create strategy trend_follow --output ./strategies
    """
    from pathlib import Path
    from .scaffold import create_strategy as _create
    _create(name, Path(output_dir) if output_dir else None)


@create_app.command(name="indicator")
def create_indicator(
    name: str = typer.Argument(..., help="Indicator name (e.g. 'my_indicator' or 'MyIndicator')"),
    output_dir: str = typer.Option(
        None, "--output", "-o",
        help="Output directory. Defaults to ~/.sixtysix/data/indicators/",
    ),
) -> None:
    """Scaffold a new indicator from a template.

    Examples:

      sixtysix create indicator vwap

      sixtysix create indicator BollingerBands

      sixtysix create indicator rsi_divergence --output ./indicators
    """
    from pathlib import Path
    from .scaffold import create_indicator as _create
    _create(name, Path(output_dir) if output_dir else None)
