# src/dattos_cli/commands/auth_cmd.py
from __future__ import annotations

import webbrowser

import httpx
import typer

from dattos_cli.config import get_active_profile, _load_profile_config
from dattos_cli.credentials import delete_secret, get_secret, store_secret
from dattos_cli.output import print_error, print_json

app = typer.Typer(help="Authentication management.", no_args_is_help=True)


def _make_http_client() -> httpx.Client:
    return httpx.Client(timeout=15, follow_redirects=False)


def _derive_app_url(api_url: str) -> str:
    """Derive the frontend app URL from the API URL.

    Examples:
        https://host/dattos.api -> https://host/app
        https://host/api        -> https://host
    """
    if api_url.endswith("/dattos.api"):
        return api_url[: -len("/dattos.api")] + "/app"
    if api_url.endswith("/api"):
        return api_url[: -len("/api")]
    return api_url


@app.command("login")
def login(
    browser: bool = typer.Option(False, "--browser", "-b", help="Open browser to create and paste an API key."),
):
    """Log in with username/password or via browser (--browser)."""
    profile = get_active_profile()
    cfg = _load_profile_config()
    api_url = cfg.get("api_url", "")

    if not api_url:
        print_error("config_error", "api_url not configured. Run: dattos config set api-url <url>", 2)
        raise typer.Exit(2)

    if browser:
        _login_browser(profile, api_url)
    else:
        _login_password(profile, api_url)


def _login_password(profile: str, api_url: str):
    """Interactive email/password login."""
    email = typer.prompt("Email or user code")
    password = typer.prompt("Password", hide_input=True)

    http = _make_http_client()
    try:
        resp = http.post(
            f"{api_url}/api/Authentication/Login",
            json={"userCodeOrEmail": email, "password": password},
            headers={"accept": "application/json"},
        )
    except (httpx.ConnectError, httpx.TimeoutException) as e:
        print_error("connection_error", str(e), 1)
        raise typer.Exit(1)

    if resp.status_code in (400, 401):
        print_error("auth_error", "Invalid credentials.", 1)
        raise typer.Exit(1)
    if resp.status_code >= 400:
        print_error("api_error", f"HTTP {resp.status_code}", 1)
        raise typer.Exit(1)

    data = resp.json()
    token = data.get("AuthToken") or data.get("authToken")
    name = data.get("FullName") or data.get("fullName") or ""

    if not token:
        print_error("auth_error", "No token in response.", 1)
        raise typer.Exit(1)

    store_secret(profile, "session_token", token)
    typer.echo()
    typer.echo(f"  Logged in as {name}" if name else "  Logged in")
    typer.echo(f"  Profile: {profile}")
    typer.echo()


def _login_browser(profile: str, api_url: str):
    """Browser-based login: open API key page, paste key."""
    app_url = _derive_app_url(api_url)
    key_url = f"{app_url}/my-profile/api-key"

    typer.echo()
    typer.echo("  Opening browser to create an API Key...")
    typer.echo()
    try:
        webbrowser.open(key_url)
    except OSError:
        typer.echo(f"  Could not open browser. Visit: {key_url}")


    typer.echo('  1. Click "New" to create an API Key')
    typer.echo("  2. Copy the generated token")
    typer.echo("  3. Paste it below")
    typer.echo()

    api_key = typer.prompt("API Key", hide_input=True)

    if not api_key.startswith("api-"):
        print_error("auth_error", "Invalid API Key format. Must start with 'api-'.", 1)
        raise typer.Exit(1)

    http = _make_http_client()
    try:
        resp = http.get(
            f"{api_url}/api/Authentication/UserInfo",
            headers={"Authorization": f"Bearer {api_key}", "accept": "application/json"},
        )
    except (httpx.ConnectError, httpx.TimeoutException) as e:
        print_error("connection_error", str(e), 1)
        raise typer.Exit(1)

    if resp.status_code in (401, 403):
        print_error("auth_error", "Invalid API Key.", 1)
        raise typer.Exit(1)
    if resp.status_code >= 400:
        print_error("api_error", f"HTTP {resp.status_code}", 1)
        raise typer.Exit(1)

    data = resp.json()
    name = data.get("FullName") or data.get("fullName") or ""

    store_secret(profile, "api_key", api_key)
    typer.echo()
    typer.echo(f"  Authenticated as {name}" if name else "  Authenticated")
    typer.echo(f"  Profile: {profile}")
    typer.echo()


@app.command("logout")
def logout():
    """Log out and remove the stored session token."""
    profile = get_active_profile()
    cfg = _load_profile_config()
    api_url = cfg.get("api_url", "")
    token = get_secret(profile, "session_token")

    if token and api_url:
        http = _make_http_client()
        try:
            http.post(
                f"{api_url}/api/Authentication/Logout",
                headers={"Authorization": f"Bearer {token}", "accept": "application/json"},
            )
        except (httpx.ConnectError, httpx.TimeoutException):
            pass  # Best-effort logout

    delete_secret(profile, "session_token")
    delete_secret(profile, "api_key")
    print_json({"status": "logged_out", "profile": profile})


@app.command("status")
def auth_status():
    """Show current authentication method and status."""
    profile = get_active_profile()
    cfg = _load_profile_config()

    session = get_secret(profile, "session_token")
    api_key = get_secret(profile, "api_key") or cfg.get("api_key", "")

    if session:
        print_json({"method": "session", "profile": profile, "token": session[:8] + "***"})
    elif api_key:
        masked = api_key[:4] + "***" if len(api_key) > 4 else "***"
        print_json({"method": "api-key", "profile": profile, "key": masked})
    else:
        print_json({"method": "none", "profile": profile})
