import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
 * CreateProjectScreen — Inline "Create new project…" flow.
 *
 * Reached from AuthScreen when the user picks "Create new project…" from
 * the project picker, and via the `/create-project` slash command.
 *
 * Flow:
 *   1. Prompt for a project name (TextInput)
 *   2. Validate locally (non-empty, ≤255 chars, no control chars)
 *   3. POST {proxyBase}/projects via createAmplitudeApp()
 *   4. On success:
 *        - Persist the returned apiKey via setCredentials() — this advances
 *          past AuthScreen the same way the regular env picker does.
 *        - Fire-and-forget refresh the org list so the new project shows
 *          up if the user navigates back.
 *   5. On error:
 *        - NAME_TAKEN: stay on screen, show inline error, let user retry.
 *        - QUOTA_REACHED: friendly message + fallback deep-link.
 *        - FORBIDDEN: "ask your admin" + cancel back to picker.
 *        - INVALID_REQUEST / INTERNAL / network: show message + retry button
 *          + fallback deep-link.
 *
 * The screen renders only when `session.createProject.pending` is true;
 * the router skips AuthScreen while in this mode.
 */
import { Box, Text, useInput } from 'ink';
import { useState, useEffect } from 'react';
import { TextInput } from '@inkjs/ui';
import opn from 'opn';
import { useWizardStore } from '../hooks/useWizardStore.js';
import { useScreenInput } from '../hooks/useScreenInput.js';
import { Colors, Icons } from '../styles.js';
import { BrailleSpinner } from '../components/BrailleSpinner.js';
import { TerminalLink } from '../primitives/index.js';
import { OUTBOUND_URLS } from '../../../lib/constants.js';
import { useResolvedZone } from '../hooks/useResolvedZone.js';
import { analytics } from '../../../utils/analytics.js';
import { createAmplitudeApp, validateProjectName, fetchAmplitudeUser, ApiError, } from '../../../lib/api.js';
import { getHostFromRegion } from '../../../utils/urls.js';
import { toCredentialAppId } from '../../../lib/wizard-session.js';
export const CreateProjectScreen = ({ store }) => {
    useWizardStore(store);
    const { session } = store;
    const zone = useResolvedZone(session);
    const orgId = session.selectedOrgId;
    const orgName = session.selectedOrgName;
    // /create-project can fire mid-SUSI (pending* tokens set, credentials
    // null) OR after the user is fully signed in (credentials set, pending*
    // may be null because bin.ts auto-selected a single environment). We need
    // BOTH tokens: the access token authenticates against the wizard-proxy
    // (Hydra introspection rejects id_tokens), and the id_token is what
    // fetchAmplitudeUser + the stored credentials use for the data-api.
    const accessToken = session.pendingAuthAccessToken || session.credentials?.accessToken || null;
    const idToken = session.pendingAuthIdToken || session.credentials?.idToken || null;
    const [phase, setPhase] = useState({ kind: 'idle' });
    // Uncontrolled TextInput — we only read the value on submit. We seed
    // with the suggested name so agent/CI mode can auto-fill.
    const suggestedName = session.createProject.suggestedName ?? '';
    // In agent/CI mode we must NOT prompt — if the flow got here with a name,
    // submit automatically; otherwise surface a clear error to the caller.
    // The actual agent/CI routing lives in bin.ts (see resolveNonInteractive
    // CreateProject helper) — this guard is defensive for edge cases where the
    // TUI is somehow active in a non-interactive context.
    useEffect(() => {
        if (phase.kind !== 'idle' ||
            !suggestedName ||
            !(session.agent || session.ci) ||
            !orgId ||
            !accessToken ||
            !idToken) {
            return;
        }
        void handleSubmit(suggestedName);
        // Only fires once on mount — intentionally empty deps.
    }, []);
    // Esc cancels from any phase that isn't a live submission.
    useScreenInput((input, key) => {
        if (key.escape && phase.kind !== 'submitting') {
            store.cancelCreateProject();
        }
    });
    const handleSubmit = async (rawValue) => {
        const name = rawValue.trim();
        const issue = validateProjectName(name);
        if (issue) {
            setPhase({
                kind: 'error',
                name,
                code: 'INVALID_REQUEST',
                message: issue.message,
            });
            return;
        }
        if (!orgId) {
            setPhase({
                kind: 'error',
                name,
                code: 'INVALID_REQUEST',
                message: "We couldn't carry your organization through to project creation. Press Esc and pick the organization again. (If this keeps happening, run with `--debug` and report it.)",
            });
            return;
        }
        if (!accessToken || !idToken) {
            setPhase({
                kind: 'error',
                name,
                code: 'FORBIDDEN',
                message: 'You must be signed in to create a project. Press Esc to cancel and /login to sign in.',
            });
            return;
        }
        setPhase({ kind: 'submitting', name });
        analytics.wizardCapture('Create Project Submit', {
            source: session.createProject.source,
        });
        try {
            const result = await createAmplitudeApp(accessToken, zone, {
                orgId,
                name,
            });
            // Persist the apiKey + update credentials so AuthScreen's completion
            // predicate (`session.credentials !== null`) fires and the router
            // advances to the data check. The apiKey is *not* stored on
            // session.createProject — it flows through credentials like every
            // other key.
            //
            // Persist inside its own try — the project already exists on the
            // backend at this point, so a local write failure (FS permission
            // etc.) must not be treated as a create-project error.
            const { persistApiKey } = await import('../../../utils/api-key-store.js');
            try {
                persistApiKey(result.apiKey, session.installDir);
            }
            catch {
                // In-memory credentials below still let the flow progress; a rerun
                // will re-persist. Intentionally swallow — surfacing as a create
                // error would misrepresent the backend state to the user.
            }
            store.setSelectedEnvName(result.name);
            // Dash creates a same-named taxonomy project alongside the new app.
            // Setting the project name satisfies Auth.isComplete so the router
            // can advance past Auth; the real project id will appear on the
            // next fetchAmplitudeUser refresh.
            store.restoreSessionIds({ projectName: result.name });
            store.setCredentials({
                accessToken: session.pendingAuthAccessToken ??
                    session.credentials?.accessToken ??
                    '',
                idToken,
                projectApiKey: result.apiKey,
                host: getHostFromRegion(zone),
                // The proxy returns `appId` as a string; credentials.appId is the
                // branded `AppId | 0` shape. `toCredentialAppId` validates and
                // brands the value, falling back to `0` for non-numeric input.
                appId: toCredentialAppId(result.appId),
            });
            store.setProjectHasData(false);
            store.setApiKeyNotice(null);
            // Fire-and-forget org refresh so the new project appears if the user
            // navigates back to the picker. Best-effort — never blocks the flow.
            void fetchAmplitudeUser(idToken, zone)
                .then((info) => store.setPendingOrgs(info.orgs))
                .catch(() => {
                // Swallow — we've already landed on success.
            });
            // Clear the create-project state last, after credentials are set, so
            // the router only transitions once.
            store.completeCreateProject();
        }
        catch (err) {
            const code = err instanceof ApiError && err.code
                ? err.code
                : 'INTERNAL';
            const message = err instanceof Error
                ? err.message
                : 'Could not create project. Please try again.';
            analytics.wizardCapture('Create Project Error', { code });
            setPhase({ kind: 'error', name, code, message });
        }
    };
    const handleOpenFallback = () => {
        const url = OUTBOUND_URLS.projectsSettings(zone, orgId ?? undefined);
        analytics.wizardCapture('Create Project Fallback Link Opened', {
            code: phase.kind === 'error' ? phase.code : 'unknown',
        });
        opn(url, { wait: false }).catch(() => { });
    };
    const handleRetry = () => {
        const lastTypedName = phase.kind === 'error' ? phase.name : undefined;
        setPhase({ kind: 'idle', lastTypedName });
    };
    return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: Colors.heading, children: "Create a new Amplitude project" }), orgName && (_jsxs(Text, { color: Colors.secondary, children: ["in ", _jsx(Text, { color: Colors.body, children: orgName })] }))] }), phase.kind === 'idle' && (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: Colors.body, children: "Project name" }), _jsx(Text, { color: Colors.muted, children: "Letters, numbers, and spaces. You can rename it later in Amplitude." })] }), _jsx(TextInput, { defaultValue: (phase.kind === 'idle' && phase.lastTypedName) || suggestedName, placeholder: "My new project", onSubmit: (value) => {
                            void handleSubmit(value);
                        } }), _jsxs(Text, { color: Colors.muted, children: [Icons.dot, " Press Enter to create, Esc to go back."] })] })), phase.kind === 'submitting' && (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 1, children: [_jsx(BrailleSpinner, { color: Colors.accent }), _jsxs(Text, { color: Colors.body, children: ["Creating ", _jsx(Text, { color: Colors.heading, children: phase.name }), Icons.ellipsis] })] }), _jsx(Text, { color: Colors.muted, children: "This usually takes a second or two." })] })), phase.kind === 'error' && (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Text, { color: Colors.error, children: [Icons.warning, " ", phase.message] }), phase.code === 'NAME_TAKEN' && (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { color: Colors.body, children: "That name is already in use. Try a different one." }), _jsx(TextInput, { defaultValue: phase.name, placeholder: "Pick a unique name", onSubmit: (value) => {
                                    void handleSubmit(value);
                                } })] })), phase.code === 'INVALID_REQUEST' && (_jsx(Box, { flexDirection: "column", gap: 1, children: _jsx(TextInput, { defaultValue: phase.name, placeholder: "Try a different name", onSubmit: (value) => {
                                void handleSubmit(value);
                            } }) })), phase.code === 'QUOTA_REACHED' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: Colors.body, children: "You've reached your org's project limit. Create one in the Amplitude dashboard, then come back and pick \"Start over\"." }), _jsx(Box, { marginTop: 1, children: _jsx(TerminalLink, { url: OUTBOUND_URLS.projectsSettings(zone, orgId ?? undefined), children: "Open Amplitude projects settings" }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: Colors.muted, children: "Press O to open in browser, Esc to go back." }) }), _jsx(FallbackKeyHandler, { onOpen: handleOpenFallback })] })), phase.code === 'FORBIDDEN' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: Colors.body, children: ["You don't have permission to create a project", orgName ? (_jsxs(_Fragment, { children: [' ', "in ", _jsx(Text, { bold: true, children: orgName })] })) : (' in this org'), ". Ask an admin to create one for you, or open Amplitude in your browser and create it yourself."] }), _jsx(Box, { marginTop: 1, children: _jsx(TerminalLink, { url: OUTBOUND_URLS.projectsSettings(zone, orgId ?? undefined), children: "Open Amplitude (so an admin can create the project)" }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: Colors.muted, children: "Press O to open Amplitude, Esc to go back to the picker." }) }), _jsx(FallbackKeyHandler, { onOpen: handleOpenFallback })] })), phase.code === 'INTERNAL' && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: Colors.muted, children: "Press R to retry, O to open the Amplitude dashboard, Esc to cancel." }), _jsx(FallbackKeyHandler, { onOpen: handleOpenFallback, onRetry: handleRetry })] }))] }))] }));
};
/**
 * Tiny key-input helper. Kept local to CreateProjectScreen because it only
 * exists to listen for `o` / `r` inside the error branch and we don't want
 * it to steal keystrokes from TextInput in the retry sub-branches.
 */
const FallbackKeyHandler = ({ onOpen, onRetry, }) => {
    useInput((input) => {
        if (!input)
            return;
        const ch = input.toLowerCase();
        if (ch === 'o')
            onOpen();
        if (ch === 'r' && onRetry)
            onRetry();
    });
    return null;
};
