'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
 * DeployPanel — rich content rendered inside the SmartDeployButton's
 * popover. Two unified rows (GitHub backup, cloud host) that map to the
 * user's mental model of "where my code is saved" + "where my site is
 * live". Every row is the same shape: brand icon on the left, title +
 * status subtitle in the middle, compact icon-only actions on the right.
 *
 * Visual language borrowed from the Codex/OpenAI app: neutral chrome,
 * brand colors carried ONLY by the leading icons, one accent pill per
 * row for active status, and icon-only action buttons instead of wide
 * colored CTAs. No nested amber-on-emerald-on-primary chip pileup.
 *
 * The panel is purely presentational — it composes hooks owned by the
 * SmartDeployButton's parent. All click handlers are passed in as props
 * so this file stays a thin renderer that's trivial to story-test.
 */
import { useState } from 'react';
import { AlertTriangle, ArrowLeft, ArrowUpRight, Cloud, ExternalLink, RefreshCw, Rocket, Save, ScrollText, XCircle, } from 'lucide-react';
import { cn } from '../../../lib/utils.js';
import { ProviderList } from './provider-list.js';
import { CLOUD_PROVIDER_BRAND_HEX, CLOUD_PROVIDER_ICONS, GitHubIcon } from './cloud-provider-icons.js';
import { PublishToGitHubForm } from './publish-to-github-modal.js';
function ServiceRow({ Icon, brandHex, title, subtitle, href, status, statusLabel, actions, expansion, }) {
    const statusClass = status ? STATUS_PILL_CLASSES[status] : undefined;
    const titleNode = href ? (_jsxs("a", { href: href, target: "_blank", rel: "noopener noreferrer", className: "hover:text-primary inline-flex items-center gap-1 truncate transition-colors", title: href, children: [_jsx("span", { className: "truncate", children: title }), _jsx(ExternalLink, { className: "size-3 shrink-0 opacity-60" })] })) : (_jsx("span", { className: "truncate", children: title }));
    return (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-3", children: [_jsx(Icon, { className: "size-5 shrink-0", style: brandHex ? { color: brandHex } : undefined }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-foreground truncate text-[12px] font-medium", children: titleNode }), subtitle ? (_jsx("div", { className: "text-muted-foreground truncate text-[10px]", children: subtitle })) : null] }), status && statusLabel ? (_jsx("span", { className: cn('hidden shrink-0 rounded-full px-1.5 py-0.5 text-[9px] font-semibold tracking-wide whitespace-nowrap uppercase sm:inline-block', statusClass), children: statusLabel })) : null, _jsx("div", { className: "flex shrink-0 items-center gap-0.5", children: actions })] }), expansion] }));
}
const STATUS_PILL_CLASSES = {
    live: 'bg-emerald-500/10 text-emerald-700 dark:text-emerald-400',
    dirty: 'bg-amber-500/10 text-amber-700 dark:text-amber-400',
    off: 'bg-muted text-muted-foreground',
    working: 'bg-primary/10 text-primary',
    failed: 'bg-destructive/10 text-destructive',
};
/**
 * Compact icon-only action button. Codex style — square, neutral by
 * default, primary tinted only when `variant="primary"`. Always carries
 * a `title` attribute so it doubles as a tooltip.
 */
