"""runner signin — the OAuth device flow (prod.md §Sign-in).

Print a URL + short code, the human approves it in the browser, the CLI polls
until it gets a token, and the token is cached at ~/.config/acsetra/credentials
(0600). No token -> every command tells you to run `runner signin`, so sign-in is
structurally required, not a flag.
"""
import sys
import time
import webbrowser

from . import api, config


def signin(api_base=None, token_name="cli", open_browser=True):
    if api_base:
        config.set_project(api_base=api_base.rstrip("/"))
    base = config.api_base()
    print(f"Signing in to {base}", file=sys.stderr)
    try:
        start = api.device_start(token_name)
    except api.ApiError as e:
        print(f"could not start sign-in: {e}", file=sys.stderr)
        return 1

    user_code = start["user_code"]
    verify = start.get("verification_uri_complete") or start.get("verification_uri")
    interval = max(1, int(start.get("interval", 5)))
    device_code = start["device_code"]

    print("\n  To sign in, visit:\n")
    print(f"    {verify}\n")
    print(f"  and confirm the code:  {user_code}\n", file=sys.stderr)
    if open_browser:
        try:
            webbrowser.open(verify)
        except Exception:
            pass

    deadline = time.time() + int(start.get("expires_in", 900))
    while time.time() < deadline:
        time.sleep(interval)
        status, body = api.device_token(device_code)
        st = body.get("status")
        if status == 200 and body.get("token"):
            _persist(base, body)
            print(f"\n✓ Signed in. Workspace: {body.get('workspace')}", file=sys.stderr)
            return 0
        if st == "denied":
            print("\n✗ Sign-in was denied.", file=sys.stderr)
            return 1
        if st in ("expired",) or status == 410:
            print("\n✗ The code expired. Run `runner signin` again.", file=sys.stderr)
            return 1
        # 202 pending / 404 not-yet-visible -> keep polling
    print("\n✗ Timed out waiting for approval.", file=sys.stderr)
    return 1


def _persist(base, body):
    cred = config.load_user()
    cred.update({"api_base": base, "token": body["token"],
                 "workspace": body.get("workspace"), "scope_root": body.get("scope_root")})
    config.save_user(cred)
    # mirror the workspace into the project config (safe to commit; no token)
    config.set_project(api_base=base, workspace=body.get("workspace"),
                       default_scope=body.get("scope_root"))
