#!/usr/bin/env node
import { hostname } from "node:os";
import { loadBridgeConfig } from "../config/bridgeConfig.js";
import { LOCAL_UI_SCOPES, isLocalUiScope, } from "../capabilities/LocalUiCapabilityService.js";
import { LocalUiHandoffError, mintLocalUiHandoff, } from "./LocalUiHandoffLauncher.js";
const DEFAULT_SCOPES = ["bridge:read"];
async function main(argv, env) {
    const options = parseArgs(argv, env);
    const bridgeToken = env.PATCHTRAIL_BRIDGE_CAPABILITY_TOKEN;
    if (!bridgeToken) {
        throw new LocalUiHandoffError("invalid_request", "PATCHTRAIL_BRIDGE_CAPABILITY_TOKEN is required. The launcher must not pass the durable bridge token in CLI args or URLs.");
    }
    if (!options.workspaceId || !options.userSessionId) {
        throw new LocalUiHandoffError("invalid_request", "--workspace-id and --user-session-id are required for a workspace-bound local UI handoff.");
    }
    const result = await mintLocalUiHandoff({
        bridgeUrl: options.bridgeUrl ?? defaultBridgeUrl(env),
        bridgeToken,
        uiUrl: options.uiUrl,
        workspaceId: options.workspaceId,
        deviceId: options.deviceId,
        userSessionId: options.userSessionId,
        scopes: options.scopes,
        ...(options.ttlSeconds ? { ttlSeconds: options.ttlSeconds } : {}),
        ...(options.sessionTtlSeconds
            ? { sessionTtlSeconds: options.sessionTtlSeconds }
            : {}),
    });
    if (options.json) {
        process.stdout.write(`${JSON.stringify({
            ...result,
            handoffUrl: options.printUrl ? result.handoffUrl : undefined,
            ...(options.printUrl ? { debugOnly: "handoffUrl" } : {}),
        })}\n`);
        return;
    }
    process.stdout.write("Local UI handoff capability minted.\n");
    process.stdout.write(`Origin: ${result.origin}\n`);
    process.stdout.write(`Workspace: ${result.workspaceId}\n`);
    process.stdout.write(`Scopes: ${result.scopes.join(",")}\n`);
    process.stdout.write(`Expires: ${result.expiresAt}\n`);
    if (options.printUrl) {
        process.stdout.write(`Handoff URL (DEBUG ONLY): ${result.handoffUrl}\n`);
    }
    else {
        process.stdout.write("Handoff URL hidden. Re-run with --print-url only for local debugging.\n");
    }
}
function parseArgs(argv, env) {
    const options = {
        uiUrl: env.PATCHTRAIL_UI_URL ?? "https://app.patchtrail.local/",
        deviceId: env.PATCHTRAIL_DEVICE_ID ?? `local-${hostname()}`,
        scopes: [...DEFAULT_SCOPES],
        printUrl: false,
        json: false,
    };
    if (env.PATCHTRAIL_BRIDGE_URL)
        options.bridgeUrl = env.PATCHTRAIL_BRIDGE_URL;
    if (env.PATCHTRAIL_WORKSPACE_ID)
        options.workspaceId = env.PATCHTRAIL_WORKSPACE_ID;
    if (env.PATCHTRAIL_USER_SESSION_ID)
        options.userSessionId = env.PATCHTRAIL_USER_SESSION_ID;
    for (let index = 0; index < argv.length; index += 1) {
        const arg = argv[index];
        if (!arg || arg === "--")
            continue;
        if (arg === "--help" || arg === "-h") {
            process.stdout.write(helpText());
            process.exit(0);
        }
        if (arg === "--json") {
            options.json = true;
            continue;
        }
        if (arg === "--print-url") {
            options.printUrl = true;
            continue;
        }
        if (arg === "--open") {
            throw new LocalUiHandoffError("invalid_request", "--open is disabled because local UI handoff URLs contain one-time capability fragments that must not be passed through child process arguments. Use --print-url only for explicit local debugging or implement a non-argv opener.");
        }
        if (arg === "--scope") {
            options.scopes.push(parseScope(readNext(argv, ++index, arg)));
            continue;
        }
        if (arg === "--scopes") {
            options.scopes = readNext(argv, ++index, arg)
                .split(",")
                .map((scope) => parseScope(scope.trim()));
            continue;
        }
        if (arg === "--ui-url") {
            options.uiUrl = readNext(argv, ++index, arg);
            continue;
        }
        if (arg === "--bridge-url") {
            options.bridgeUrl = readNext(argv, ++index, arg);
            continue;
        }
        if (arg === "--workspace-id") {
            options.workspaceId = readNext(argv, ++index, arg);
            continue;
        }
        if (arg === "--device-id") {
            options.deviceId = readNext(argv, ++index, arg);
            continue;
        }
        if (arg === "--user-session-id") {
            options.userSessionId = readNext(argv, ++index, arg);
            continue;
        }
        if (arg === "--ttl-seconds") {
            options.ttlSeconds = parsePositiveInt(readNext(argv, ++index, arg), arg);
            continue;
        }
        if (arg === "--session-ttl-seconds") {
            options.sessionTtlSeconds = parsePositiveInt(readNext(argv, ++index, arg), arg);
            continue;
        }
        if (arg === "--bridge-token") {
            throw new LocalUiHandoffError("invalid_request", "Do not pass the durable bridge token as a CLI argument. Use PATCHTRAIL_BRIDGE_CAPABILITY_TOKEN so it does not enter shell history.");
        }
        throw new LocalUiHandoffError("invalid_request", `Unknown argument: ${arg}`);
    }
    options.scopes = [...new Set(options.scopes)];
    return options;
}
function readNext(argv, index, flag) {
    const value = argv[index];
    if (!value || value.startsWith("--")) {
        throw new LocalUiHandoffError("invalid_request", `${flag} requires a value.`);
    }
    return value;
}
function parseScope(value) {
    // The bridge's LOCAL_UI_SCOPE_METADATA is the single source of truth for the
    // scope taxonomy; validate against it so a new scope never needs a second,
    // drift-prone allowlist here.
    if (isLocalUiScope(value))
        return value;
    throw new LocalUiHandoffError("invalid_request", `Unsupported local UI scope: ${value}`);
}
function parsePositiveInt(value, flag) {
    const parsed = Number.parseInt(value, 10);
    if (!Number.isInteger(parsed) || parsed <= 0) {
        throw new LocalUiHandoffError("invalid_request", `${flag} must be a positive integer.`);
    }
    return parsed;
}
function defaultBridgeUrl(env) {
    const config = loadBridgeConfig(env);
    return `http://${config.host}:${config.port}`;
}
function helpText() {
    return `Usage: pnpm local-ui:handoff -- --workspace-id <id> --user-session-id <id> [options]\n\nMints a short-lived one-time local UI handoff capability through the local bridge.\n\nRequired via environment:\n  PATCHTRAIL_BRIDGE_CAPABILITY_TOKEN   Durable launcher-only bridge token. Never pass it as an arg.\n\nOptions:\n  --ui-url <url>                      Hosted/local UI URL. Default: PATCHTRAIL_UI_URL or https://app.patchtrail.local/\n  --bridge-url <url>                  Local bridge URL. Default: PATCHTRAIL_BRIDGE_URL or PATCHTRAIL_BRIDGE_HOST/PORT.\n  --workspace-id <id>                 Workspace binding. Also PATCHTRAIL_WORKSPACE_ID.\n  --device-id <id>                    Device binding. Default: PATCHTRAIL_DEVICE_ID or local hostname.\n  --user-session-id <id>              Hosted user session binding. Also PATCHTRAIL_USER_SESSION_ID.\n  --scope <scope>                     Add one scope. Repeatable. Default: bridge:read. Supported: ${LOCAL_UI_SCOPES.join(", ")}.\n  --scopes <a,b>                      Replace scopes with a comma-separated list.\n  --ttl-seconds <n>                   One-time capability TTL. Bridge clamps accepted range.\n  --session-ttl-seconds <n>           Local UI session TTL. Bridge clamps accepted range.\n  --open                              Deprecated/rejected: fragment-bearing handoff URLs must not be passed through browser opener argv.\n  --print-url                         DEBUG ONLY: print the fragment URL for local debugging/tests.\n  --json                              Print machine-readable output. Hides handoffUrl unless --print-url is set.\n`;
}
main(process.argv.slice(2), process.env).catch((error) => {
    if (error instanceof LocalUiHandoffError) {
        process.stderr.write(`${error.message}\n`);
        process.exitCode = error.statusCode && error.statusCode >= 500 ? 2 : 1;
        return;
    }
    process.stderr.write(`${error instanceof Error ? error.message : "Unexpected launcher error."}\n`);
    process.exitCode = 1;
});