function IconAction({ icon: Icon, label, onClick, variant = 'default', disabled, }) {
    const variantClass = {
        default: 'text-muted-foreground hover:text-foreground hover:bg-accent',
        primary: 'text-primary hover:bg-primary/10',
    }[variant];
    return (_jsx("button", { type: "button", onClick: onClick, disabled: disabled, "aria-label": label, title: label, className: cn('inline-flex size-7 cursor-pointer items-center justify-center rounded-md transition-colors', variantClass, disabled && 'cursor-not-allowed opacity-50'), children: _jsx(Icon, { className: "size-3.5" }) }));
}
export function DeployPanel({ state, gitStatus, cloudDeploy, cloudProviderName, lastDeployedAgo, providers, providersLoading = false, providersError = null, publishOwners = null, publishDefaultRepoName = '', onPublishSubmit, onSaveChanges, onPublishToWeb, onRedeploy, onSetUpCodeStorage, onSelectProvider, onConnectProvider, onEditConnection, onOpenLogs, onOpenInGitHub, }) {
    const hasRemote = state.hasRemote;
    const hasCloud = state.hasCloud;
    const liveUrl = state.liveUrl ?? cloudDeploy.state.url;
    const isWorking = state.kind === 'working' || cloudDeploy.state.isWorking || state.kind === 'loading';
    // ── Inline subpanel state (publish-to-github) ─────────────
    // Rendered as a slide-in view that replaces the main two-row panel
    // body when the user clicks "Set up code backup" on the GitHub row.
    // Kept local to the panel so the parent doesn't need to track it.
    const [subpanel, setSubpanel] = useState('main');
    const canInlinePublish = Boolean(publishOwners && onPublishSubmit);
    const handleOpenPublishSubpanel = () => {
        if (canInlinePublish) {
            setSubpanel('publish');
        }
        else {
            // Orgs fetch still in-flight — fall back to the legacy modal
            // path so the button is never a dead click.
            onSetUpCodeStorage();
        }
    };
    const handleClosePublishSubpanel = () => setSubpanel('main');
    // Pull a friendly repo display name out of the remote URL —
    // "https://github.com/owner/repo.git" → "owner/repo".
    const remoteDisplay = gitStatus?.remoteUrl ? prettyRepoName(gitStatus.remoteUrl) : null;
    // ── Derive the GitHub row state ────────────────────────────
    const gitDirtyCount = gitStatus
        ? gitStatus.uncommittedCount + gitStatus.unpushedCount
        : state.changeCount;
    const gitSubtitle = hasRemote
        ? gitStatus
            ? gitStatus.uncommittedCount > 0
                ? `${gitStatus.uncommittedCount} unsaved change${gitStatus.uncommittedCount === 1 ? '' : 's'}`
                : gitStatus.unpushedCount > 0
                    ? `${gitStatus.unpushedCount} change${gitStatus.unpushedCount === 1 ? '' : 's'} ready to push`
                    : 'Up to date'
            : 'Loading…'
        : 'Save your code online so you never lose it';
    const gitTitle = hasRemote && remoteDisplay ? remoteDisplay : 'No backup yet';
    const gitHref = hasRemote ? normalizeRemoteHref(gitStatus?.remoteUrl ?? null) : undefined;
    const gitStatus_ = !hasRemote
        ? 'off'
        : gitDirtyCount > 0
            ? 'dirty'
            : 'live';
    const gitStatusLabel = !hasRemote
        ? 'Off'
        : gitDirtyCount > 0
            ? `${gitDirtyCount} pending`
            : 'In sync';
    // ── Derive the cloud host row state ────────────────────────
    const hostTitle = cloudProviderName ?? 'Cloudflare Pages';
    const hostSubtitle = hasCloud
        ? liveUrl
            ? `Last published ${lastDeployedAgo ?? 'just now'}`
            : 'Connected — not yet published'
        : 'Click to connect a hosting provider';
    const hostStatus = isWorking
        ? 'working'
        : state.kind === 'failed' && state.failedSource === 'deploy'
            ? 'failed'
            : !hasCloud
                ? 'off'
                : liveUrl
                    ? state.changeCount > 0 && hasRemote
                        ? 'dirty'
                        : 'live'
                    : 'off';
    const hostStatusLabel = isWorking
        ? 'Working'
        : state.kind === 'failed' && state.failedSource === 'deploy'
            ? 'Failed'
            : !hasCloud
                ? 'Off'
                : liveUrl
                    ? state.changeCount > 0 && hasRemote
                        ? 'Out of sync'
                        : 'Live'
                    : 'Ready';
    // Prefer the real connected provider's brand icon over the
    // generic Cloud lucide when available.
    const selectedProviderId = cloudDeploy.state.provider ?? null;
    const HostIcon = selectedProviderId && CLOUD_PROVIDER_ICONS[selectedProviderId]
        ? CLOUD_PROVIDER_ICONS[selectedProviderId]
        : Cloud;
    const hostBrandHex = selectedProviderId
        ? CLOUD_PROVIDER_BRAND_HEX[selectedProviderId]
        : undefined;
    // ── Subpanel: publish to GitHub ──────────────────────────
    // Slide-in view that replaces the two-row main body with the
    // PublishToGitHubForm. Keeps the user inside the popover instead of
    // popping a separate Radix Dialog on top of it.
    if (subpanel === 'publish' && publishOwners && onPublishSubmit) {
        return (_jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-2", children: [_jsx("button", { type: "button", onClick: handleClosePublishSubpanel, "aria-label": "Back", className: "text-muted-foreground hover:text-foreground hover:bg-accent inline-flex size-7 cursor-pointer items-center justify-center rounded-md transition-colors", children: _jsx(ArrowLeft, { className: "size-3.5" }) }), _jsx(GitHubIcon, { className: "size-4 shrink-0" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-foreground text-[12px] font-semibold", children: "Set up code backup" }), _jsx("div", { className: "text-muted-foreground truncate text-[10px]", children: "Publish to GitHub so you never lose your work" })] })] }), _jsx(PublishToGitHubForm, { owners: publishOwners.slice(), defaultRepoName: publishDefaultRepoName, variant: "subpanel", onSubmit: async (input) => {
                        await onPublishSubmit(input);
                        // Success → drop back to the main view. Errors are caught
                        // inside the form and surfaced as inline validation
                        // without closing the subpanel.
                        handleClosePublishSubpanel();
                    }, onCancel: handleClosePublishSubpanel })] }));
    }
    return (_jsxs("div", { className: "flex flex-col divide-y", children: [_jsx(ServiceRow, { Icon: GitHubIcon, title: gitTitle, subtitle: gitSubtitle, href: gitHref, status: gitStatus_, statusLabel: gitStatusLabel, actions: hasRemote ? (_jsxs(_Fragment, { children: [_jsx(IconAction, { icon: Save, label: gitDirtyCount > 0
                                ? `Save ${gitDirtyCount} change${gitDirtyCount === 1 ? '' : 's'}`
                                : 'Nothing to save', onClick: onSaveChanges, variant: gitDirtyCount > 0 ? 'primary' : 'default', disabled: isWorking || gitDirtyCount === 0 }), _jsx(IconAction, { icon: ArrowUpRight, label: "Open in GitHub", onClick: onOpenInGitHub })] })) : (_jsx(IconAction, { icon: GitHubIcon, label: "Set up code backup", onClick: handleOpenPublishSubpanel, variant: "primary" })) }), _jsx(ServiceRow, { Icon: HostIcon, brandHex: hostBrandHex, title: hostTitle, subtitle: hostSubtitle, href: liveUrl ?? undefined, status: hostStatus, statusLabel: hostStatusLabel, actions: hasCloud ? (_jsxs(_Fragment, { children: [_jsx(IconAction, { icon: liveUrl ? RefreshCw : Rocket, label: liveUrl ? 'Republish' : 'Publish to web', onClick: liveUrl ? onRedeploy : onPublishToWeb, variant: "primary", disabled: isWorking }), _jsx(IconAction, { icon: ScrollText, label: "Activity log", onClick: onOpenLogs })] })) : (_jsx(IconAction, { icon: Cloud, label: "Connect hosting", onClick: () => {
                        const firstEnabled = providers.find((p) => p.enabled);
                        if (firstEnabled)
                            onConnectProvider(firstEnabled.id);
                    }, variant: "primary", disabled: isWorking })), expansion: _jsx("div", { className: "px-4 pb-3", children: _jsx(ProviderList, { providers: providers, selectedProvider: selectedProviderId, loading: providersLoading, loadError: providersError, 
                        // The cloud host ServiceRow above already renders the
                        // currently-selected provider as its own main row. Tell
                        // the provider list to hide it so we don't render two
                        // "Cloudflare Pages" rows stacked on top of each other —
                        // the user just sees a "Change provider" chevron that
                        // reveals the alternatives (and "Coming soon" stubs)
                        // when clicked.
                        hideSelected: true, onSelectConnected: onSelectProvider, onSelectDisconnected: onConnectProvider, onEditConnection: onEditConnection }) }) }), state.kind === 'failed' && state.failedSource === 'deploy' ? (_jsxs("div", { className: "text-destructive flex items-start gap-1.5 px-4 py-2 text-[10px]", children: [_jsx(XCircle, { className: "mt-0.5 size-3 shrink-0" }), _jsx("span", { className: "break-words", children: state.errorMessage })] })) : state.kind === 'failed' && state.failedSource === 'sync' ? (_jsxs("div", { className: "text-destructive flex items-start gap-1.5 px-4 py-2 text-[10px]", children: [_jsx(AlertTriangle, { className: "mt-0.5 size-3 shrink-0" }), _jsx("span", { className: "break-words", children: state.errorMessage })] })) : null] }));
}
/** "https://github.com/owner/repo(.git)?" → "owner/repo". */
function prettyRepoName(remoteUrl) {
    try {
        const url = new URL(remoteUrl);
        const path = url.pathname.replace(/^\//, '').replace(/\.git$/, '');
        return path || url.host;
    }
    catch {
        // SSH-form like "git@github.com:owner/repo.git"
        const m = remoteUrl.match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
        return m?.[1] ?? remoteUrl;
    }
}
/** Normalize SSH form to https for click-to-open. */
function normalizeRemoteHref(remoteUrl) {
    if (!remoteUrl)
        return undefined;
    if (remoteUrl.startsWith('http'))
        return remoteUrl.replace(/\.git$/, '');
    const m = remoteUrl.match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
    return m ? `https://github.com/${m[1]}` : undefined;
}
