"""Velar CLI - deploy and manage GPU workloads."""

from __future__ import annotations

import importlib.util
import sys

import click
from rich.console import Console

console = Console()


def _load_app(app_ref: str):
    """Import a module and return the App object from it.

    app_ref format: ``module_path:attr`` (e.g. ``app:app`` or ``train:app``).
    """
    module_path, _, attr = app_ref.partition(":")
    if not attr:
        attr = "app"

    if "." in module_path:
        mod = __import__(module_path, fromlist=[attr])
    else:
        spec = importlib.util.spec_from_file_location(module_path, f"{module_path}.py")
        if spec is None or spec.loader is None:
            console.print(f"[red]Could not find module: {module_path}.py[/red]")
            sys.exit(1)
        mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(mod)

    try:
        return getattr(mod, attr)
    except AttributeError:
        console.print(f"[red]'{attr}' not found in {module_path}[/red]")
        sys.exit(1)


@click.group()
@click.version_option(package_name="velar-sdk")
def cli():
    """Velar - Deploy ML models to GPUs with one command."""
    pass


# ---------------------------------------------------------------------------
# velar login
# ---------------------------------------------------------------------------


@cli.command()
def login():
    """Authenticate via browser and save credentials.

    Opens velar.run in your browser. After you sign in, a persistent
    API key is created and saved to ~/.velar/token automatically.
    """
    import http.server
    import secrets
    import socket
    import urllib.parse
    import webbrowser

    from velar.config import save_token

    # Find a free ephemeral port
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind(("127.0.0.1", 0))
        port = s.getsockname()[1]

    state = secrets.token_urlsafe(16)
    received: list[str] = []

    class _Handler(http.server.BaseHTTPRequestHandler):
        def do_GET(self):
            parsed = urllib.parse.urlparse(self.path)
            params = urllib.parse.parse_qs(parsed.query)
            token_list = params.get("token", [])

            if token_list and params.get("state", [""])[0] == state:
                received.append(token_list[0])
                body = _SUCCESS_HTML
                code = 200
            else:
                body = b"<p>Authentication failed. Please try again.</p>"
                code = 400

            self.send_response(code)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)

        def log_message(self, fmt, *args):
            pass  # Suppress server logs

    server = http.server.HTTPServer(("127.0.0.1", port), _Handler)

    callback = f"http://127.0.0.1:{port}/callback"
    login_url = (
        "https://velar.run/cli-auth"
        f"?callback={urllib.parse.quote(callback, safe='')}"
        f"&state={state}"
    )

    console.print("\n[bold]Opening browser to authenticate...[/bold]")
    console.print(
        "[dim]If the browser doesn't open automatically, visit:[/dim]\n"
        f"[cyan]{login_url}[/cyan]\n"
    )

    webbrowser.open(login_url)

    # Block until we receive exactly one callback request
    server.handle_request()
    server.server_close()

    if received:
        save_token(received[0])
        console.print("[green]✓ Authenticated successfully[/green]")
        console.print("[dim]  Token saved to ~/.velar/token[/dim]")
    else:
        console.print("[red]✗ Authentication failed[/red]")
        sys.exit(1)


_SUCCESS_HTML = b"""<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Velar CLI</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      font-family: system-ui, -apple-system, sans-serif;
      background: #09090b;
      color: #fff;
      display: flex;
      align-items: center;
      justify-content: center;
      min-height: 100vh;
    }
    .card {
      text-align: center;
      padding: 2.5rem;
      border: 1px solid rgba(255,255,255,0.08);
      border-radius: 1rem;
      background: rgba(255,255,255,0.03);
      max-width: 380px;
    }
    .icon {
      width: 48px; height: 48px;
      background: rgba(99,102,241,0.15);
      border-radius: 50%;
      display: flex; align-items: center; justify-content: center;
      margin: 0 auto 1.25rem;
    }
    svg { color: #818cf8; }
    h1 { font-size: 1.25rem; margin-bottom: 0.5rem; }
    p  { font-size: 0.875rem; color: #71717a; }
  </style>
</head>
<body>
  <div class="card">
    <div class="icon">
      <svg width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.5"
           stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24">
        <polyline points="20 6 9 17 4 12"/>
      </svg>
    </div>
    <h1>Logged in!</h1>
    <p>You can close this tab and return to the terminal.</p>
  </div>
</body>
</html>"""


# ---------------------------------------------------------------------------
# velar deploy
# ---------------------------------------------------------------------------


