'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * PublishToGitHubButton — the user-facing entry point for publishing an
 * application to GitHub. Replaces the old "Create GitHub repo" button.
 *
 * State machine:
 *   • loading        — we're checking gh auth + listing owners on mount
 *   • has-remote     — application already has a gitRemoteUrl; show a chip
 *                       linking to the published repo
 *   • not-signed-in  — gh CLI isn't authenticated. Button is gated to the
 *                       sign-in flow; clicking opens gh auth login --web and
 *                       polls until done, then re-fetches owners
 *   • ready          — gh is authenticated + owners are loaded; button is
 *                       active and opens the PublishToGitHubModal
 *   • signing-in     — sign-in flow in progress (spinner)
 *   • publishing     — POST /api/applications/:id/git/create-remote in flight
 *   • failed         — show the error inline with a Retry action
 *
 * No business logic lives here — the button is a thin client over four
 * routes: /api/cloud-providers/github/auth-status, .../auth-login,
 * .../orgs, and .../applications/:id/git/create-remote.
 */
import { useCallback, useEffect, useState } from 'react';
import { ExternalLink, GitBranch, Loader2, TriangleAlert } from 'lucide-react';
import { cn } from '../../../lib/utils.js';
import { GitHubIcon } from './cloud-provider-icons.js';
import { PublishToGitHubModal } from './publish-to-github-modal.js';
import { OperationLogsDrawer } from './operation-logs-drawer.js';
import { OperationLogsIconButton } from './operation-logs-icon-button.js';
const baseClass = 'h-7 px-2 border rounded-md text-[11px] inline-flex items-center gap-1.5 transition-colors';
const interactiveHover = 'hover:bg-accent hover:text-accent-foreground cursor-pointer';
async function fetchAuthStatus() {
    const res = await fetch('/api/cloud-providers/github/auth-status');
    if (!res.ok)
        return { authenticated: false };
    return (await res.json());
}
async function fetchOwners() {
    const res = await fetch('/api/cloud-providers/github/orgs');
    if (res.status === 401)
        return { gated: true };
    if (!res.ok)
        throw new Error(`Failed to load owners (HTTP ${res.status})`);
    const body = (await res.json());
    return body.owners;
}
export function PublishToGitHubButton({ applicationId, defaultRepoName, initialRemoteUrl, disabled, className, }) {
    const [state, setState] = useState(initialRemoteUrl ? { kind: 'has-remote', url: initialRemoteUrl } : { kind: 'loading' });
    const [modalOpen, setModalOpen] = useState(false);
    const [logsOpen, setLogsOpen] = useState(false);
    const refresh = useCallback(async () => {
        if (initialRemoteUrl)
            return;
        setState({ kind: 'loading' });
        try {
            const owners = await fetchOwners();
            if ('gated' in owners) {
                setState({ kind: 'not-signed-in' });
                return;
            }
            setState({ kind: 'ready', owners });
        }
        catch (err) {
            setState({
                kind: 'failed',
                error: err instanceof Error ? err.message : 'Failed to load GitHub owners',
                canRetry: true,
            });
        }
    }, [initialRemoteUrl]);
    useEffect(() => {
        void refresh();
    }, [refresh]);
    const runSignIn = useCallback(async () => {
        setState({ kind: 'signing-in' });
        try {
            await fetch('/api/cloud-providers/github/auth-login', { method: 'POST' });
        }
        catch {
            // surface via polling below
        }
        let cancelled = false;
        const timer = setInterval(async () => {
            if (cancelled)
                return;
            const { authenticated } = await fetchAuthStatus();
            if (authenticated) {
                clearInterval(timer);
                if (!cancelled)
                    await refresh();
            }
        }, 1500);
        // The polling effect cleans itself up the next time refresh() flips state.
        return () => {
            cancelled = true;
            clearInterval(timer);
        };
    }, [refresh]);
    const runPublish = useCallback(async (input) => {
        // The MODAL owns the submitting spinner — don't touch outer state until
        // we have a definitive success or non-recoverable failure. That way the
        // dialog stays mounted and the user can fix their input and retry.
        const res = await fetch(`/api/applications/${applicationId}/git/create-remote`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(input),
        });
        if (res.ok) {
            const body = (await res.json());
            setState({ kind: 'has-remote', url: body.remoteUrl });
            setModalOpen(false);
            return;
        }
        const body = (await res.json().catch(() => ({})));
        if (body.code === 'GH_NOT_AUTHENTICATED') {
            // Auth flipped off mid-flight (rare). Close modal and route the user
            // back to sign-in.
            setModalOpen(false);
            setState({ kind: 'not-signed-in' });
            throw new Error('Sign in to GitHub first');
        }
        if (body.code === 'GH_REPO_NAME_TAKEN') {
            // Recoverable: surface inline in the modal so the user picks another
            // name without losing their context.
            throw new Error(body.error ??
                `That name is already taken on ${body.ownerLogin ?? 'this account'}. Try a different one.`);
        }
        // Non-recoverable failure: collapse to the failed branch with a Retry.
        const message = body.error ?? `Publish failed (HTTP ${res.status})`;
        setModalOpen(false);
        setState({ kind: 'failed', error: message, canRetry: true });
        throw new Error(message);
    }, [applicationId]);
    // Compute the button element for the current state. Rendered below
    // alongside the shared OperationLogsDrawer affordance so every state
    // (including failed/signing-in) can access logs without a rewrite per
    // branch.
    let buttonEl;
    if (state.kind === 'has-remote') {
        buttonEl = (_jsxs("a", { href: state.url, target: "_blank", rel: "noopener noreferrer", className: cn(baseClass, interactiveHover, 'text-foreground/80', className), title: "Open GitHub repository", children: [_jsx(GitHubIcon, { className: "size-3" }), _jsx("span", { className: "max-w-[14ch] truncate", children: state.url.replace(/^https?:\/\//, '') }), _jsx(ExternalLink, { className: "size-3" })] }));
    }
    else if (state.kind === 'loading') {
        buttonEl = (_jsxs("button", { type: "button", disabled: true, className: cn(baseClass, 'cursor-wait opacity-60', className), children: [_jsx(Loader2, { className: "size-3 animate-spin" }), _jsx("span", { children: "Publish to GitHub" })] }));
    }
    else if (state.kind === 'not-signed-in') {
        buttonEl = (_jsxs("button", { type: "button", onClick: runSignIn, disabled: disabled, className: cn(baseClass, 'border-primary text-primary hover:bg-primary/10 cursor-pointer', className), title: "Sign in with GitHub to enable publishing", children: [_jsx(GitHubIcon, { className: "size-3" }), _jsx("span", { children: "Sign in with GitHub" })] }));
    }
    else if (state.kind === 'signing-in') {
        buttonEl = (_jsxs("button", { type: "button", disabled: true, className: cn(baseClass, 'border-primary text-primary cursor-wait', className), title: "Waiting for the GitHub sign-in to complete", children: [_jsx(Loader2, { className: "size-3 animate-spin" }), _jsx("span", { children: "Waiting for sign-in\u2026" })] }));
    }
    else if (state.kind === 'failed') {
        buttonEl = (_jsxs("button", { type: "button", onClick: () => void refresh(), disabled: disabled, className: cn(baseClass, 'border-destructive text-destructive hover:bg-destructive/10 cursor-pointer', className), title: "Retry publishing \u2014 full details available in the operation logs", children: [_jsx(TriangleAlert, { className: "size-3" }), _jsx("span", { children: "Retry publish" })] }));
    }
    else {
        // state.kind === 'ready'
        buttonEl = (_jsxs("button", { type: "button", onClick: () => setModalOpen(true), disabled: disabled, className: cn(baseClass, interactiveHover, className), title: "Publish this app to GitHub", children: [_jsx(GitBranch, { className: "size-3" }), _jsx("span", { children: "Publish to GitHub" })] }));
    }
    const logsIconState = state.kind === 'signing-in'
        ? 'running'
        : state.kind === 'failed'
            ? 'failed'
            : state.kind === 'has-remote'
                ? 'success'
                : 'idle';
    // The logs affordance is intentionally hidden in the two earliest states
    // (loading / not-signed-in) where there's nothing meaningful to show yet.
    const showLogsAffordance = state.kind === 'failed' || state.kind === 'has-remote' || state.kind === 'signing-in';
    return (_jsxs("div", { className: "inline-flex items-center gap-1", children: [buttonEl, showLogsAffordance ? (_jsx(OperationLogsIconButton, { state: logsIconState, onClick: () => setLogsOpen(true), label: "View publish logs" })) : null, state.kind === 'ready' ? (_jsx(PublishToGitHubModal, { open: modalOpen, onOpenChange: setModalOpen, owners: state.owners, defaultRepoName: defaultRepoName, onSubmit: runPublish })) : null, _jsx(OperationLogsDrawer, { open: logsOpen, onOpenChange: setLogsOpen, kind: "GitRemoteCreate", operationId: applicationId, title: "Publish to GitHub logs", subtitle: defaultRepoName, isRunning: state.kind === 'signing-in' })] }));
}
