import { useCallback, useMemo, useState } from 'react';
import { FolderPlus, X } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import ErrorBanner from './components/ErrorBanner';
import StepConfiguration from './components/StepConfiguration';
import StepReview from './components/StepReview';
import StepTypeSelection from './components/StepTypeSelection';
import WizardFooter from './components/WizardFooter';
import WizardProgress from './components/WizardProgress';
import { useGithubTokens } from './hooks/useGithubTokens';
import { cloneWorkspaceWithProgress, createWorkspaceRequest } from './data/workspaceApi';
import { isCloneWorkflow, shouldShowGithubAuthentication } from './utils/pathUtils';
import type { TokenMode, WizardFormState, WizardStep, WorkspaceType } from './types';
type ProjectCreationWizardProps = {
onClose: () => void;
onProjectCreated?: (project?: Record<string, unknown>) => void;
};
const initialFormState: WizardFormState = {
workspaceType: 'existing',
workspacePath: '',
githubUrl: '',
tokenMode: 'stored',
selectedGithubToken: '',
newGithubToken: '',
};
export default function ProjectCreationWizard({
onClose,
onProjectCreated,
}: ProjectCreationWizardProps) {
const { t } = useTranslation();
const [step, setStep] = useState<WizardStep>(1);
const [formState, setFormState] = useState<WizardFormState>(initialFormState);
const [isCreating, setIsCreating] = useState(false);
const [error, setError] = useState<string | null>(null);
const [cloneProgress, setCloneProgress] = useState('');
const shouldLoadTokens =
step === 2 && shouldShowGithubAuthentication(formState.workspaceType, formState.githubUrl);
const autoSelectToken = useCallback((tokenId: string) => {
setFormState((previous) => ({ ...previous, selectedGithubToken: tokenId }));
}, []);
const {
tokens: availableTokens,
loading: loadingTokens,
loadError: tokenLoadError,
selectedTokenName,
} = useGithubTokens({
shouldLoad: shouldLoadTokens,
selectedTokenId: formState.selectedGithubToken,
onAutoSelectToken: autoSelectToken,
});
const updateField = useCallback(<K extends keyof WizardFormState>(key: K, value: WizardFormState[K]) => {
setFormState((previous) => ({ ...previous, [key]: value }));
}, []);
const updateWorkspaceType = useCallback(
(workspaceType: WorkspaceType) => updateField('workspaceType', workspaceType),
[updateField],
);
const updateTokenMode = useCallback(
(tokenMode: TokenMode) => updateField('tokenMode', tokenMode),
[updateField],
);
const handleNext = useCallback(() => {
setError(null);
if (step === 1) {
if (!formState.workspaceType) {
setError(t('projectWizard.errors.selectType'));
return;
}
setStep(2);
return;
}
if (step === 2) {
if (!formState.workspacePath.trim()) {
setError(t('projectWizard.errors.providePath'));
return;
}
setStep(3);
}
}, [formState.workspacePath, formState.workspaceType, step, t]);
const handleBack = useCallback(() => {
setError(null);
setStep((previousStep) => (previousStep > 1 ? ((previousStep - 1) as WizardStep) : previousStep));
}, []);
const handleCreate = useCallback(async () => {
setIsCreating(true);
setError(null);
setCloneProgress('');
try {
const shouldCloneRepository = isCloneWorkflow(formState.workspaceType, formState.githubUrl);
if (shouldCloneRepository) {
const project = await cloneWorkspaceWithProgress(
{
workspacePath: formState.workspacePath,
githubUrl: formState.githubUrl,
tokenMode: formState.tokenMode,
selectedGithubToken: formState.selectedGithubToken,
newGithubToken: formState.newGithubToken,
},
{
onProgress: setCloneProgress,
},
);
onProjectCreated?.(project);
onClose();
return;
}
const project = await createWorkspaceRequest({
workspaceType: formState.workspaceType,
path: formState.workspacePath.trim(),
});
onProjectCreated?.(project);
onClose();
} catch (createError) {
const errorMessage =
createError instanceof Error
? createError.message
: t('projectWizard.errors.failedToCreate');
setError(errorMessage);
} finally {
setIsCreating(false);
}
}, [formState, onClose, onProjectCreated, t]);
const shouldCloneRepository = useMemo(
() => isCloneWorkflow(formState.workspaceType, formState.githubUrl),
[formState.githubUrl, formState.workspaceType],
);
return (
<div className="fixed bottom-0 left-0 right-0 top-0 z-[60] flex items-center justify-center bg-black/50 p-0 backdrop-blur-sm sm:p-4">
<div className="h-full w-full overflow-y-auto border-0 bg-card text-card-foreground shadow-xl sm:h-auto sm:max-w-2xl sm:rounded-xl sm:border sm:border-border">
<div className="flex items-center justify-between border-b border-border p-6">
<div className="flex items-center gap-3">
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-muted text-foreground">
<FolderPlus className="h-4 w-4" strokeWidth={1.75} />
</div>
<h3 className="text-lg font-semibold text-foreground">
{t('projectWizard.title')}
</h3>
</div>
<button
onClick={onClose}
className="rounded-md p-2 text-muted-foreground hover:bg-accent hover:text-foreground"
disabled={isCreating}
aria-label="Close"
>
<X className="h-5 w-5" strokeWidth={1.75} />
</button>
</div>
<WizardProgress step={step} />
<div className="min-h-[300px] space-y-6 p-6">
{error && <ErrorBanner message={error} />}
{step === 1 && (
<StepTypeSelection
workspaceType={formState.workspaceType}
onWorkspaceTypeChange={updateWorkspaceType}
/>
)}
{step === 2 && (
<StepConfiguration
workspaceType={formState.workspaceType}
workspacePath={formState.workspacePath}
githubUrl={formState.githubUrl}
tokenMode={formState.tokenMode}
selectedGithubToken={formState.selectedGithubToken}
newGithubToken={formState.newGithubToken}
availableTokens={availableTokens}
loadingTokens={loadingTokens}
tokenLoadError={tokenLoadError}
isCreating={isCreating}
onWorkspacePathChange={(workspacePath) => updateField('workspacePath', workspacePath)}
onGithubUrlChange={(githubUrl) => updateField('githubUrl', githubUrl)}
onTokenModeChange={updateTokenMode}
onSelectedGithubTokenChange={(selectedGithubToken) =>
updateField('selectedGithubToken', selectedGithubToken)
}
onNewGithubTokenChange={(newGithubToken) =>
updateField('newGithubToken', newGithubToken)
}
onAdvanceToConfirm={() => setStep(3)}
/>
)}
{step === 3 && (
<StepReview
formState={formState}
selectedTokenName={selectedTokenName}
isCreating={isCreating}
cloneProgress={cloneProgress}
/>
)}
</div>
<WizardFooter
step={step}
isCreating={isCreating}
isCloneWorkflow={shouldCloneRepository}
onClose={onClose}
onBack={handleBack}
onNext={handleNext}
onCreate={handleCreate}
/>
</div>
</div>
);
}