@cli.command()
@click.argument("app_ref")
def deploy(app_ref: str):
    """Deploy an app to the cloud.

    APP_REF is module:app (e.g. app:app or train:app).

    \b
    Examples:
        velar deploy app:app
        velar deploy my_project.main:app
    """
    try:
        app = _load_app(app_ref)
        console.print(f"[bold]Deploying {app.name}...[/bold]\n")
        app.deploy()
    except FileNotFoundError:
        module_path = app_ref.partition(":")[0]
        console.print(f"[red]File not found: {module_path}.py[/red]")
        sys.exit(1)
    except Exception as e:
        console.print(f"[red]Error: {e}[/red]")
        sys.exit(1)


# ---------------------------------------------------------------------------
# velar run
# ---------------------------------------------------------------------------


@cli.command()
@click.argument("app_ref")
def run(app_ref: str):
    """Run the local entrypoint of an app.

    APP_REF is module:app (e.g. app:app or train:app).
    The app must have a function decorated with @app.local_entrypoint().

    \b
    Examples:
        velar run app:app
        velar run inference:app
    """
    try:
        app = _load_app(app_ref)

        if app._local_entrypoint is None:
            console.print(
                "[red]No local entrypoint found.[/red] "
                "Decorate a function with [bold]@app.local_entrypoint()[/bold]."
            )
            sys.exit(1)

        console.print(f"[dim]Running local entrypoint for '{app.name}'...[/dim]\n")
        app._local_entrypoint()

    except FileNotFoundError:
        module_path = app_ref.partition(":")[0]
        console.print(f"[red]File not found: {module_path}.py[/red]")
        sys.exit(1)
    except Exception as e:
        console.print(f"[red]Error: {e}[/red]")
        sys.exit(1)


# ---------------------------------------------------------------------------
# velar token
# ---------------------------------------------------------------------------


@cli.group()
def token():
    """Manage API tokens."""
    pass


@token.command("set")
@click.argument("api_key")
def token_set(api_key: str):
    """Save an API key for use by the SDK.

    The key is stored in ~/.velar/token with 600 permissions.

    \b
    Example:
        velar token set sk_live_xxxxxxxxxxxxxxxx
    """
    from velar.config import save_token

    save_token(api_key)
    console.print("[green]✓ Token saved[/green]  [dim](~/.velar/token)[/dim]")


@token.command("whoami")
def token_whoami():
    """Verify the saved token by fetching your user info."""
    from velar.client import VelarClient

    client = VelarClient()
    user = client.get_me()
    console.print(f"Email: [bold]{user.get('email', 'N/A')}[/bold]")
    console.print(f"Plan:  {user.get('plan', 'free')}")


# ---------------------------------------------------------------------------
# velar status / balance / cancel / whoami  (kept for backwards-compat)
# ---------------------------------------------------------------------------


@cli.command()
def status():
    """Show deployment status."""
    from velar.client import VelarClient

    client = VelarClient()
    deployments = client.list_deployments()

    if not deployments:
        console.print("[dim]No deployments found.[/dim]")
        return

    from rich.table import Table

    table = Table(title="Deployments")
    table.add_column("ID", style="cyan")
    table.add_column("Type")
    table.add_column("GPU")
    table.add_column("Status")
    table.add_column("Created")

    for d in deployments:
        table.add_row(
            d["id"][:8],
            d["type"],
            d["gpu_type"],
            d["status"],
            d.get("created_at", "")[:19],
        )
    console.print(table)


@cli.command()
def balance():
    """Show credit balance."""
    from velar.client import VelarClient

    client = VelarClient()
    info = client.get_balance()
    console.print(f"Credits: [bold green]${info.get('credits_balance', 0):.2f}[/bold green]")


@cli.command()
@click.argument("deployment_id")
def cancel(deployment_id: str):
    """Cancel a deployment."""
    from velar.client import VelarClient

    client = VelarClient()
    result = client.cancel_deployment(deployment_id)
    console.print(f"[yellow]Cancelled deployment {result['id'][:8]}[/yellow]")


@cli.command()
def whoami():
    """Show current user info."""
    from velar.client import VelarClient

    client = VelarClient()
    user = client.get_me()
    console.print(f"Email: [bold]{user.get('email', 'N/A')}[/bold]")
    console.print(f"Plan:  {user.get('plan', 'free')}")


if __name__ == "__main__":
    cli()
