'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useCallback, useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { PaperclipIcon, ChevronsUpDown, CheckIcon, Zap, Clock, FolderPlus, Loader2, GitFork, FileText, Puzzle, RefreshCw, LayoutGrid, ClipboardList, } from 'lucide-react';
import { cn } from '../../../lib/utils.js';
import { useSoundAction } from '../../../hooks/use-sound-action.js';
import { BaseDrawer } from '../../common/base-drawer/index.js';
import { DrawerTitle, DrawerDescription } from '../../ui/drawer.js';
import { Button } from '../../ui/button.js';
import { Input } from '../../ui/input.js';
import { Textarea } from '../../ui/textarea.js';
import { Label } from '../../ui/label.js';
import { Badge } from '../../ui/badge.js';
import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover.js';
import { Switch } from '../../ui/switch.js';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip.js';
import { useGuardedDrawerClose } from '../../../hooks/drawer-close-guard.js';
import { AttachmentChip } from '../../common/attachment-chip/index.js';
import { getViewerPermission } from '../../../app/actions/get-viewer-permission.js';
import { AgentModelPicker } from '../../features/settings/AgentModelPicker/index.js';
import { Separator } from '../../ui/separator.js';
import { pickFolder } from '../../common/add-repository-button/pick-folder.js';
import { ReactFileManagerDialog } from '../../common/react-file-manager-dialog/index.js';
import { useFeatureFlags } from '../../../hooks/feature-flags-context.js';
import { addRepository } from '../../../app/actions/add-repository.js';
import { BuildMode as BuildModeEnum } from '../../../../../../packages/core/src/domain/generated/output.js';
import { pickFiles } from './pick-files.js';
const BUILD_MODE_ORDER = [BuildModeEnum.Fast, BuildModeEnum.Spec];
const BUILD_MODE_META = {
    // Application is retained in the meta map only so legacy `buildMode='application'`
    // rows do not crash if they ever flow through this path; it is never rendered.
    [BuildModeEnum.Application]: { icon: LayoutGrid, labelKey: 'createDrawer.modeApplication' },
    [BuildModeEnum.Fast]: { icon: Zap, labelKey: 'createDrawer.modeFast' },
    [BuildModeEnum.Spec]: { icon: ClipboardList, labelKey: 'createDrawer.modeSpec' },
};
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
const ALLOWED_EXTENSIONS = new Set([
    '.png',
    '.jpg',
    '.jpeg',
    '.gif',
    '.webp',
    '.svg',
    '.bmp',
    '.ico',
    '.pdf',
    '.doc',
    '.docx',
    '.xls',
    '.xlsx',
    '.ppt',
    '.pptx',
    '.txt',
    '.md',
    '.csv',
    '.json',
    '.yaml',
    '.yml',
    '.xml',
    '.ts',
    '.tsx',
    '.js',
    '.jsx',
    '.py',
    '.rb',
    '.go',
    '.rs',
    '.java',
    '.c',
    '.cpp',
    '.h',
    '.hpp',
    '.cs',
    '.swift',
    '.kt',
    '.html',
    '.css',
    '.scss',
    '.less',
    '.sh',
    '.bash',
    '.zsh',
    '.fish',
    '.toml',
    '.ini',
    '.cfg',
    '.conf',
    '.env',
    '.zip',
    '.tar',
    '.gz',
    '.log',
]);
function getExtension(filename) {
    const dot = filename.lastIndexOf('.');
    return dot >= 0 ? filename.slice(dot).toLowerCase() : '';
}
const EMPTY_GATES = {
    allowPrd: false,
    allowPlan: false,
    allowMerge: false,
};
function resolveInitialMode(initialMode, workflowDefaults) {
    if (initialMode)
        return initialMode;
    if (workflowDefaults?.fast === false)
        return BuildModeEnum.Spec;
    return BuildModeEnum.Fast;
}
export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, isSubmitting = false, workflowDefaults, features, repositories, initialParentId, currentAgentType, currentModel, initialDescription, canPushDirectly, initialMode, initialApplicationId, }) {
    const isAppScoped = initialApplicationId !== undefined;
    // App-scoped invocations seed the picker with `Spec` (the SDD intent) so
    // the easy path matches the entry-point name, but the picker remains
    // user-editable: launching a feature against an application should feel
    // like launching one against a regular repository.
    const effectiveInitialMode = isAppScoped && !initialMode ? BuildModeEnum.Spec : initialMode;
    const createSound = useSoundAction('create');
    const { t } = useTranslation('web');
    // Validate repositoryPath from URL against active repos — prevents stale URL params
    // from selecting deleted repos after add/delete/re-add cycles.
    // Trust the prop when: app-scoped (the application is the authority on its
    // own repo path, even if that path is not a registered Repository entity),
    // repos not loaded yet (undefined), empty list (no repos to check), or the
    // path matches an active repo.
    const validRepoPath = !repositoryPath
        ? ''
        : isAppScoped ||
            !repositories ||
            repositories.length === 0 ||
            repositories.some((r) => r.path === repositoryPath)
            ? repositoryPath
            : '';
    const defaultGates = workflowDefaults?.approvalGates ?? EMPTY_GATES;
    const defaultPush = workflowDefaults?.push ?? false;
    const defaultOpenPr = workflowDefaults?.openPr ?? false;
    const defaultCiWatch = workflowDefaults?.ciWatchEnabled !== false;
    const defaultEnableEvidence = workflowDefaults?.enableEvidence ?? false;
    const defaultCommitEvidence = workflowDefaults?.commitEvidence ?? false;
    const defaultMode = resolveInitialMode(effectiveInitialMode, workflowDefaults);
    const [description, setDescription] = useState(initialDescription ?? '');
    // Sync description when initialDescription prop changes (e.g. from session context)
    useEffect(() => {
        if (initialDescription) {
            setDescription(initialDescription);
        }
    }, [initialDescription]);
    const [attachments, setAttachments] = useState([]);
    const [approvalGates, setApprovalGates] = useState({ ...defaultGates });
    const [push, setPush] = useState(defaultPush);
    const [openPr, setOpenPr] = useState(defaultOpenPr);
    const [ciWatchEnabled, setCiWatchEnabled] = useState(workflowDefaults?.ciWatchEnabled !== false);
    const [enableEvidence, setEnableEvidence] = useState(defaultEnableEvidence);
    const [commitEvidence, setCommitEvidence] = useState(defaultCommitEvidence);
    const [parentId, setParentId] = useState(undefined);
    const [mode, setMode] = useState(defaultMode);
    const fast = mode === BuildModeEnum.Fast;
    const [pending, setPending] = useState(false);
    const [forkAndPr, setForkAndPr] = useState(false);
    const [commitSpecs, setCommitSpecs] = useState(true);
    const [rebaseBeforeBranch, setRebaseBeforeBranch] = useState(true);
    const [injectSkills, setInjectSkills] = useState(workflowDefaults?.injectSkills ?? false);
    const [overrideAgent, setOverrideAgent] = useState(undefined);
    const [overrideModel, setOverrideModel] = useState(undefined);
    const [selectedRepoPath, setSelectedRepoPath] = useState(validRepoPath || undefined);
    const [localRepos, setLocalRepos] = useState(repositories ?? []);
    const [isDragOver, setIsDragOver] = useState(false);
    const [uploadError, setUploadError] = useState(null);
    const [isPromptFocused, setIsPromptFocused] = useState(false);
    // Stable sessionId per mount — used for upload dedup grouping
    const sessionIdRef = useRef(crypto.randomUUID());
    const dragCounterRef = useRef(0);
    const promptContainerRef = useRef(null);
    // Sync state when workflowDefaults load asynchronously. Mode is only
    // re-synced from defaults when the caller did NOT pin an explicit
    // initialMode (or app-scoped Spec lock) — pinned modes win over async
    // defaults.
    useEffect(() => {
        if (workflowDefaults) {
            setApprovalGates({ ...workflowDefaults.approvalGates });
            setPush(workflowDefaults.push);
            setOpenPr(workflowDefaults.openPr);
            setCiWatchEnabled(workflowDefaults.ciWatchEnabled !== false);
            setEnableEvidence(workflowDefaults.enableEvidence);
            setCommitEvidence(workflowDefaults.commitEvidence);
            if (!effectiveInitialMode) {
                setMode(workflowDefaults.fast !== false ? BuildModeEnum.Fast : BuildModeEnum.Spec);
            }
            setInjectSkills(workflowDefaults.injectSkills ?? false);
        }
    }, [workflowDefaults, effectiveInitialMode]);
    // Sync localRepos when repositories prop changes
    useEffect(() => {
        setLocalRepos(repositories ?? []);
    }, [repositories]);
    // Pre-select parent when initialParentId changes (e.g. (+) button on feature node)
    useEffect(() => {
        if (open && initialParentId) {
            setParentId(initialParentId);
        }
    }, [open, initialParentId]);
    // Permission-aware Fork & PR toggle visibility
    const [canPush, setCanPush] = useState(canPushDirectly ?? false);
    // Sync canPush from prop when it changes (e.g. initial server-side value)
    useEffect(() => {
        setCanPush(canPushDirectly ?? false);
    }, [canPushDirectly]);
    // Re-check permission when user switches repos via the combobox
    const prevRepoRef = useRef(selectedRepoPath);
    useEffect(() => {
        if (selectedRepoPath && selectedRepoPath !== prevRepoRef.current) {
            prevRepoRef.current = selectedRepoPath;
            getViewerPermission(selectedRepoPath)
                .then((result) => setCanPush(result.canPushDirectly))
                .catch(() => setCanPush(false));
        }
    }, [selectedRepoPath]);
    // Auto-reset forkAndPr and dependent states when canPush becomes true
    useEffect(() => {
        if (canPush) {
            setForkAndPr(false);
            setPush(defaultPush);
            setOpenPr(defaultOpenPr);
            setCommitSpecs(true);
        }
    }, [canPush, defaultPush, defaultOpenPr]);
    const resetForm = useCallback(() => {
        setDescription('');
        setAttachments([]);
        setApprovalGates({ ...defaultGates });
        setPush(defaultPush);
        setOpenPr(defaultOpenPr);
        setCiWatchEnabled(defaultCiWatch);
        setEnableEvidence(defaultEnableEvidence);
        setCommitEvidence(defaultCommitEvidence);
        setParentId(undefined);
        setSelectedRepoPath(validRepoPath || undefined);
        setLocalRepos(repositories ?? []);
        setMode(defaultMode);
        setPending(false);
        setForkAndPr(false);
        setCommitSpecs(true);
        setRebaseBeforeBranch(true);
        setOverrideAgent(undefined);
        setOverrideModel(undefined);
        setUploadError(null);
        dragCounterRef.current = 0;
        setIsDragOver(false);
    }, [
        defaultGates,
        defaultPush,
        defaultOpenPr,
        defaultEnableEvidence,
        defaultCiWatch,
        defaultCommitEvidence,
        defaultMode,
        validRepoPath,
        repositories,
    ]);
    // Track whether the form has unsaved data
    const isDirty = description.trim() !== '' || attachments.length > 0;
    // Shared close guard — shows confirmation when dirty, prevents navigation
    const { attemptClose } = useGuardedDrawerClose({ open, isDirty, onClose, onReset: resetForm });
    /** Validate and upload files from drop or paste. */
    const handleFiles = useCallback(async (fileList) => {
        setUploadError(null);
        for (const file of fileList) {
            // Client-side size validation
            if (file.size > MAX_FILE_SIZE) {
                setUploadError(`"${file.name}" exceeds 10 MB limit`);
                return;
            }
            // Client-side extension validation
            const ext = getExtension(file.name);
            if (ext && !ALLOWED_EXTENSIONS.has(ext)) {
                setUploadError(`File type "${ext}" is not allowed`);
                return;
            }
        }
        for (const file of fileList) {
            const tempId = crypto.randomUUID();
            // Optimistic loading placeholder
            setAttachments((prev) => [
                ...prev,
                {
                    id: tempId,
                    name: file.name,
                    size: file.size,
                    mimeType: file.type || 'application/octet-stream',
                    path: '',
                    loading: true,
                },
            ]);
            try {
                const formData = new FormData();
                formData.append('file', file);
                formData.append('sessionId', sessionIdRef.current);
                const res = await fetch('/api/attachments/upload', {
                    method: 'POST',
                    body: formData,
                });
                if (!res.ok) {
                    const body = await res.json().catch(() => ({ error: 'Upload failed' }));
                    // Remove loading placeholder on error
                    setAttachments((prev) => prev.filter((a) => a.id !== tempId));
                    setUploadError(body.error ?? 'Upload failed');
                    return;
                }
                const uploaded = await res.json();
                // Server dedup may return the same path for identical content — drop the duplicate.
                setAttachments((prev) => {
                    const isDupe = prev.some((a) => a.id !== tempId && a.path === uploaded.path);
                    if (isDupe)
                        return prev.filter((a) => a.id !== tempId);
                    return prev.map((a) => a.id === tempId ? { ...uploaded, id: tempId, loading: false } : a);
                });
            }
            catch {
                setAttachments((prev) => prev.filter((a) => a.id !== tempId));
                setUploadError('Upload failed');
            }
        }
    }, []);
    const handleDragEnter = useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
        dragCounterRef.current += 1;
        if (dragCounterRef.current === 1) {
            setIsDragOver(true);
        }
    }, []);
    const handleDragLeave = useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
        dragCounterRef.current -= 1;
        if (dragCounterRef.current === 0) {
            setIsDragOver(false);
        }
    }, []);
    const handleDragOver = useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
    }, []);
    const handleDrop = useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
        dragCounterRef.current = 0;
        setIsDragOver(false);
        const files = Array.from(e.dataTransfer.files);
        if (files.length > 0) {
            handleFiles(files);
        }
    }, [handleFiles]);
    const handlePaste = useCallback((e) => {
        const items = e.clipboardData?.items;
        if (!items)
            return;
        const files = [];
        for (const item of Array.from(items)) {
            if (item.kind === 'file') {
                const file = item.getAsFile();
                if (file)
                    files.push(file);
            }
        }
        if (files.length > 0) {
            e.preventDefault();
            handleFiles(files);
        }
    }, [handleFiles]);
    const handleSubmit = useCallback((e) => {
        e.preventDefault();
        if (!description.trim())
            return;
        const effectiveRepoPath = selectedRepoPath ?? validRepoPath;
        if (!effectiveRepoPath)
            return;
        createSound.play();
        onSubmit({
            description: description.trim(),
            attachments: attachments.filter((a) => !a.loading),
            repositoryPath: effectiveRepoPath,
            approvalGates: {
                allowPrd: approvalGates.allowPrd ?? false,
                allowPlan: approvalGates.allowPlan ?? false,
                allowMerge: approvalGates.allowMerge ?? false,
            },
            push: forkAndPr ? true : push || openPr,
            openPr: forkAndPr ? true : openPr,
            ciWatchEnabled,
            enableEvidence,
            commitEvidence,
            fast,
            forkAndPr,
            commitSpecs,
            rebaseBeforeBranch,
            injectSkills,
            ...(pending ? { pending } : {}),
            ...(overrideAgent ? { agentType: overrideAgent } : {}),
            ...(overrideModel ? { model: overrideModel } : {}),
            ...(parentId ? { parentId } : {}),
            ...(initialApplicationId ? { applicationId: initialApplicationId } : {}),
            sessionId: sessionIdRef.current,
        });
        resetForm();
    }, [
        description,
        attachments,
        approvalGates,
        selectedRepoPath,
        validRepoPath,
        onSubmit,
        push,
        openPr,
        enableEvidence,
        ciWatchEnabled,
        commitEvidence,
        fast,
        forkAndPr,
        commitSpecs,
        rebaseBeforeBranch,
        injectSkills,
        pending,
        overrideAgent,
        overrideModel,
        parentId,
        initialApplicationId,
        createSound,
        resetForm,
    ]);
    const handleAddFiles = useCallback(async () => {
        try {
            const files = await pickFiles();
            if (!files)
                return;
            for (const file of files) {
                const tempId = crypto.randomUUID();
                setAttachments((prev) => [
                    ...prev,
                    {
                        id: tempId,
                        name: file.name,
                        size: file.size,
                        mimeType: 'application/octet-stream',
                        path: '',
                        loading: true,
                    },
                ]);
                try {
                    const res = await fetch('/api/attachments/upload-from-path', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ path: file.path, sessionId: sessionIdRef.current }),
                    });
                    if (!res.ok) {
                        const body = await res.json().catch(() => ({ error: 'Upload failed' }));
                        setAttachments((prev) => prev.filter((a) => a.id !== tempId));
                        setUploadError(body.error ?? 'Upload failed');
                        return;
                    }
                    const uploaded = await res.json();
                    setAttachments((prev) => {
                        const isDupe = prev.some((a) => a.id !== tempId && a.path === uploaded.path);
                        if (isDupe)
                            return prev.filter((a) => a.id !== tempId);
                        return prev.map((a) => a.id === tempId ? { ...uploaded, id: tempId, loading: false } : a);
                    });
                }
                catch {
                    setAttachments((prev) => prev.filter((a) => a.id !== tempId));
                    setUploadError('Upload failed');
                }
            }
        }
        catch {
            // Native dialog failed — silently ignore (user can retry)
        }
    }, []);
    const handleRemoveFile = useCallback((id) => {
        setAttachments((prev) => prev.filter((f) => f.id !== id));
    }, []);
    const handleNotesChange = useCallback((id, notes) => {
        setAttachments((prev) => prev.map((f) => (f.id === id ? { ...f, notes } : f)));
    }, []);
    const formRef = useRef(null);
    const handleKeyDown = useCallback((e) => {
        if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
            e.preventDefault();
            formRef.current?.requestSubmit();
        }
    }, []);
    const handlePromptFocus = useCallback(() => {
        setIsPromptFocused(true);
    }, []);
    const handlePromptBlur = useCallback(() => {
        // Defer the check so focus has time to settle on the new target.
        // This correctly handles Radix portals (e.g. AgentModelPicker popover) that
        // render outside the container DOM but are logically part of the prompt area.
        setTimeout(() => {
            const withinContainer = promptContainerRef.current?.contains(document.activeElement);
            const pickerPopoverOpen = promptContainerRef.current?.querySelector('[aria-expanded="true"]') !== null;
            if (!withinContainer && !pickerPopoverOpen) {
                setIsPromptFocused(false);
            }
        }, 0);
    }, []);
    const hasFeatures = features && features.length > 0;
    const needsRepo = !validRepoPath && !selectedRepoPath;
    const showRepoSelector = !validRepoPath && repositories !== undefined;
    const AUTO_APPROVE_OPTIONS = [
        { id: 'allowPrd', label: t('createDrawer.prd'), description: t('createDrawer.prdDescription') },
        {
            id: 'allowPlan',
            label: t('createDrawer.plan'),
            description: t('createDrawer.planDescription'),
        },
        {
            id: 'allowMerge',
            label: t('createDrawer.merge'),
            description: t('createDrawer.mergeDescription'),
        },
    ];
    return (_jsx(BaseDrawer, { open: open, onClose: attemptClose, size: "md", modal: false, dismissOnOutsideClick: true, "data-testid": "feature-create-drawer", header: _jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-2.5 w-2.5 shrink-0 rounded-full bg-blue-500" }), _jsx(DrawerTitle, { children: t('createDrawer.title') })] }), isSubmitting ? (_jsx(DrawerDescription, { asChild: true, children: _jsx("div", { children: _jsx(Badge, { variant: "secondary", children: t('createDrawer.creating') }) }) })) : null] }), footer: _jsxs("div", { className: "flex flex-row justify-end gap-2", children: [_jsx(Button, { variant: "outline", onClick: attemptClose, disabled: isSubmitting, children: t('createDrawer.cancel') }), _jsx(Button, { type: "submit", form: "create-feature-form", disabled: !description.trim() || isSubmitting || needsRepo, children: isSubmitting ? t('createDrawer.creating') : t('createDrawer.createFeature') })] }), children: _jsx("div", { className: "overflow-y-auto p-4", children: _jsx(TooltipProvider, { delayDuration: 400, children: _jsxs("form", { ref: formRef, id: "create-feature-form", onSubmit: handleSubmit, onKeyDown: handleKeyDown, className: "flex flex-col gap-4", children: [isAppScoped ? (_jsxs("div", { className: "flex flex-col gap-1.5", "data-testid": "repo-readonly-section", "data-locked-by-application": "true", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: t('createDrawer.repository') }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("p", { className: "text-sm opacity-70", "data-testid": "repo-readonly-label", "aria-disabled": "true", "aria-describedby": "locked-by-application-tooltip", title: t('createDrawer.lockedByApplication'), children: repositories?.find((r) => r.path === validRepoPath)?.name ??
                                                    (validRepoPath ? validRepoPath.split('/').pop() : '') ??
                                                    validRepoPath }) }), _jsx(TooltipContent, { id: "locked-by-application-tooltip", role: "tooltip", side: "bottom", children: t('createDrawer.lockedByApplication') })] })] })) : showRepoSelector ? (_jsxs("div", { className: "flex flex-col gap-1.5", "data-testid": "repo-selector-section", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: t('createDrawer.repository') }), _jsx(RepositoryCombobox, { repositories: localRepos, value: selectedRepoPath, onChange: setSelectedRepoPath, onAddRepository: (repo) => {
                                        setLocalRepos((prev) => [...prev, repo]);
                                        setSelectedRepoPath(repo.path);
                                    }, disabled: isSubmitting })] })) : validRepoPath ? (_jsxs("div", { className: "flex flex-col gap-1.5", "data-testid": "repo-readonly-section", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: t('createDrawer.repository') }), _jsx("p", { className: "text-sm", "data-testid": "repo-readonly-label", children: repositories?.find((r) => r.path === validRepoPath)?.name ??
                                        validRepoPath.split('/').pop() })] })) : null, _jsxs("div", { role: "region", "aria-label": t('createDrawer.fileDropZone'), "data-drag-over": isDragOver ? 'true' : 'false', onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: cn('flex flex-col gap-1.5 rounded-md border-2 border-transparent p-1 transition-colors', isDragOver && 'border-primary/50 bg-primary/5'), children: [_jsx(Label, { htmlFor: "feature-description", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: t('createDrawer.describeFeature') }), _jsxs("div", { ref: promptContainerRef, onFocus: handlePromptFocus, onBlur: handlePromptBlur, className: cn('border-input flex h-56 flex-col overflow-hidden rounded-md border shadow-xs transition-[color,box-shadow]', isPromptFocused && 'ring-ring/50 border-ring ring-[3px]'), children: [_jsx(Textarea, { id: "feature-description", placeholder: t('createDrawer.featurePlaceholder'), value: description, onChange: (e) => setDescription(e.target.value), onPaste: handlePaste, required: true, disabled: isSubmitting, className: "min-h-0 flex-1 resize-none rounded-none border-0 shadow-none focus-visible:ring-0" }), attachments.length > 0 && (_jsx("div", { className: "flex flex-wrap items-center gap-1.5 px-3 py-2", children: attachments.map((file) => (_jsx(AttachmentChip, { name: file.name, size: file.size, mimeType: file.mimeType, path: file.path, onRemove: () => handleRemoveFile(file.id), disabled: isSubmitting, loading: file.loading, notes: file.notes, onNotesChange: (notes) => handleNotesChange(file.id, notes) }, file.id))) })), uploadError ? (_jsx("p", { className: "text-destructive px-3 pb-2 text-xs", children: uploadError })) : null, _jsxs("div", { className: "border-input flex items-center gap-3 border-t px-3 py-1.5", children: [_jsx(AgentModelPicker
                                                // No hardcoded `'claude-code'` fallback — `currentAgentType`
                                                // already comes from the user's settings via the create
                                                // drawer page's SSR pass (single source of truth). When
                                                // settings is absent (impossible in practice but kept
                                                // defensive), the picker shows an empty label and the
                                                // user can pick an agent explicitly.
                                                , { 
                                                    // No hardcoded `'claude-code'` fallback — `currentAgentType`
                                                    // already comes from the user's settings via the create
                                                    // drawer page's SSR pass (single source of truth). When
                                                    // settings is absent (impossible in practice but kept
                                                    // defensive), the picker shows an empty label and the
                                                    // user can pick an agent explicitly.
                                                    initialAgentType: overrideAgent ?? currentAgentType ?? '', initialModel: overrideModel ?? currentModel ?? '', mode: "override", onAgentModelChange: (agent, model) => {
                                                        setOverrideAgent(agent);
                                                        setOverrideModel(model);
                                                    }, disabled: isSubmitting, className: "w-55" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "ml-auto flex cursor-pointer items-center gap-2", children: [_jsx(Switch, { id: "pending-mode", checked: pending, onCheckedChange: setPending, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "pending-mode", className: "flex cursor-pointer items-center gap-1 text-sm font-medium", children: [_jsx(Clock, { className: "h-3.5 w-3.5" }), t('createDrawer.pendingMode')] })] }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.pendingModeDescription') })] }), _jsx("div", { role: "group", "aria-label": t('createDrawer.modeGroupLabel'), className: "border-input flex items-center gap-0.5 rounded-md border p-0.5", children: BUILD_MODE_ORDER.map((m) => {
                                                        const meta = BUILD_MODE_META[m];
                                                        const Icon = meta.icon;
                                                        const isActive = mode === m;
                                                        return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", "data-testid": `build-mode-${m}`, "aria-pressed": isActive, "aria-disabled": isSubmitting, disabled: isSubmitting, onClick: () => setMode(m), className: cn('flex cursor-pointer items-center gap-1 rounded-sm px-2 py-1 text-xs font-medium transition-colors', isActive
                                                                            ? 'bg-accent text-foreground'
                                                                            : 'text-muted-foreground hover:text-foreground', 'disabled:cursor-not-allowed disabled:opacity-50'), children: [_jsx(Icon, { className: "h-3.5 w-3.5" }), t(meta.labelKey)] }) }), _jsx(TooltipContent, { role: "tooltip", side: "bottom", children: t(`${meta.labelKey}Description`) })] }, m));
                                                    }) }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: handleAddFiles, disabled: isSubmitting, "aria-label": t('chat.attachFiles'), className: "text-muted-foreground hover:text-foreground cursor-pointer rounded p-1 transition-colors", children: _jsx(PaperclipIcon, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { side: "bottom", children: t('chat.attachFiles') })] })] })] })] }), hasFeatures && initialParentId !== undefined ? (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "parent-feature", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: t('createDrawer.parentFeature') }), _jsx(ParentFeatureCombobox, { features: features, value: parentId, onChange: setParentId, disabled: isSubmitting })] })) : null, _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "border-input flex items-center gap-4 rounded-md border px-3 py-2.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "text-muted-foreground w-16 shrink-0 cursor-default text-xs font-semibold tracking-wider", children: t('createDrawer.approve') }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.approveDescription') })] }), _jsx("div", { className: "flex flex-1 items-center gap-4", children: AUTO_APPROVE_OPTIONS.map((opt) => (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: `approve-${opt.id}`, size: "sm", checked: approvalGates[opt.id] ?? false, onCheckedChange: (v) => setApprovalGates((prev) => ({ ...prev, [opt.id]: v })), disabled: isSubmitting ||
                                                                        (fast && (opt.id === 'allowPrd' || opt.id === 'allowPlan')) }), _jsx(Label, { htmlFor: `approve-${opt.id}`, className: "cursor-pointer text-xs font-medium", children: opt.label })] }) }), _jsx(TooltipContent, { side: "bottom", children: fast && (opt.id === 'allowPrd' || opt.id === 'allowPlan')
                                                            ? t('createDrawer.skippedInFastMode')
                                                            : opt.description })] }, opt.id))) }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => {
                                                            const allOn = AUTO_APPROVE_OPTIONS.every((o) => approvalGates[o.id]);
                                                            const next = {};
                                                            for (const o of AUTO_APPROVE_OPTIONS)
                                                                next[o.id] = !allOn;
                                                            setApprovalGates(next);
                                                        }, disabled: isSubmitting, className: cn('text-muted-foreground hover:text-foreground cursor-pointer rounded px-1.5 py-0.5 text-[10px] font-semibold tracking-wider uppercase transition-colors', AUTO_APPROVE_OPTIONS.every((o) => approvalGates[o.id]) && 'text-primary'), children: t('createDrawer.all') }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.toggleAllApprovalGates') })] })] }), _jsxs("div", { className: "border-input flex items-center gap-4 rounded-md border px-3 py-2.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "text-muted-foreground w-16 shrink-0 cursor-default text-xs font-semibold tracking-wider", children: t('createDrawer.evidence') }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.evidenceDescription') })] }), _jsxs("div", { className: "flex flex-1 items-center gap-4", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "enable-evidence", size: "sm", checked: enableEvidence, onCheckedChange: (v) => {
                                                                            setEnableEvidence(v);
                                                                            if (!v)
                                                                                setCommitEvidence(false);
                                                                        }, disabled: isSubmitting }), _jsx(Label, { htmlFor: "enable-evidence", className: "cursor-pointer text-xs font-medium", children: t('createDrawer.collect') })] }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.collectDescription') })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "commit-evidence", size: "sm", checked: commitEvidence, onCheckedChange: setCommitEvidence, disabled: isSubmitting || !enableEvidence || (!openPr && !forkAndPr) }), _jsx(Label, { htmlFor: "commit-evidence", className: cn('cursor-pointer text-xs font-medium', (!enableEvidence || (!openPr && !forkAndPr)) && 'opacity-50'), children: t('createDrawer.addToPr') })] }) }), _jsx(TooltipContent, { side: "bottom", children: !openPr && !forkAndPr
                                                                ? t('createDrawer.requiresPr')
                                                                : !enableEvidence
                                                                    ? t('createDrawer.requiresEvidence')
                                                                    : t('createDrawer.addToPrDescription') })] })] })] }), _jsxs("div", { className: "border-input flex items-center gap-4 rounded-md border px-3 py-2.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "text-muted-foreground w-16 shrink-0 cursor-default text-xs font-semibold tracking-wider", children: t('createDrawer.skills') }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.skillsDescription') })] }), _jsx("div", { className: "flex flex-1 items-center gap-4", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "inject-skills", size: "sm", checked: injectSkills, onCheckedChange: setInjectSkills, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "inject-skills", className: "flex cursor-pointer items-center gap-1 text-xs font-medium", children: [_jsx(Puzzle, { className: "h-3 w-3" }), t('createDrawer.injectSkills')] })] }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.injectSkillsDescription') })] }) })] }), _jsxs("div", { className: "border-input flex items-start gap-4 rounded-md border px-3 py-2.5", children: [_jsx("span", { className: "text-muted-foreground w-16 shrink-0 pt-0.5 text-xs font-semibold tracking-wider", children: t('createDrawer.git') }), _jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-4", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "push", size: "sm", checked: forkAndPr ? true : push || openPr, onCheckedChange: (v) => {
                                                                            setPush(v);
                                                                            if (!v && openPr)
                                                                                setOpenPr(false);
                                                                        }, disabled: isSubmitting || forkAndPr }), _jsx(Label, { htmlFor: "push", className: cn('cursor-pointer text-xs font-medium', forkAndPr && 'opacity-50'), children: t('createDrawer.push') })] }) }), _jsx(TooltipContent, { side: "bottom", children: forkAndPr
                                                                ? 'Enabled — contributing to upstream'
                                                                : t('createDrawer.pushDescription') })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "open-pr", size: "sm", checked: forkAndPr ? true : openPr, onCheckedChange: (v) => {
                                                                            setOpenPr(v);
                                                                            if (!v)
                                                                                setCommitEvidence(false);
                                                                        }, disabled: isSubmitting || forkAndPr }), _jsx(Label, { htmlFor: "open-pr", className: cn('cursor-pointer text-xs font-medium', forkAndPr && 'opacity-50'), children: t('createDrawer.pr') })] }) }), _jsx(TooltipContent, { side: "bottom", children: forkAndPr
                                                                ? 'Enabled — contributing to upstream'
                                                                : t('createDrawer.prDescription') })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "ci-watch", size: "sm", checked: ciWatchEnabled, onCheckedChange: setCiWatchEnabled, disabled: isSubmitting }), _jsx(Label, { htmlFor: "ci-watch", className: "cursor-pointer text-xs font-medium", children: t('createDrawer.watch') })] }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.watchDescription') })] }), _jsx("div", { className: "bg-border h-4 w-px shrink-0" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "rebase-before-branch", size: "sm", checked: rebaseBeforeBranch, onCheckedChange: setRebaseBeforeBranch, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "rebase-before-branch", className: "flex cursor-pointer items-center gap-1 text-xs font-medium", children: [_jsx(RefreshCw, { className: "h-3 w-3" }), t('createDrawer.sync')] })] }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.syncDescription') })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "commit-specs", size: "sm", checked: commitSpecs, onCheckedChange: setCommitSpecs, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "commit-specs", className: "flex cursor-pointer items-center gap-1 text-xs font-medium", children: [_jsx(FileText, { className: "h-3 w-3" }), t('createDrawer.commitSpecs')] })] }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.commitSpecsDescription') })] }), !canPush && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "fork-and-pr", size: "sm", checked: forkAndPr, onCheckedChange: (v) => {
                                                                            setForkAndPr(v);
                                                                            // Auto-flip commitSpecs to false when enabling contribute mode
                                                                            if (v)
                                                                                setCommitSpecs(false);
                                                                        }, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "fork-and-pr", className: "flex cursor-pointer items-center gap-1 text-xs font-medium", children: [_jsx(GitFork, { className: "h-3 w-3" }), t('createDrawer.forkAndPr')] })] }) }), _jsx(TooltipContent, { side: "bottom", children: t('createDrawer.forkAndPrDescription') })] }))] })] })] })] }) }) }) }));
}
function ParentFeatureCombobox({ features, value, onChange, disabled, }) {
    const { t } = useTranslation('web');
    const [open, setOpen] = useState(false);
    const [query, setQuery] = useState('');
    const inputRef = useRef(null);
    const selectedFeature = features.find((f) => f.id === value);
    const filtered = query.trim()
        ? features.filter((f) => f.name.toLowerCase().includes(query.toLowerCase()) ||
            f.id.toLowerCase().includes(query.toLowerCase()))
        : features;
    const handleSelect = useCallback((id) => {
        onChange(id);
        setOpen(false);
        setQuery('');
    }, [onChange]);
    useEffect(() => {
        if (open) {
            setTimeout(() => inputRef.current?.focus(), 0);
        }
        else {
            setQuery('');
        }
    }, [open]);
    return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { id: "parent-feature", type: "button", role: "combobox", "aria-expanded": open, "aria-label": "Parent Feature", disabled: disabled, "data-testid": "parent-feature-combobox", className: cn('border-input bg-background ring-offset-background focus:ring-ring flex h-9 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50', !selectedFeature && 'text-muted-foreground'), children: [_jsx("span", { className: "truncate", children: selectedFeature
                                ? `${selectedFeature.name} (${selectedFeature.id.slice(0, 8)})`
                                : t('createDrawer.selectParent') }), _jsx(ChevronsUpDown, { className: "ms-2 h-4 w-4 shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "w-80 p-0", align: "start", "data-testid": "parent-feature-combobox-content", children: _jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "border-b p-2", children: _jsx(Input, { ref: inputRef, placeholder: t('createDrawer.searchFeatures'), value: query, onChange: (e) => setQuery(e.target.value), className: "h-8 border-0 p-0 text-sm shadow-none focus-visible:ring-0", "data-testid": "parent-feature-search" }) }), _jsxs("div", { className: "max-h-48 overflow-y-auto py-1", role: "listbox", "aria-label": "Features", children: [_jsxs("button", { type: "button", role: "option", "aria-selected": value === undefined, onClick: () => handleSelect(undefined), className: cn('hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm', value === undefined && 'bg-accent/50'), "data-testid": "parent-feature-option-none", children: [_jsx(CheckIcon, { className: cn('h-4 w-4 shrink-0', value !== undefined && 'invisible') }), _jsx("span", { className: "text-muted-foreground italic", children: t('createDrawer.noParent') })] }), filtered.length === 0 && query ? (_jsx("p", { className: "text-muted-foreground px-3 py-2 text-sm", children: t('createDrawer.noFeaturesFound') })) : (filtered.map((f) => (_jsxs("button", { type: "button", role: "option", "aria-selected": value === f.id, onClick: () => handleSelect(f.id), className: cn('hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm', value === f.id && 'bg-accent/50'), "data-testid": `parent-feature-option-${f.id}`, children: [_jsx(CheckIcon, { className: cn('h-4 w-4 shrink-0', value !== f.id && 'invisible') }), _jsxs("span", { className: "truncate", children: [f.name, ' ', _jsxs("span", { className: "text-muted-foreground font-mono text-xs", children: ["(", f.id.slice(0, 8), ")"] })] })] }, f.id))))] })] }) })] }));
}
export function RepositoryCombobox({ repositories, value, onChange, onAddRepository, disabled, }) {
    const [open, setOpen] = useState(false);
    const [query, setQuery] = useState('');
    const [isAdding, setIsAdding] = useState(false);
    const [addError, setAddError] = useState(null);
    const [showReactPicker, setShowReactPicker] = useState(false);
    const inputRef = useRef(null);
    const { reactFileManager: useReactFileManager } = useFeatureFlags();
    const { t } = useTranslation('web');
    const selectedRepo = repositories.find((r) => r.path === value);
    const filtered = query.trim()
        ? repositories.filter((r) => r.name.toLowerCase().includes(query.toLowerCase()) ||
            r.path.toLowerCase().includes(query.toLowerCase()))
        : repositories;
    const handleSelect = useCallback((path) => {
        onChange(path);
        setOpen(false);
        setQuery('');
    }, [onChange]);
    const addRepoFromPath = useCallback(async (folderPath) => {
        const result = await addRepository({ path: folderPath });
        if (result.error) {
            setAddError(result.error);
            setIsAdding(false);
            return;
        }
        if (result.repository) {
            const newRepo = {
                id: result.repository.id,
                name: result.repository.name,
                path: result.repository.path,
            };
            onAddRepository?.(newRepo);
            onChange(newRepo.path);
            setOpen(false);
            setQuery('');
        }
    }, [onAddRepository, onChange]);
    const handleAddRepository = useCallback(async () => {
        if (isAdding)
            return;
        if (useReactFileManager) {
            setShowReactPicker(true);
            return;
        }
        setIsAdding(true);
        setAddError(null);
        try {
            const folderPath = await pickFolder();
            if (!folderPath) {
                setIsAdding(false);
                return;
            }
            await addRepoFromPath(folderPath);
        }
        catch {
            // Native picker failed — fall back to React file manager
            setShowReactPicker(true);
        }
        finally {
            setIsAdding(false);
        }
    }, [isAdding, useReactFileManager, addRepoFromPath]);
    const handleReactPickerSelect = useCallback(async (path) => {
        setShowReactPicker(false);
        if (!path)
            return;
        setIsAdding(true);
        setAddError(null);
        try {
            await addRepoFromPath(path);
        }
        catch (err) {
            setAddError(err instanceof Error ? err.message : 'Failed to add repository');
        }
        finally {
            setIsAdding(false);
        }
    }, [addRepoFromPath]);
    useEffect(() => {
        if (open) {
            setTimeout(() => inputRef.current?.focus(), 0);
        }
        else {
            setQuery('');
        }
    }, [open]);
    return (_jsxs(_Fragment, { children: [_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", role: "combobox", "aria-expanded": open, "aria-label": "Repository", disabled: disabled, "data-testid": "repository-combobox", className: cn('border-input bg-background ring-offset-background focus:ring-ring flex h-9 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50', !selectedRepo && 'text-muted-foreground'), children: [_jsx("span", { className: "truncate", children: selectedRepo ? selectedRepo.name : 'Select repository...' }), _jsx(ChevronsUpDown, { className: "ms-2 h-4 w-4 shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "w-80 p-0", align: "start", "data-testid": "repository-combobox-content", children: _jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "border-b p-2", children: _jsx(Input, { ref: inputRef, placeholder: t('createDrawer.searchRepositories'), value: query, onChange: (e) => setQuery(e.target.value), className: "h-8 border-0 p-0 text-sm shadow-none focus-visible:ring-0", "data-testid": "repository-search" }) }), _jsx("div", { className: "max-h-48 overflow-y-auto py-1", role: "listbox", "aria-label": "Repositories", children: filtered.length === 0 ? (_jsx("p", { className: "text-muted-foreground px-3 py-2 text-sm", "data-testid": "repository-empty", children: "No repositories found." })) : (filtered.map((r) => (_jsxs("button", { type: "button", role: "option", "aria-selected": value === r.path, onClick: () => handleSelect(r.path), className: cn('hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm', value === r.path && 'bg-accent/50'), "data-testid": `repository-option-${r.id}`, children: [_jsx(CheckIcon, { className: cn('h-4 w-4 shrink-0', value !== r.path && 'invisible') }), _jsxs("span", { className: "flex flex-col items-start truncate", children: [_jsxs("span", { className: "flex items-center gap-1.5 truncate", children: [r.name, r.isFork ? (_jsxs(Badge, { variant: "outline", className: "h-4 shrink-0 px-1 text-[10px]", children: [_jsx(GitFork, { className: "mr-0.5 h-2.5 w-2.5" }), "Fork"] })) : null] }), _jsx("span", { className: "text-muted-foreground truncate text-xs", children: r.path })] })] }, r.id)))) }), _jsx(Separator, {}), _jsxs("button", { type: "button", onClick: handleAddRepository, disabled: isAdding, className: "hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm", "data-testid": "add-repository-item", children: [isAdding ? (_jsx(Loader2, { className: "h-4 w-4 shrink-0 animate-spin" })) : (_jsx(FolderPlus, { className: "h-4 w-4 shrink-0" })), _jsx("span", { children: "Add new repository..." })] }), addError ? (_jsx("p", { className: "px-3 pb-2 text-xs text-red-500", "data-testid": "add-repository-error", children: addError })) : null] }) })] }), _jsx(ReactFileManagerDialog, { open: showReactPicker, onOpenChange: (isOpen) => {
                    if (!isOpen)
                        setShowReactPicker(false);
                }, onSelect: handleReactPickerSelect })] }));
}
