import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

import {
  reconcileAnthropicRuntimeSelections,
  resolveAnthropicFastMode,
  resolveAnthropicRuntimeSelection,
} from '@features/anthropic-runtime-profile/renderer';
import {
  mergeCodexCliStatusWithSnapshot,
  useCodexAccountSnapshot,
} from '@features/codex-account/renderer';
import {
  buildCodexFastModeArgs,
  reconcileCodexRuntimeSelections,
  resolveCodexFastMode,
  resolveCodexRuntimeSelection,
} from '@features/codex-runtime-profile/renderer';
import { useAppTranslation } from '@features/localization/renderer';
import { api } from '@renderer/api';
import { ProviderActivityStatusStrip } from '@renderer/components/common/ProviderActivityStatusStrip';
import {
  buildMemberDraftColorMap,
  buildMemberDraftSuggestions,
  buildMembersFromDrafts,
  clearMemberModelOverrides,
  createMemberDraft,
  normalizeLeadProviderForMode,
  normalizeMemberDraftForProviderMode,
  validateMemberNameInline,
} from '@renderer/components/team/members/MembersEditorSection';
import { TeamRosterEditorSection } from '@renderer/components/team/members/TeamRosterEditorSection';
import { AutoResizeTextarea } from '@renderer/components/ui/auto-resize-textarea';
import { Button } from '@renderer/components/ui/button';
import { Checkbox } from '@renderer/components/ui/checkbox';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@renderer/components/ui/dialog';
import { Input } from '@renderer/components/ui/input';
import { Label } from '@renderer/components/ui/label';
import { MentionableTextarea } from '@renderer/components/ui/MentionableTextarea';
import { getTeamColorSet, getThemedBadge } from '@renderer/constants/teamColors';
import { useChipDraftPersistence } from '@renderer/hooks/useChipDraftPersistence';
import { useCreateTeamDraft } from '@renderer/hooks/useCreateTeamDraft';
import { useDraftPersistence } from '@renderer/hooks/useDraftPersistence';
import { useTaskSuggestions } from '@renderer/hooks/useTaskSuggestions';
import { useTeamSuggestions } from '@renderer/hooks/useTeamSuggestions';
import { useTheme } from '@renderer/hooks/useTheme';
import { cn } from '@renderer/lib/utils';
import {
  applyStoredCreateTeamMemberRuntimePreferences,
  getStoredCreateTeamEffort,
  getStoredCreateTeamFastMode as getStoredTeamFastMode,
  getStoredCreateTeamLimitContext,
  getStoredCreateTeamMemberRuntimePreferences,
  getStoredCreateTeamModel as getStoredTeamModel,
  getStoredCreateTeamProvider as getStoredTeamProvider,
  getStoredCreateTeamSkipPermissions,
  migrateLegacyCreateTeamPreferences,
  setStoredCreateTeamEffort,
  setStoredCreateTeamFastMode,
  setStoredCreateTeamLimitContext,
  setStoredCreateTeamMemberRuntimePreferences,
  setStoredCreateTeamModel,
  setStoredCreateTeamProvider,
  setStoredCreateTeamSkipPermissions,
} from '@renderer/services/createTeamPreferences';
import { useStore } from '@renderer/store';
import { createLoadingMultimodelCliStatus } from '@renderer/store/slices/cliInstallerSlice';
import { isGeminiUiFrozen } from '@renderer/utils/geminiUiFreeze';
import { normalizePath } from '@renderer/utils/pathNormalize';
import { resolveUiOwnedProviderBackendId } from '@renderer/utils/providerBackendIdentity';
import { refreshCliStatusForCurrentMode } from '@renderer/utils/refreshCliStatus';
import { getAvailableTeamEffortValue } from '@renderer/utils/teamEffortOptions';
import {
  getTeamModelSelectionError,
  isTeamProviderRuntimeStatusLoading,
  normalizeExplicitTeamModelForUi,
} from '@renderer/utils/teamModelAvailability';
import { getTeamProviderLabel as getCatalogTeamProviderLabel } from '@renderer/utils/teamModelCatalog';
import { isEphemeralProjectPath } from '@shared/utils/ephemeralProjectPath';
import { DEFAULT_PROVIDER_MODEL_SELECTION } from '@shared/utils/providerModelSelection';
import { resolveTeamLeadColorName } from '@shared/utils/teamMemberColors';
import { isTeamProviderId, normalizeOptionalTeamProviderId } from '@shared/utils/teamProvider';
import { AlertTriangle, CheckCircle2, Info, Loader2, X } from 'lucide-react';
import { useShallow } from 'zustand/react/shallow';

import { AdvancedCliSection } from './AdvancedCliSection';
import { AnthropicFastModeSelector } from './AnthropicFastModeSelector';
import { CodexFastModeSelector } from './CodexFastModeSelector';
import { CodexReconnectPrompt, shouldShowCodexReconnectPrompt } from './CodexReconnectPrompt';
import {
  clearInheritedMemberModelsUnavailableForProvider,
  resolveProviderScopedMemberModel,
} from './memberModelScope';
import { OptionalSettingsSection } from './OptionalSettingsSection';
import {
  isDeletedProjectPathSelection,
  isSelectableProjectPathProject,
} from './projectPathOptions';
import { loadProjectPathProjects, type ProjectPathProject } from './projectPathProjects';
import { ProjectPathSelector } from './ProjectPathSelector';
import { buildProviderPrepareModelCacheKey } from './providerPrepareCacheKey';
import {
  mergeReusableProviderPrepareModelResults,
  type ProviderPrepareDiagnosticsModelResult,
  runProviderPrepareDiagnostics,
} from './providerPrepareDiagnostics';
import { buildProviderPreparePlans, type ProviderPreparePlan } from './providerPreparePlans';
import {
  buildProviderPrepareModelChecksSignature,
  buildProviderPrepareRuntimeStatusSignature,
} from './providerPrepareRequestSignature';
import {
  getShortLivedProviderPrepareModelIssueReasons,
  storeShortLivedProviderPrepareModelResults,
} from './providerPrepareShortLivedCache';
import { getProvisioningModelIssue } from './provisioningModelIssues';
import { ProvisioningProviderRuntimeSettingsDialog } from './ProvisioningProviderRuntimeSettingsDialog';
import {
  deriveEffectiveProvisioningPrepareState,
  getPrimaryProvisioningFailureDetail,
  getProvisioningFailureHint,
  getProvisioningProviderBackendSummary,
  getProvisioningProviderProgressMessage,
  type ProvisioningProviderCheck,
  ProvisioningProviderStatusList,
  shouldHideProvisioningProviderStatusList,
  updateProviderCheck,
} from './ProvisioningProviderStatusList';
import { SkipPermissionsCheckbox } from './SkipPermissionsCheckbox';
import {
  analyzeTeammateRuntimeCompatibility,
  useTmuxRuntimeReadiness,
} from './teammateRuntimeCompatibility';
import { TeammateRuntimeCompatibilityNotice } from './TeammateRuntimeCompatibilityNotice';
import { computeEffectiveTeamModel } from './TeamModelSelector';
import { getNextSuggestedTeamName } from './teamNameSets';
import {
  getWorktreeGitBlockingMessage,
  getWorktreeGitControlDisabledReason,
  useWorktreeGitReadiness,
  WorktreeGitReadinessBanner,
} from './WorktreeGitReadinessBanner';

import type { MemberDraft } from '@renderer/components/team/members/MembersEditorSection';
import type {
  CliProviderId,
  EffortLevel,
  TeamCreateRequest,
  TeamFastMode,
  TeamProviderId,
  TeamProvisioningMemberInput,
  TeamProvisioningModelCheckRequest,
} from '@shared/types';

const TEAM_COLOR_NAMES = [
  'blue',
  'green',
  'red',
  'yellow',
  'purple',
  'cyan',
  'orange',
  'pink',
] as const;

const APP_TEAM_RUNTIME_DISALLOWED_TOOLS = 'TeamDelete,TodoWrite,TaskCreate,TaskUpdate';

function getProviderLabel(providerId: TeamProviderId): string {
  return getCatalogTeamProviderLabel(providerId) ?? 'Anthropic';
}

function alignProvisioningChecks(
  existingChecks: ProvisioningProviderCheck[],
  providerIds: TeamProviderId[]
): ProvisioningProviderCheck[] {
  const existingByProviderId = new Map(
    existingChecks.map((check) => [check.providerId, check] as const)
  );
  return providerIds.map(
    (providerId) =>
      existingByProviderId.get(providerId) ?? {
        providerId,
        status: 'pending',
        backendSummary: null,
        details: [],
      }
  );
}

export interface TeamCopyData {
  teamName: string;
  description?: string;
  color?: string;
  members: TeamProvisioningMemberInput[];
}

export interface ActiveTeamRef {
  teamName: string;
  displayName: string;
  projectPath: string;
}

interface CreateTeamDialogProps {
  open: boolean;
  canCreate: boolean;
  provisioningErrorsByTeam: Record<string, string | null>;
  clearProvisioningError?: (teamName?: string) => void;
  existingTeamNames: string[];
  /** Team names currently in active provisioning (launching) — used to prevent name conflicts. */
  provisioningTeamNames?: string[];
  activeTeams?: ActiveTeamRef[];
  initialData?: TeamCopyData;
  defaultProjectPath?: string | null;
  onClose: () => void;
  onCreate: (request: TeamCreateRequest) => Promise<void>;
  onOpenTeam: (teamName: string, projectPath?: string) => void;
}

interface ValidationResult {
  valid: boolean;
  errors?: {
    teamName?: string;
    members?: string;
    cwd?: string;
  };
}

import { CUSTOM_ROLE, PRESET_ROLES } from '@renderer/constants/teamRoles';

const DEFAULT_MEMBERS: { name: string; roleSelection: string; workflow?: string }[] = [
  {
    name: 'alice',
    roleSelection: 'reviewer',
    workflow:
      'Review every completed task in the project. Read the code changes, check for correctness, style, and potential issues. Approve the task or request changes with clear feedback.',
  },
  {
    name: 'tom',
    roleSelection: 'developer',
  },
  { name: 'bob', roleSelection: 'developer' },
  { name: 'jack', roleSelection: 'developer' },
];

/** Mirrors Claude CLI's `zuA()` sanitization: non-alphanumeric → `-`, then lowercase. */
function sanitizeTeamName(name: string): string {
  let result = name
    .replace(/[^a-zA-Z0-9]/g, '-')
    .replace(/-{2,}/g, '-')
    .toLowerCase();
  // Trim leading/trailing dashes without backtracking-vulnerable regex
  while (result.startsWith('-')) result = result.slice(1);
  while (result.endsWith('-')) result = result.slice(0, -1);
  return result;
}

function validateTeamNameInline(
  name: string,
  t: ReturnType<typeof useAppTranslation>['t']
): string | null {
  const trimmed = name.trim();
  if (!trimmed) return null;
  const sanitized = sanitizeTeamName(trimmed);
  if (!sanitized) {
    return t('create.validation.nameMustContainLetterOrDigit');
  }
  if (sanitized.length > 128) {
    return t('create.validation.nameTooLong');
  }
  return null;
}

function buildDefaultTeamDescription(teamName: string): string {
  const trimmedName = teamName.trim();
  return trimmedName.length > 0
    ? `${trimmedName} team for provisioning flow`
    : 'Team for provisioning flow';
}

function validateRequest(
  request: TeamCreateRequest,
  t: ReturnType<typeof useAppTranslation>['t'],
  options?: { requireCwd?: boolean }
): ValidationResult {
  const requireCwd = options?.requireCwd ?? true;
  const sanitized = sanitizeTeamName(request.teamName);
  if (!sanitized) {
    return {
      valid: false,
      errors: {
        teamName: t('create.validation.nameMustContainLetterOrDigit'),
      },
    };
  }
  if (sanitized.length > 128) {
    return {
      valid: false,
      errors: {
        teamName: t('create.validation.nameTooLong'),
      },
    };
  }
  if (requireCwd && !request.cwd.trim()) {
    return {
      valid: false,
      errors: {
        cwd: t('create.validation.selectWorkingDirectory'),
      },
    };
  }
  if (request.members.some((member) => !member.name.trim())) {
    return {
      valid: false,
      errors: {
        members: t('create.validation.memberNameRequired'),
      },
    };
  }
  if (request.members.some((member) => validateMemberNameInline(member.name.trim()) !== null)) {
    return {
      valid: false,
      errors: {
        members: t('create.validation.memberNameInvalid'),
      },
    };
  }
  const uniqueNames = new Set(request.members.map((member) => member.name.trim().toLowerCase()));
  if (uniqueNames.size !== request.members.length) {
    return {
      valid: false,
      errors: {
        members: t('create.validation.memberNamesUnique'),
      },
    };
  }
  return { valid: true };
}

type IdleWindow = Window & {
  requestIdleCallback?: (callback: () => void, options?: { timeout: number }) => number;
  cancelIdleCallback?: (id: number) => void;
};

interface ScheduledIdleHandle {
  kind: 'idle' | 'timeout';
  id: number;
}

function scheduleIdle(cb: () => void): ScheduledIdleHandle {
  const idleWindow = window as IdleWindow;
  if (typeof idleWindow.requestIdleCallback === 'function') {
    return { kind: 'idle', id: idleWindow.requestIdleCallback(cb, { timeout: 2000 }) };
  }
  return { kind: 'timeout', id: window.setTimeout(cb, 0) };
}

function cancelScheduledIdle(handle: ScheduledIdleHandle | null): void {
  if (!handle) return;
  if (handle.kind === 'idle') {
    const idleWindow = window as IdleWindow;
    if (typeof idleWindow.cancelIdleCallback === 'function') {
      idleWindow.cancelIdleCallback(handle.id);
    }
    return;
  }
  window.clearTimeout(handle.id);
}

function cancelScheduledIdleSet(handles: Set<ScheduledIdleHandle>): void {
  for (const handle of handles) {
    cancelScheduledIdle(handle);
  }
  handles.clear();
}

function isCurrentPrepareGeneration(ref: { current: number }, generation: number): boolean {
  return ref.current === generation;
}

export const CreateTeamDialog = ({
  open,
  canCreate,
  provisioningErrorsByTeam,
  clearProvisioningError,
  existingTeamNames,
  provisioningTeamNames = [],
  activeTeams,
  initialData,
  defaultProjectPath,
  onClose,
  onCreate,
  onOpenTeam,
}: CreateTeamDialogProps): React.JSX.Element => {
  const { isLight } = useTheme();
  const { t } = useAppTranslation('team');
  const multimodelEnabled = useStore((s) => s.appConfig?.general?.multimodelEnabled ?? true);
  const anthropicProviderFastModeDefault = useStore(
    (s) => s.appConfig?.providerConnections?.anthropic.fastModeDefault ?? false
  );
  const { cliStatus, cliStatusLoading, cliProviderStatusLoading } = useStore(
    useShallow((s) => ({
      cliStatus: s.cliStatus,
      cliStatusLoading: s.cliStatusLoading,
      cliProviderStatusLoading: s.cliProviderStatusLoading,
    }))
  );
  const bootstrapCliStatus = useStore((s) => s.bootstrapCliStatus);
  const fetchCliStatus = useStore((s) => s.fetchCliStatus);
  const openDashboard = useStore((s) => s.openDashboard);
  const loadingCliStatus = useMemo(
    () =>
      !cliStatus && cliStatusLoading && multimodelEnabled
        ? createLoadingMultimodelCliStatus()
        : cliStatus,
    [cliStatus, cliStatusLoading, multimodelEnabled]
  );
  const codexAccount = useCodexAccountSnapshot({
    enabled:
      multimodelEnabled &&
      loadingCliStatus?.flavor === 'agent_teams_orchestrator' &&
      Boolean(loadingCliStatus?.providers.some((provider) => provider.providerId === 'codex')),
  });
  const effectiveCliStatus = useMemo(
    () => mergeCodexCliStatusWithSnapshot(loadingCliStatus, codexAccount.snapshot),
    [loadingCliStatus, codexAccount.snapshot]
  );
  const codexSnapshotPending =
    codexAccount.loading &&
    Boolean(loadingCliStatus?.providers.some((provider) => provider.providerId === 'codex')) &&
    !codexAccount.snapshot;

  // ── Persisted draft state (survives tab navigation) ──────────────────
  const {
    teamName,
    setTeamName,
    members,
    setMembers,
    syncModelsWithLead,
    setSyncModelsWithLead,
    teammateWorktreeDefault,
    setTeammateWorktreeDefault,
    cwdMode,
    setCwdMode,
    selectedProjectPath,
    setSelectedProjectPath,
    customCwd,
    setCustomCwd,
    soloTeam,
    setSoloTeam,
    launchTeam,
    setLaunchTeam,
    teamColor,
    setTeamColor,
    isLoaded: draftLoaded,
    clearDraft,
  } = useCreateTeamDraft();

  const descriptionDraft = useDraftPersistence({ key: 'createTeam:description' });
  const promptDraft = useDraftPersistence({ key: 'createTeam:prompt' });
  const promptChipDraft = useChipDraftPersistence('createTeam:prompt:chips');

  // ── Transient UI state (NOT persisted) ───────────────────────────────
  const [projects, setProjects] = useState<ProjectPathProject[]>([]);
  const [projectsLoading, setProjectsLoading] = useState(false);
  const [projectsError, setProjectsError] = useState<string | null>(null);
  const [localError, setLocalError] = useState<string | null>(null);
  const [prepareState, setPrepareState] = useState<'idle' | 'loading' | 'ready' | 'failed'>('idle');
  const [prepareMessage, setPrepareMessage] = useState<string | null>(null);
  const [prepareWarnings, setPrepareWarnings] = useState<string[]>([]);
  const [prepareChecks, setPrepareChecks] = useState<ProvisioningProviderCheck[]>([]);
  const [prepareProviderInvalidationEpochById, setPrepareProviderInvalidationEpochById] = useState<
    Partial<Record<TeamProviderId, number>>
  >({});
  const [providerSettingsProviderId, setProviderSettingsProviderId] =
    useState<TeamProviderId | null>(null);
  const [workflowMentionSuggestionsEnabled, setWorkflowMentionSuggestionsEnabled] = useState(false);
  const prepareRequestSeqRef = useRef(0);
  const prepareIdleHandlesRef = useRef(new Set<ScheduledIdleHandle>());
  const prepareUnmountGenerationRef = useRef(0);
  const appliedDefaultProjectPathRef = useRef<string | null>(null);
  const lastAutoDescriptionRef = useRef<string | null>(null);
  const [fieldErrors, setFieldErrors] = useState<{
    teamName?: string;
    members?: string;
    cwd?: string;
  }>({});
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [conflictDismissed, setConflictDismissed] = useState(false);
  const [selectedProviderId, setSelectedProviderIdRaw] = useState<TeamProviderId>(() =>
    normalizeLeadProviderForMode(getStoredTeamProvider(), multimodelEnabled)
  );
  const [selectedModel, setSelectedModelRaw] = useState(() =>
    getStoredTeamModel(normalizeLeadProviderForMode(getStoredTeamProvider(), multimodelEnabled))
  );
  const [limitContext, setLimitContextRaw] = useState(getStoredCreateTeamLimitContext);
  const [skipPermissions, setSkipPermissionsRaw] = useState(getStoredCreateTeamSkipPermissions);
  const [selectedEffort, setSelectedEffortRaw] = useState(getStoredCreateTeamEffort);
  const [selectedFastMode, setSelectedFastModeRaw] = useState<TeamFastMode>(getStoredTeamFastMode);
  const [anthropicRuntimeNotice, setAnthropicRuntimeNotice] = useState<string | null>(null);

  // Advanced CLI section state (use teamName-derived key for localStorage)
  const advancedKey = useMemo(() => sanitizeTeamName(teamName.trim()) || '_new_', [teamName]);
  const [worktreeEnabled, setWorktreeEnabledRaw] = useState(false);
  const [worktreeName, setWorktreeNameRaw] = useState('');
  const [customArgs, setCustomArgsRaw] = useState('');

  useEffect(() => {
    migrateLegacyCreateTeamPreferences();
  }, []);

  useEffect(() => {
    if (!open) {
      setProviderSettingsProviderId(null);
    }
  }, [open]);

  // Re-read localStorage when advancedKey changes
  useEffect(() => {
    const storedEnabled =
      localStorage.getItem(`team:lastWorktreeEnabled:${advancedKey}`) === 'true';
    const storedName = localStorage.getItem(`team:lastWorktreeName:${advancedKey}`) ?? '';
    setWorktreeEnabledRaw(storedEnabled && Boolean(storedName));
    setWorktreeNameRaw(storedName);
    setCustomArgsRaw(localStorage.getItem(`team:lastCustomArgs:${advancedKey}`) ?? '');
  }, [advancedKey]);

  const setSelectedModel = useCallback(
    (value: string): void => {
      const normalizedValue = normalizeExplicitTeamModelForUi(selectedProviderId, value);
      setSelectedModelRaw(normalizedValue);
      setStoredCreateTeamModel(selectedProviderId, normalizedValue);
    },
    [selectedProviderId]
  );

  const setSelectedProviderId = useCallback(
    (value: TeamProviderId): void => {
      const normalizedValue = normalizeLeadProviderForMode(value, multimodelEnabled);
      setSelectedProviderIdRaw(normalizedValue);
      setStoredCreateTeamProvider(normalizedValue);
      setSelectedModelRaw(getStoredTeamModel(normalizedValue));
    },
    [multimodelEnabled]
  );

  const setLimitContext = useCallback((value: boolean): void => {
    setLimitContextRaw(value);
    setStoredCreateTeamLimitContext(value);
  }, []);

  const setSkipPermissions = useCallback((value: boolean): void => {
    setSkipPermissionsRaw(value);
    setStoredCreateTeamSkipPermissions(value);
  }, []);

  const setSelectedEffort = useCallback((value: string): void => {
    setSelectedEffortRaw(value);
    setStoredCreateTeamEffort(value);
  }, []);

  const setSelectedFastMode = useCallback((value: TeamFastMode): void => {
    setSelectedFastModeRaw(value);
    setStoredCreateTeamFastMode(value);
  }, []);
  const enableWorkflowMentionSuggestions = useCallback((): void => {
    setWorkflowMentionSuggestionsEnabled(true);
  }, []);

  const setWorktreeEnabled = (value: boolean): void => {
    setWorktreeEnabledRaw(value);
    localStorage.setItem(`team:lastWorktreeEnabled:${advancedKey}`, String(value));
    if (!value) {
      setWorktreeNameRaw('');
      localStorage.setItem(`team:lastWorktreeName:${advancedKey}`, '');
    }
  };
  const setWorktreeName = (value: string): void => {
    setWorktreeNameRaw(value);
    localStorage.setItem(`team:lastWorktreeName:${advancedKey}`, value);
  };
  const setCustomArgs = (value: string): void => {
    setCustomArgsRaw(value);
    localStorage.setItem(`team:lastCustomArgs:${advancedKey}`, value);
  };

  const resetUIState = (): void => {
    setLocalError(null);
    setFieldErrors({});
    setIsSubmitting(false);
    setPrepareState('idle');
    setPrepareMessage(null);
    setPrepareWarnings([]);
    setPrepareChecks([]);
    setConflictDismissed(false);
  };

  const resetFormState = (): void => {
    clearDraft();
    lastAutoDescriptionRef.current = null;
    descriptionDraft.clearDraft();
    promptDraft.clearDraft();
    promptChipDraft.clearChipDraft();
    resetUIState();
  };

  const persistCurrentMemberRuntimePreferences = useCallback(
    (nextMembers: readonly MemberDraft[] = members): void => {
      setStoredCreateTeamMemberRuntimePreferences(nextMembers);
    },
    [members]
  );

  const selectedProjectPathDeleted = useMemo(
    () =>
      cwdMode === 'project' &&
      selectedProjectPath.length > 0 &&
      isDeletedProjectPathSelection(projects, selectedProjectPath),
    [cwdMode, projects, selectedProjectPath]
  );
  const selectedProjectCwd =
    isEphemeralProjectPath(selectedProjectPath) || selectedProjectPathDeleted
      ? ''
      : selectedProjectPath.trim();
  const effectiveCwd = cwdMode === 'project' ? selectedProjectCwd : customCwd.trim();
  const dialogTeamNameKey = sanitizeTeamName(teamName.trim());
  /** All taken names: existing teams + teams currently being provisioned. */
  const allTakenTeamNames = useMemo(
    () => [...new Set([...existingTeamNames, ...provisioningTeamNames])],
    [existingTeamNames, provisioningTeamNames]
  );
  const suggestedTeamName = useMemo(
    () => getNextSuggestedTeamName(allTakenTeamNames),
    [allTakenTeamNames]
  );

  // Clear stale provisioning error when dialog opens
  useEffect(() => {
    if (open && dialogTeamNameKey) {
      clearProvisioningError?.(dialogTeamNameKey);
    }
  }, [open, clearProvisioningError, dialogTeamNameKey]);

  const effectiveMemberDrafts = useMemo(
    () => (syncModelsWithLead ? members.map(clearMemberModelOverrides) : members),
    [members, syncModelsWithLead]
  );
  const hasSelectedWorktreeIsolation =
    !soloTeam &&
    effectiveMemberDrafts.some((member) => !member.removedAt && member.isolation === 'worktree');
  const worktreeGitReadiness = useWorktreeGitReadiness(
    effectiveCwd || null,
    open && canCreate && hasSelectedWorktreeIsolation
  );
  const worktreeIsolationDisabledReason =
    !soloTeam && canCreate ? getWorktreeGitControlDisabledReason(worktreeGitReadiness) : null;
  const worktreeGitBlockingMessage = getWorktreeGitBlockingMessage(
    worktreeGitReadiness,
    hasSelectedWorktreeIsolation
  );
  const worktreeGitBlocksSubmission = Boolean(worktreeGitBlockingMessage);
  const tmuxRuntime = useTmuxRuntimeReadiness(open && canCreate);

  const selectedMemberProviders = useMemo<TeamProviderId[]>(() => {
    if (!multimodelEnabled) {
      return ['anthropic'];
    }
    if (soloTeam || syncModelsWithLead) {
      return [selectedProviderId];
    }
    return Array.from(
      new Set([
        selectedProviderId,
        ...members.flatMap((member) =>
          !member.removedAt && isTeamProviderId(member.providerId) ? [member.providerId] : []
        ),
      ])
    );
  }, [members, multimodelEnabled, selectedProviderId, soloTeam, syncModelsWithLead]);
  const hasSelectedAnthropicRuntime = selectedMemberProviders.includes('anthropic');
  const effectiveAnthropicRuntimeLimitContext = hasSelectedAnthropicRuntime ? limitContext : false;

  const runtimeBackendSummaryByProvider = useMemo(() => {
    const entries: (readonly [TeamProviderId, string | null])[] = (
      effectiveCliStatus?.providers ?? []
    ).map(
      (provider) =>
        [
          provider.providerId as TeamProviderId,
          getProvisioningProviderBackendSummary(provider),
        ] as const
    );
    return new Map<TeamProviderId, string | null>(entries);
  }, [effectiveCliStatus?.providers]);
  const runtimeProviderStatusById = useMemo(
    () =>
      new Map(
        (effectiveCliStatus?.providers ?? []).map(
          (provider) => [provider.providerId, provider] as const
        )
      ),
    [effectiveCliStatus?.providers]
  );
  const runtimeProviderLoadingById = useMemo(
    () =>
      new Map(
        selectedMemberProviders.map(
          (providerId) =>
            [
              providerId,
              isTeamProviderRuntimeStatusLoading(
                providerId,
                runtimeProviderStatusById.get(providerId),
                cliProviderStatusLoading[providerId] === true ||
                  (providerId === 'codex' && codexSnapshotPending)
              ),
            ] as const
        )
      ),
    [
      cliProviderStatusLoading,
      codexSnapshotPending,
      runtimeProviderStatusById,
      selectedMemberProviders,
    ]
  );
  const selectedProviderBackendId = useMemo(
    () =>
      resolveUiOwnedProviderBackendId(
        selectedProviderId,
        runtimeProviderStatusById.get(selectedProviderId)
      ),
    [runtimeProviderStatusById, selectedProviderId]
  );
  const runtimeBackendSummaryByProviderRef = useRef(runtimeBackendSummaryByProvider);
  const prepareChecksRef = useRef<ProvisioningProviderCheck[]>([]);
  const prepareMessageRef = useRef<string | null>(null);
  const prepareModelResultsCacheRef = useRef(
    new Map<string, Record<string, ProviderPrepareDiagnosticsModelResult>>()
  );
  const lastPrepareProviderSignatureByIdRef = useRef(new Map<TeamProviderId, string>());
  const pendingPrepareProviderSignatureByIdRef = useRef(new Map<TeamProviderId, string>());
  const prepareProviderRequestSeqByIdRef = useRef(new Map<TeamProviderId, number>());
  const prepareWarningsByProviderIdRef = useRef(new Map<TeamProviderId, string[]>());

  useEffect(() => {
    runtimeBackendSummaryByProviderRef.current = runtimeBackendSummaryByProvider;
  }, [runtimeBackendSummaryByProvider]);

  useEffect(() => {
    const sanitized = clearInheritedMemberModelsUnavailableForProvider({
      members,
      selectedProviderId,
      runtimeProviderStatusById,
    });
    if (sanitized.changed) {
      setMembers(sanitized.members);
    }
  }, [members, runtimeProviderStatusById, selectedProviderId, setMembers]);

  useEffect(() => {
    prepareChecksRef.current = prepareChecks;
  }, [prepareChecks]);

  useEffect(() => {
    prepareMessageRef.current = prepareMessage;
  }, [prepareMessage]);

  const invalidatePrepareProvider = useCallback((providerId: CliProviderId): void => {
    if (!isTeamProviderId(providerId)) {
      return;
    }

    lastPrepareProviderSignatureByIdRef.current.delete(providerId);
    pendingPrepareProviderSignatureByIdRef.current.delete(providerId);
    prepareProviderRequestSeqByIdRef.current.set(
      providerId,
      (prepareProviderRequestSeqByIdRef.current.get(providerId) ?? 0) + 1
    );
    prepareWarningsByProviderIdRef.current.delete(providerId);
    setPrepareProviderInvalidationEpochById((current) => ({
      ...current,
      [providerId]: (current[providerId] ?? 0) + 1,
    }));
  }, []);

  useEffect(() => {
    if (!open) {
      lastPrepareProviderSignatureByIdRef.current.clear();
      pendingPrepareProviderSignatureByIdRef.current.clear();
      prepareProviderRequestSeqByIdRef.current.clear();
      prepareWarningsByProviderIdRef.current.clear();
    }
  }, [open]);

  useEffect(() => {
    const generation = ++prepareUnmountGenerationRef.current;
    const idleHandles = prepareIdleHandlesRef.current;
    const lastProviderSignatures = lastPrepareProviderSignatureByIdRef.current;
    const pendingProviderSignatures = pendingPrepareProviderSignatureByIdRef.current;
    const providerRequestSeqs = prepareProviderRequestSeqByIdRef.current;
    const warningsByProviderId = prepareWarningsByProviderIdRef.current;
    return () => {
      // React StrictMode replays effect cleanup/setup in development; defer
      // invalidation so the replay does not cancel the live prepare request.
      queueMicrotask(() => {
        if (!isCurrentPrepareGeneration(prepareUnmountGenerationRef, generation)) {
          return;
        }
        cancelScheduledIdleSet(idleHandles);
        prepareRequestSeqRef.current += 1;
        lastProviderSignatures.clear();
        pendingProviderSignatures.clear();
        providerRequestSeqs.clear();
        warningsByProviderId.clear();
      });
    };
  }, []);

  const selectedEffortForCurrentSelection = useMemo(
    () =>
      getAvailableTeamEffortValue({
        providerId: selectedProviderId,
        model: selectedModel,
        limitContext: effectiveAnthropicRuntimeLimitContext,
        providerStatus: runtimeProviderStatusById.get(selectedProviderId),
        value: selectedEffort,
      }),
    [
      effectiveAnthropicRuntimeLimitContext,
      runtimeProviderStatusById,
      selectedEffort,
      selectedModel,
      selectedProviderId,
    ]
  );

  const selectedModelChecksByProvider = useMemo(() => {
    const modelsByProvider = new Map<TeamProviderId, TeamProvisioningModelCheckRequest[]>();
    const leadEffort = (selectedEffortForCurrentSelection as EffortLevel | '') || undefined;
    const addModel = (
      providerId: TeamProviderId,
      model: string | undefined,
      effort?: EffortLevel
    ): void => {
      const trimmed = model?.trim() ?? '';
      if (!trimmed) {
        return;
      }
      const existing = modelsByProvider.get(providerId) ?? [];
      if (!existing.some((entry) => entry.model === trimmed && entry.effort === effort)) {
        modelsByProvider.set(providerId, [
          ...existing,
          {
            providerId,
            model: trimmed,
            ...(effort ? { effort } : {}),
          },
        ]);
      }
    };
    const addDefaultSelection = (providerId: TeamProviderId, effort?: EffortLevel): void => {
      if (
        providerId === 'codex' ||
        providerId === 'gemini' ||
        (providerId === 'anthropic' && selectedProviderId === 'anthropic')
      ) {
        addModel(providerId, DEFAULT_PROVIDER_MODEL_SELECTION, effort);
      }
    };

    const leadModel = computeEffectiveTeamModel(
      selectedModel,
      effectiveAnthropicRuntimeLimitContext,
      selectedProviderId
    );
    if (selectedModel.trim()) {
      addModel(selectedProviderId, leadModel, leadEffort);
    } else {
      addDefaultSelection(selectedProviderId, leadEffort);
    }
    for (const member of effectiveMemberDrafts) {
      if (member.removedAt) {
        continue;
      }
      const memberProviderId = normalizeOptionalTeamProviderId(member.providerId);
      const inheritsDefaultRuntime = !memberProviderId || memberProviderId === selectedProviderId;
      const explicitMemberModel = member.model?.trim() ?? '';
      const memberEffort =
        member.effort ?? (inheritsDefaultRuntime && !explicitMemberModel ? leadEffort : undefined);
      const scopedModel = resolveProviderScopedMemberModel({
        memberProviderId: member.providerId,
        memberModel: member.model,
        selectedProviderId,
        runtimeProviderStatusById,
      });
      if (scopedModel.model) {
        addModel(scopedModel.providerId, scopedModel.model, memberEffort);
      } else {
        addDefaultSelection(scopedModel.providerId, memberEffort);
      }
    }

    return modelsByProvider;
  }, [
    effectiveAnthropicRuntimeLimitContext,
    effectiveMemberDrafts,
    runtimeProviderStatusById,
    selectedEffortForCurrentSelection,
    selectedModel,
    selectedProviderId,
  ]);
  const selectedModelChecksByProviderSignature = useMemo(
    () => buildProviderPrepareModelChecksSignature(selectedModelChecksByProvider),
    [selectedModelChecksByProvider]
  );
  const shortLivedModelIssueReasons = useMemo(() => {
    void prepareChecks;
    void selectedModelChecksByProviderSignature;
    const modelAdvisoryReasonByProvider: Partial<Record<TeamProviderId, Record<string, string>>> =
      {};
    const modelIssueReasonByProvider: Partial<Record<TeamProviderId, Record<string, string>>> = {};
    const modelUnavailableReasonByProvider: Partial<
      Record<TeamProviderId, Record<string, string>>
    > = {};

    for (const providerId of selectedMemberProviders) {
      const backendSummary = runtimeBackendSummaryByProvider.get(providerId) ?? null;
      const providerRuntimeStatusSignature = buildProviderPrepareRuntimeStatusSignature(
        [providerId],
        runtimeProviderStatusById
      );
      const providerModelChecksSignature = buildProviderPrepareModelChecksSignature(
        new Map([[providerId, selectedModelChecksByProvider.get(providerId) ?? []]])
      );
      const cacheKey = buildProviderPrepareModelCacheKey({
        cwd: effectiveCwd,
        providerId,
        backendSummary,
        limitContext: effectiveAnthropicRuntimeLimitContext,
        runtimeStatusSignature: providerRuntimeStatusSignature,
        modelChecksSignature: providerModelChecksSignature,
      });
      const issueReasons = getShortLivedProviderPrepareModelIssueReasons({
        providerId,
        cacheKey,
      });
      if (Object.keys(issueReasons.modelAdvisoryReasonByValue).length > 0) {
        modelAdvisoryReasonByProvider[providerId] = issueReasons.modelAdvisoryReasonByValue;
      }
      if (Object.keys(issueReasons.modelIssueReasonByValue).length > 0) {
        modelIssueReasonByProvider[providerId] = issueReasons.modelIssueReasonByValue;
      }
      if (Object.keys(issueReasons.modelUnavailableReasonByValue).length > 0) {
        modelUnavailableReasonByProvider[providerId] = issueReasons.modelUnavailableReasonByValue;
      }
    }

    return {
      modelAdvisoryReasonByProvider,
      modelIssueReasonByProvider,
      modelUnavailableReasonByProvider,
    };
  }, [
    effectiveAnthropicRuntimeLimitContext,
    effectiveCwd,
    prepareChecks,
    runtimeBackendSummaryByProvider,
    runtimeProviderStatusById,
    selectedModelChecksByProvider,
    selectedModelChecksByProviderSignature,
    selectedMemberProviders,
  ]);

  useEffect(() => {
    if (multimodelEnabled) {
      return;
    }
    if (selectedProviderId !== 'anthropic') {
      setSelectedProviderIdRaw('anthropic');
      setSelectedModelRaw(getStoredTeamModel('anthropic'));
    }
    const nextMembers = members.map((member) => normalizeMemberDraftForProviderMode(member, false));
    const changed = nextMembers.some((member, index) => member !== members[index]);
    if (changed) {
      setMembers(nextMembers);
    }
  }, [members, multimodelEnabled, selectedProviderId, setMembers]);

  useEffect(() => {
    if (!open || cliStatus || cliStatusLoading) {
      return;
    }
    void refreshCliStatusForCurrentMode({
      multimodelEnabled,
      bootstrapCliStatus,
      fetchCliStatus,
    });
  }, [bootstrapCliStatus, cliStatus, cliStatusLoading, fetchCliStatus, multimodelEnabled, open]);

  const handleCodexReconnect = useCallback(
    (mode: 'browser' | 'device_code' = 'browser') => {
      void (async () => {
        await codexAccount.startChatgptLogin(mode);
      })();
    },
    [codexAccount]
  );

  useEffect(() => {
    if (!open || !canCreate || !launchTeam) {
      cancelScheduledIdleSet(prepareIdleHandlesRef.current);
      prepareRequestSeqRef.current += 1;
      lastPrepareProviderSignatureByIdRef.current.clear();
      pendingPrepareProviderSignatureByIdRef.current.clear();
      prepareProviderRequestSeqByIdRef.current.clear();
      prepareWarningsByProviderIdRef.current.clear();
      return;
    }

    if (typeof api.teams.prepareProvisioning !== 'function') {
      cancelScheduledIdleSet(prepareIdleHandlesRef.current);
      prepareRequestSeqRef.current += 1;
      lastPrepareProviderSignatureByIdRef.current.clear();
      pendingPrepareProviderSignatureByIdRef.current.clear();
      prepareProviderRequestSeqByIdRef.current.clear();
      prepareWarningsByProviderIdRef.current.clear();
      setPrepareState('failed');
      setPrepareWarnings([]);
      setPrepareChecks([]);
      setPrepareMessage(t('create.prepare.unsupportedPreload'));
      return;
    }

    if (!effectiveCwd) {
      cancelScheduledIdleSet(prepareIdleHandlesRef.current);
      prepareRequestSeqRef.current += 1;
      lastPrepareProviderSignatureByIdRef.current.clear();
      pendingPrepareProviderSignatureByIdRef.current.clear();
      prepareProviderRequestSeqByIdRef.current.clear();
      prepareWarningsByProviderIdRef.current.clear();
      setPrepareState('idle');
      setPrepareWarnings([]);
      setPrepareChecks([]);
      setPrepareMessage(t('create.prepare.selectWorkingDirectory'));
      return;
    }

    const selectedProviderIdSet = new Set(selectedMemberProviders);
    for (const providerId of Array.from(lastPrepareProviderSignatureByIdRef.current.keys())) {
      if (!selectedProviderIdSet.has(providerId)) {
        lastPrepareProviderSignatureByIdRef.current.delete(providerId);
        pendingPrepareProviderSignatureByIdRef.current.delete(providerId);
        prepareProviderRequestSeqByIdRef.current.delete(providerId);
        prepareWarningsByProviderIdRef.current.delete(providerId);
      }
    }

    const loadingProviderIds = selectedMemberProviders.filter((providerId) =>
      runtimeProviderLoadingById.get(providerId)
    );
    const readyProviderIds = selectedMemberProviders.filter(
      (providerId) => !runtimeProviderLoadingById.get(providerId)
    );
    const providerPlans = buildProviderPreparePlans({
      cwd: effectiveCwd,
      providerIds: readyProviderIds,
      selectedModelChecksByProvider,
      backendSummaryByProvider: runtimeBackendSummaryByProviderRef.current,
      limitContext: effectiveAnthropicRuntimeLimitContext,
      runtimeProviderStatusById,
      cachedModelResultsByCacheKey: prepareModelResultsCacheRef.current,
    });
    const changedPlans = providerPlans.filter((plan) => {
      const lastSignature = lastPrepareProviderSignatureByIdRef.current.get(plan.providerId);
      const pendingSignature = pendingPrepareProviderSignatureByIdRef.current.get(plan.providerId);
      return lastSignature !== plan.requestSignature && pendingSignature !== plan.requestSignature;
    });
    const loadingMessage = getProvisioningProviderProgressMessage(
      [...loadingProviderIds, ...changedPlans.map((plan) => plan.providerId)],
      selectedMemberProviders.length,
      t
    );
    const getSelectedWarnings = (): string[] =>
      selectedMemberProviders.flatMap(
        (providerId) => prepareWarningsByProviderIdRef.current.get(providerId) ?? []
      );
    const commitChecks = (nextChecks: ProvisioningProviderCheck[]): void => {
      prepareChecksRef.current = nextChecks;
      setPrepareChecks(nextChecks);
    };
    const applyPrepareOutcome = (
      nextChecks: ProvisioningProviderCheck[],
      pendingMessage: string | null
    ): void => {
      const selectedWarnings = getSelectedWarnings();
      setPrepareWarnings(selectedWarnings);

      if (nextChecks.some((check) => check.status === 'pending' || check.status === 'checking')) {
        setPrepareState('loading');
        setPrepareMessage(pendingMessage);
        return;
      }

      const anyFailure = nextChecks.some((check) => check.status === 'failed');
      const anyNotes =
        selectedWarnings.length > 0 || nextChecks.some((check) => check.status === 'notes');
      const failureMessage =
        getPrimaryProvisioningFailureDetail(nextChecks) ??
        t('create.prepare.someProvidersNeedAttention');
      setPrepareState(anyFailure ? 'failed' : 'ready');
      setPrepareMessage(
        anyFailure
          ? failureMessage
          : anyNotes
            ? t('create.prepare.readyWithNotes')
            : t('create.prepare.ready')
      );
    };

    let checks = alignProvisioningChecks(prepareChecksRef.current, selectedMemberProviders);
    for (const providerId of loadingProviderIds) {
      lastPrepareProviderSignatureByIdRef.current.delete(providerId);
      pendingPrepareProviderSignatureByIdRef.current.delete(providerId);
      prepareProviderRequestSeqByIdRef.current.delete(providerId);
      prepareWarningsByProviderIdRef.current.delete(providerId);
      checks = updateProviderCheck(checks, providerId, {
        status: 'checking',
        backendSummary: runtimeBackendSummaryByProviderRef.current.get(providerId) ?? null,
        details: [
          `${getProviderLabel(providerId)} provider status is still loading. Model checks will start automatically.`,
        ],
        supportDiagnostics: undefined,
      });
    }
    for (const plan of changedPlans) {
      checks = updateProviderCheck(checks, plan.providerId, {
        status: plan.selectedModelIds.length > 0 ? plan.cachedSnapshot.status : 'checking',
        backendSummary: plan.backendSummary,
        details: plan.cachedSnapshot.details,
        supportDiagnostics: undefined,
      });
      prepareWarningsByProviderIdRef.current.delete(plan.providerId);
    }
    commitChecks(checks);
    applyPrepareOutcome(
      checks,
      changedPlans.length > 0
        ? loadingMessage
        : (prepareMessageRef.current ??
            getProvisioningProviderProgressMessage([], selectedMemberProviders.length, t))
    );

    if (changedPlans.length === 0) {
      return;
    }

    for (const plan of changedPlans) {
      pendingPrepareProviderSignatureByIdRef.current.set(plan.providerId, plan.requestSignature);
    }

    const idleHandle = scheduleIdle(() => {
      prepareIdleHandlesRef.current.delete(idleHandle);
      const generation = prepareRequestSeqRef.current;
      const runningPlans = changedPlans.flatMap((plan) => {
        if (
          pendingPrepareProviderSignatureByIdRef.current.get(plan.providerId) !==
          plan.requestSignature
        ) {
          return [];
        }
        pendingPrepareProviderSignatureByIdRef.current.delete(plan.providerId);
        const requestSeq = (prepareProviderRequestSeqByIdRef.current.get(plan.providerId) ?? 0) + 1;
        prepareProviderRequestSeqByIdRef.current.set(plan.providerId, requestSeq);
        lastPrepareProviderSignatureByIdRef.current.set(plan.providerId, plan.requestSignature);
        return [{ ...plan, requestSeq }];
      });
      if (runningPlans.length === 0) {
        return;
      }
      const isPlanCurrent = (plan: ProviderPreparePlan & { requestSeq: number }): boolean =>
        prepareRequestSeqRef.current === generation &&
        lastPrepareProviderSignatureByIdRef.current.get(plan.providerId) ===
          plan.requestSignature &&
        prepareProviderRequestSeqByIdRef.current.get(plan.providerId) === plan.requestSeq &&
        !pendingPrepareProviderSignatureByIdRef.current.has(plan.providerId);
      void (async () => {
        await Promise.all(
          runningPlans.map(async (plan) => {
            try {
              const prepResult = await runProviderPrepareDiagnostics({
                cwd: effectiveCwd,
                providerId: plan.providerId,
                selectedModelIds: plan.selectedModelIds,
                selectedModelChecks: plan.selectedModelChecks,
                prepareProvisioning: api.teams.prepareProvisioning,
                limitContext: effectiveAnthropicRuntimeLimitContext,
                cachedModelResultsById: plan.cachedModelResultsById,
                onModelProgress: ({ status, details }) => {
                  if (!isPlanCurrent(plan)) {
                    return;
                  }
                  const nextChecks = updateProviderCheck(
                    prepareChecksRef.current,
                    plan.providerId,
                    {
                      status,
                      backendSummary: plan.backendSummary,
                      details,
                      supportDiagnostics: undefined,
                    }
                  );
                  commitChecks(nextChecks);
                  applyPrepareOutcome(nextChecks, loadingMessage);
                },
              });
              if (!isPlanCurrent(plan)) {
                return;
              }
              prepareWarningsByProviderIdRef.current.set(
                plan.providerId,
                prepResult.warnings.map(
                  (warning) => `${getProviderLabel(plan.providerId)}: ${warning}`
                )
              );
              prepareModelResultsCacheRef.current.set(
                plan.cacheKey,
                mergeReusableProviderPrepareModelResults(
                  prepareModelResultsCacheRef.current.get(plan.cacheKey),
                  prepResult.modelResultsById
                )
              );
              storeShortLivedProviderPrepareModelResults({
                providerId: plan.providerId,
                cacheKey: plan.cacheKey,
                modelResultsById: prepResult.modelResultsById,
              });
              const nextChecks = updateProviderCheck(prepareChecksRef.current, plan.providerId, {
                status: prepResult.status,
                backendSummary: plan.backendSummary,
                details: prepResult.details,
                supportDiagnostics: prepResult.supportDiagnostics,
              });
              commitChecks(nextChecks);
              applyPrepareOutcome(nextChecks, loadingMessage);
            } catch (error) {
              if (!isPlanCurrent(plan)) {
                return;
              }
              const failureMessage =
                error instanceof Error ? error.message : t('create.prepare.failed');
              const nextChecks = updateProviderCheck(prepareChecksRef.current, plan.providerId, {
                status: 'failed',
                backendSummary: plan.backendSummary,
                details: [failureMessage],
                supportDiagnostics: undefined,
              });
              prepareWarningsByProviderIdRef.current.delete(plan.providerId);
              commitChecks(nextChecks);
              applyPrepareOutcome(nextChecks, failureMessage);
            }
          })
        );
      })();
    });
    prepareIdleHandlesRef.current.add(idleHandle);
  }, [
    open,
    canCreate,
    launchTeam,
    effectiveCwd,
    effectiveMemberDrafts,
    effectiveAnthropicRuntimeLimitContext,
    prepareProviderInvalidationEpochById,
    runtimeProviderStatusById,
    runtimeProviderLoadingById,
    selectedModel,
    selectedModelChecksByProvider,
    selectedModelChecksByProviderSignature,
    selectedProviderId,
    selectedMemberProviders,
    t,
  ]);

  useEffect(() => {
    if (!open) {
      setWorkflowMentionSuggestionsEnabled(false);
      return;
    }

    setProjectsLoading(true);
    setProjectsError(null);

    let cancelled = false;
    void (async () => {
      try {
        const nextProjects = await loadProjectPathProjects({ defaultProjectPath });
        if (cancelled) {
          return;
        }

        setProjects(nextProjects);
      } catch (error) {
        if (cancelled) {
          return;
        }
        setProjectsError(
          error instanceof Error ? error.message : t('create.errors.loadProjectsFailed')
        );
        setProjects([]);
      } finally {
        if (!cancelled) {
          setProjectsLoading(false);
        }
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [open, defaultProjectPath, t]);

  useEffect(() => {
    if (!open || !draftLoaded) {
      return;
    }

    if (initialData) {
      const nextSyncModelsWithLead = !initialData.members.some(
        (member) => member.providerId || member.model || member.effort
      );
      setTeamName(initialData.teamName);
      descriptionDraft.setValue(initialData.description ?? '');
      setTeamColor(initialData.color ?? '');
      setMembers(
        initialData.members.map((m) => {
          const presetRoles: readonly string[] = PRESET_ROLES;
          const isPreset = m.role != null && presetRoles.includes(m.role);
          const isCustom = m.role != null && m.role.length > 0 && !isPreset;
          return normalizeMemberDraftForProviderMode(
            createMemberDraft({
              name: m.name,
              roleSelection: isCustom ? CUSTOM_ROLE : (m.role ?? ''),
              customRole: isCustom ? m.role : '',
              workflow: m.workflow,
              isolation: m.isolation === 'worktree' ? 'worktree' : undefined,
              providerId: normalizeOptionalTeamProviderId(m.providerId),
              model: m.model ?? '',
              effort: m.effort,
              mcpPolicy: m.mcpPolicy,
            }),
            multimodelEnabled
          );
        })
      );
      setTeammateWorktreeDefault(
        initialData.members.length > 0 &&
          initialData.members.every((member) => member.isolation === 'worktree')
      );
      setSyncModelsWithLead(nextSyncModelsWithLead, { persistStoredPreference: false });
      return;
    }

    if (members.length > 0) {
      return;
    }

    const nextDefaultMembers = DEFAULT_MEMBERS.map((member) =>
      createMemberDraft({
        name: member.name,
        roleSelection: member.roleSelection,
        workflow: member.workflow,
      })
    );
    setMembers(
      syncModelsWithLead
        ? nextDefaultMembers
        : applyStoredCreateTeamMemberRuntimePreferences(nextDefaultMembers)
    );
    // eslint-disable-next-line react-hooks/exhaustive-deps -- initialData is checked once on open/draftLoaded
  }, [open, draftLoaded]);

  useEffect(() => {
    if (!open || !draftLoaded || initialData || syncModelsWithLead || members.length === 0) {
      return;
    }
    persistCurrentMemberRuntimePreferences(members);
  }, [
    draftLoaded,
    initialData,
    members,
    open,
    persistCurrentMemberRuntimePreferences,
    syncModelsWithLead,
  ]);

  useEffect(() => {
    if (!open || initialData || !draftLoaded) {
      return;
    }
    if (teamName.trim().length === 0) {
      setTeamName(suggestedTeamName);
    }
  }, [initialData, open, suggestedTeamName, draftLoaded]); // eslint-disable-line react-hooks/exhaustive-deps -- teamName read once

  useEffect(() => {
    if (!open || initialData) {
      return;
    }
    const resolvedTeamName = teamName.trim() || suggestedTeamName;
    const nextAutoDescription = buildDefaultTeamDescription(resolvedTeamName);
    const currentDescription = descriptionDraft.value.trim();
    const previousAutoDescription = lastAutoDescriptionRef.current?.trim() ?? '';
    const shouldSyncDescription =
      currentDescription.length === 0 || currentDescription === previousAutoDescription;

    if (shouldSyncDescription && descriptionDraft.value !== nextAutoDescription) {
      lastAutoDescriptionRef.current = nextAutoDescription;
      descriptionDraft.setValue(nextAutoDescription);
      return;
    }

    if (currentDescription === nextAutoDescription) {
      lastAutoDescriptionRef.current = nextAutoDescription;
    }
  }, [descriptionDraft, initialData, open, suggestedTeamName, teamName]);

  // Pre-select defaultProjectPath when projects loaded (only while dialog is open)
  useEffect(() => {
    if (!open) {
      appliedDefaultProjectPathRef.current = null;
      return;
    }
    if (cwdMode !== 'project') {
      return;
    }
    const selectableProjects = projects.filter(isSelectableProjectPathProject);
    if (selectableProjects.length === 0) {
      return;
    }
    if (defaultProjectPath && !isEphemeralProjectPath(defaultProjectPath)) {
      const normalizedDefaultProjectPath = normalizePath(defaultProjectPath);
      const defaultAlreadyApplied =
        appliedDefaultProjectPathRef.current === normalizedDefaultProjectPath;
      const match = selectableProjects.find(
        (p) => normalizePath(p.path) === normalizedDefaultProjectPath
      );
      if (match && !defaultAlreadyApplied) {
        appliedDefaultProjectPathRef.current = normalizedDefaultProjectPath;
        if (normalizePath(selectedProjectPath) !== normalizedDefaultProjectPath) {
          setSelectedProjectPath(match.path);
        }
        return;
      }
    }
    if (selectedProjectPath) {
      return;
    }
    if (defaultProjectPath && !isEphemeralProjectPath(defaultProjectPath)) {
      const normalizedDefaultProjectPath = normalizePath(defaultProjectPath);
      const match = selectableProjects.find(
        (p) => normalizePath(p.path) === normalizedDefaultProjectPath
      );
      if (match) {
        setSelectedProjectPath(match.path);
        return;
      }
    }
    setSelectedProjectPath(selectableProjects[0].path);
  }, [open, cwdMode, projects, selectedProjectPath, defaultProjectPath, setSelectedProjectPath]);

  useEffect(() => {
    if (!open || cwdMode !== 'project' || !selectedProjectPath) {
      return;
    }
    if (
      !isEphemeralProjectPath(selectedProjectPath) &&
      !isDeletedProjectPathSelection(projects, selectedProjectPath)
    ) {
      return;
    }
    setSelectedProjectPath('');
  }, [open, cwdMode, projects, selectedProjectPath, setSelectedProjectPath]);

  const { suggestions: taskSuggestions } = useTaskSuggestions(null, {
    enabled: workflowMentionSuggestionsEnabled,
  });
  const { suggestions: teamMentionSuggestions } = useTeamSuggestions(null, {
    enabled: workflowMentionSuggestionsEnabled,
  });

  const description = descriptionDraft.value;
  const prompt = promptDraft.value;
  const memberColorMap = useMemo(() => buildMemberDraftColorMap(members), [members]);

  const mentionSuggestions = useMemo(
    () =>
      soloTeam
        ? [
            {
              id: 'team-lead',
              name: 'team-lead',
              subtitle: 'Team Lead',
              color: resolveTeamLeadColorName(),
            },
          ]
        : buildMemberDraftSuggestions(members, memberColorMap),
    [memberColorMap, members, soloTeam]
  );

  const effectiveModel = useMemo(
    () =>
      computeEffectiveTeamModel(
        selectedModel,
        effectiveAnthropicRuntimeLimitContext,
        selectedProviderId,
        runtimeProviderStatusById.get(selectedProviderId)
      ),
    [
      effectiveAnthropicRuntimeLimitContext,
      runtimeProviderStatusById,
      selectedModel,
      selectedProviderId,
    ]
  );
  const teammateRuntimeCompatibility = useMemo(
    () =>
      analyzeTeammateRuntimeCompatibility({
        leadProviderId: selectedProviderId,
        leadProviderBackendId: selectedProviderBackendId,
        members: effectiveMemberDrafts,
        soloTeam: soloTeam || !canCreate,
        extraCliArgs: launchTeam ? customArgs : undefined,
        tmuxStatus: tmuxRuntime.status,
        tmuxStatusLoading: tmuxRuntime.loading,
        tmuxStatusError: tmuxRuntime.error,
      }),
    [
      customArgs,
      effectiveMemberDrafts,
      launchTeam,
      canCreate,
      selectedProviderBackendId,
      selectedProviderId,
      soloTeam,
      tmuxRuntime.error,
      tmuxRuntime.loading,
      tmuxRuntime.status,
    ]
  );
  const teammateRuntimeProviderNoticeById:
    | Partial<Record<TeamProviderId, React.ReactNode>>
    | undefined = teammateRuntimeCompatibility.providerNoticeProviderId
    ? {
        [teammateRuntimeCompatibility.providerNoticeProviderId]: (
          <TeammateRuntimeCompatibilityNotice
            analysis={teammateRuntimeCompatibility}
            onOpenDashboard={() => {
              onClose();
              openDashboard();
            }}
          />
        ),
      }
    : undefined;
  const showRosterTeammateRuntimeCompatibility =
    teammateRuntimeCompatibility.visible && !teammateRuntimeCompatibility.providerNoticeProviderId;
  const anthropicRuntimeSelection = useMemo(
    () =>
      selectedProviderId === 'anthropic'
        ? resolveAnthropicRuntimeSelection({
            source: {
              modelCatalog: runtimeProviderStatusById.get('anthropic')?.modelCatalog,
              runtimeCapabilities: runtimeProviderStatusById.get('anthropic')?.runtimeCapabilities,
            },
            selectedModel,
            limitContext: effectiveAnthropicRuntimeLimitContext,
          })
        : null,
    [
      effectiveAnthropicRuntimeLimitContext,
      runtimeProviderStatusById,
      selectedModel,
      selectedProviderId,
    ]
  );
  const anthropicFastModeResolution = useMemo(
    () =>
      selectedProviderId === 'anthropic' && anthropicRuntimeSelection
        ? resolveAnthropicFastMode({
            selection: anthropicRuntimeSelection,
            selectedFastMode,
            providerFastModeDefault: anthropicProviderFastModeDefault,
          })
        : null,
    [
      anthropicProviderFastModeDefault,
      anthropicRuntimeSelection,
      selectedFastMode,
      selectedProviderId,
    ]
  );
  const codexRuntimeSelection = useMemo(
    () =>
      selectedProviderId === 'codex'
        ? resolveCodexRuntimeSelection({
            source: {
              providerStatus: runtimeProviderStatusById.get('codex'),
              providerBackendId: resolveUiOwnedProviderBackendId(
                'codex',
                runtimeProviderStatusById.get('codex')
              ),
            },
            selectedModel,
          })
        : null,
    [runtimeProviderStatusById, selectedModel, selectedProviderId]
  );
  const codexFastModeResolution = useMemo(
    () =>
      selectedProviderId === 'codex' && codexRuntimeSelection
        ? resolveCodexFastMode({
            selection: codexRuntimeSelection,
            selectedFastMode,
          })
        : null,
    [codexRuntimeSelection, selectedFastMode, selectedProviderId]
  );

  useEffect(() => {
    if (selectedProviderId !== 'anthropic' && selectedProviderId !== 'codex') {
      setAnthropicRuntimeNotice(null);
      return;
    }

    const reconciliation =
      selectedProviderId === 'anthropic'
        ? reconcileAnthropicRuntimeSelections({
            selection:
              anthropicRuntimeSelection ??
              resolveAnthropicRuntimeSelection({
                source: {
                  modelCatalog: null,
                  runtimeCapabilities: null,
                },
                selectedModel,
                limitContext: effectiveAnthropicRuntimeLimitContext,
              }),
            selectedEffort: selectedEffortForCurrentSelection,
            selectedFastMode,
            providerFastModeDefault: anthropicProviderFastModeDefault,
            runtimeCapabilities: runtimeProviderStatusById.get('anthropic')?.runtimeCapabilities,
          })
        : {
            nextEffort: selectedEffortForCurrentSelection,
            effortResetReason: null,
            ...reconcileCodexRuntimeSelections({
              selection:
                codexRuntimeSelection ??
                resolveCodexRuntimeSelection({
                  source: {
                    providerStatus: runtimeProviderStatusById.get('codex'),
                    providerBackendId: resolveUiOwnedProviderBackendId(
                      'codex',
                      runtimeProviderStatusById.get('codex')
                    ),
                  },
                  selectedModel,
                }),
              selectedFastMode,
            }),
          };

    const notices: string[] = [];
    if (selectedEffortForCurrentSelection !== selectedEffort) {
      setSelectedEffortRaw(selectedEffortForCurrentSelection);
      setStoredCreateTeamEffort(selectedEffortForCurrentSelection);
    }
    if (reconciliation.nextEffort !== selectedEffortForCurrentSelection) {
      setSelectedEffortRaw(reconciliation.nextEffort);
      setStoredCreateTeamEffort(reconciliation.nextEffort);
      if (reconciliation.effortResetReason) {
        notices.push(reconciliation.effortResetReason);
      }
    }
    if (reconciliation.nextFastMode !== selectedFastMode) {
      setSelectedFastModeRaw(reconciliation.nextFastMode);
      setStoredCreateTeamFastMode(reconciliation.nextFastMode);
      if (reconciliation.fastModeResetReason) {
        notices.push(reconciliation.fastModeResetReason);
      }
    }
    setAnthropicRuntimeNotice(notices.length > 0 ? notices.join(' ') : null);
  }, [
    anthropicProviderFastModeDefault,
    anthropicRuntimeSelection,
    codexRuntimeSelection,
    effectiveAnthropicRuntimeLimitContext,
    runtimeProviderStatusById,
    selectedEffort,
    selectedEffortForCurrentSelection,
    selectedFastMode,
    selectedModel,
    selectedProviderId,
  ]);

  const sanitizedTeamName = sanitizeTeamName(teamName.trim());
  const teamNameInlineError = validateTeamNameInline(teamName, t);
  const isNameTakenByExistingTeam = existingTeamNames.includes(sanitizedTeamName);
  const isNameProvisioning =
    provisioningTeamNames.includes(sanitizedTeamName) && !isNameTakenByExistingTeam;

  const request = useMemo<TeamCreateRequest>(
    () => ({
      teamName: sanitizedTeamName,
      description: description.trim() || undefined,
      color: teamColor || undefined,
      members: soloTeam
        ? []
        : buildMembersFromDrafts(effectiveMemberDrafts, {
            inheritedProviderId: selectedProviderId,
          }),
      cwd: effectiveCwd,
      prompt: prompt.trim() || undefined,
      providerId: selectedProviderId,
      providerBackendId: selectedProviderBackendId ?? undefined,
      model: effectiveModel,
      effort: (selectedEffortForCurrentSelection as EffortLevel) || undefined,
      fastMode:
        selectedProviderId === 'anthropic' || selectedProviderId === 'codex'
          ? selectedFastMode
          : undefined,
      limitContext: effectiveAnthropicRuntimeLimitContext,
      skipPermissions,
      worktree: worktreeEnabled && worktreeName.trim() ? worktreeName.trim() : undefined,
      extraCliArgs: customArgs.trim() || undefined,
    }),
    [
      sanitizedTeamName,
      description,
      teamColor,
      soloTeam,
      effectiveMemberDrafts,
      effectiveCwd,
      prompt,
      selectedProviderId,
      selectedProviderBackendId,
      effectiveModel,
      selectedEffortForCurrentSelection,
      selectedFastMode,
      effectiveAnthropicRuntimeLimitContext,
      skipPermissions,
      worktreeEnabled,
      worktreeName,
      customArgs,
    ]
  );
  const requestValidation = useMemo(
    () => validateRequest(request, t, { requireCwd: launchTeam }),
    [request, launchTeam, t]
  );
  const modelValidationError = useMemo(() => {
    if (selectedProviderId === 'opencode') {
      if (!selectedModel.trim()) {
        return t('create.validation.openCodeLeadModelRequired');
      }
      const activeMemberCount = soloTeam
        ? 0
        : effectiveMemberDrafts.filter((member) => !member.removedAt && member.name.trim()).length;
      if (activeMemberCount === 0) {
        return t('create.validation.openCodeTeammateRequired');
      }
    }

    if (!runtimeProviderLoadingById.get(selectedProviderId)) {
      const leadError = getTeamModelSelectionError(
        selectedProviderId,
        selectedModel,
        runtimeProviderStatusById.get(selectedProviderId)
      );
      if (leadError) {
        return leadError;
      }
    }

    for (const member of effectiveMemberDrafts) {
      if (member.removedAt) {
        continue;
      }

      const providerId = normalizeOptionalTeamProviderId(member.providerId) ?? selectedProviderId;
      if (runtimeProviderLoadingById.get(providerId)) {
        continue;
      }
      const memberError = getTeamModelSelectionError(
        providerId,
        member.model,
        runtimeProviderStatusById.get(providerId)
      );
      if (!memberError) {
        continue;
      }

      const memberName = member.name.trim();
      return memberName ? `${memberName}: ${memberError}` : memberError;
    }

    return null;
  }, [
    effectiveMemberDrafts,
    runtimeProviderStatusById,
    runtimeProviderLoadingById,
    selectedModel,
    selectedProviderId,
    soloTeam,
    t,
  ]);
  const leadModelIssueText = useMemo(() => {
    const issue = getProvisioningModelIssue(
      prepareChecks,
      selectedProviderId,
      effectiveModel ?? selectedModel
    );
    return issue?.reason ?? issue?.detail ?? null;
  }, [effectiveModel, prepareChecks, selectedModel, selectedProviderId]);
  const memberModelIssueById = useMemo(() => {
    const next: Record<string, string> = {};
    for (const member of effectiveMemberDrafts) {
      if (member.removedAt) {
        continue;
      }
      if (syncModelsWithLead && leadModelIssueText) {
        next[member.id] = leadModelIssueText;
        continue;
      }
      const providerId = normalizeOptionalTeamProviderId(member.providerId) ?? selectedProviderId;
      const issue = getProvisioningModelIssue(prepareChecks, providerId, member.model);
      const issueText = issue?.reason ?? issue?.detail ?? null;
      if (issueText) {
        next[member.id] = issueText;
      }
    }
    return next;
  }, [
    effectiveMemberDrafts,
    leadModelIssueText,
    prepareChecks,
    selectedProviderId,
    syncModelsWithLead,
  ]);
  const hasCreateFormErrors =
    !!teamNameInlineError ||
    isNameTakenByExistingTeam ||
    isNameProvisioning ||
    !requestValidation.valid ||
    !!modelValidationError ||
    teammateRuntimeCompatibility.blocksSubmission ||
    worktreeGitBlocksSubmission;

  const internalArgs = useMemo(() => {
    const args: string[] = [];
    args.push('--input-format', 'stream-json', '--output-format', 'stream-json');
    args.push('--verbose', '--setting-sources', 'user,project,local');
    args.push('--mcp-config', '<auto>', '--disallowedTools', APP_TEAM_RUNTIME_DISALLOWED_TOOLS);
    if (skipPermissions) args.push('--dangerously-skip-permissions');
    if (effectiveModel) args.push('--model', effectiveModel);
    const effectiveEffort =
      selectedProviderId === 'anthropic'
        ? selectedEffortForCurrentSelection || anthropicRuntimeSelection?.defaultEffort || ''
        : selectedEffortForCurrentSelection;
    if (effectiveEffort) args.push('--effort', effectiveEffort);
    if (selectedProviderId === 'anthropic') {
      const fastSettings = anthropicFastModeResolution?.resolvedFastMode
        ? { fastMode: true, fastModePerSessionOptIn: false }
        : { fastMode: false };
      args.push('--settings', JSON.stringify(fastSettings));
    } else if (selectedProviderId === 'codex') {
      args.push(...buildCodexFastModeArgs(codexFastModeResolution?.resolvedFastMode));
    }
    return args;
  }, [
    anthropicFastModeResolution?.resolvedFastMode,
    anthropicRuntimeSelection?.defaultEffort,
    codexFastModeResolution?.resolvedFastMode,
    effectiveModel,
    selectedEffortForCurrentSelection,
    selectedProviderId,
    skipPermissions,
  ]);

  const launchOptionalSummary = useMemo(() => {
    const summary: string[] = [];
    if (prompt.trim()) summary.push('Lead prompt');
    if (skipPermissions) summary.push('Auto-approve tools');
    if (selectedProviderId === 'anthropic' || selectedProviderId === 'codex') {
      if (selectedFastMode === 'on') summary.push('Fast mode');
      else if (selectedFastMode === 'off') summary.push('Fast disabled');
      else if (selectedProviderId === 'anthropic' && anthropicProviderFastModeDefault) {
        summary.push('Fast default');
      }
    }
    if (effectiveAnthropicRuntimeLimitContext) {
      summary.push('Anthropic limited to 200K context');
    }
    if (worktreeEnabled && worktreeName.trim()) summary.push(`Worktree: ${worktreeName.trim()}`);
    if (customArgs.trim()) summary.push('Custom CLI args');
    return summary;
  }, [
    anthropicProviderFastModeDefault,
    customArgs,
    effectiveAnthropicRuntimeLimitContext,
    prompt,
    selectedFastMode,
    selectedProviderId,
    skipPermissions,
    worktreeEnabled,
    worktreeName,
  ]);

  const teamDetailsSummary = useMemo(() => {
    const summary: string[] = [];
    if (description.trim()) summary.push('Description');
    if (teamColor) summary.push(`Color: ${teamColor}`);
    return summary;
  }, [description, teamColor]);

  const handleSyncModelsWithLeadChange = useCallback(
    (checked: boolean): void => {
      setSyncModelsWithLead(checked);
      if (checked) {
        persistCurrentMemberRuntimePreferences(members);
        setMembers(members.map(clearMemberModelOverrides));
        return;
      }

      if (getStoredCreateTeamMemberRuntimePreferences().length === 0) {
        return;
      }

      const nextMembers = applyStoredCreateTeamMemberRuntimePreferences(members);
      const hasRuntimeChanges = nextMembers.some((member, index) => {
        const previousMember = members[index];
        return (
          member.providerId !== previousMember?.providerId ||
          member.model !== previousMember?.model ||
          member.effort !== previousMember?.effort
        );
      });
      if (hasRuntimeChanges) {
        setMembers(nextMembers);
      }
    },
    [members, persistCurrentMemberRuntimePreferences, setMembers, setSyncModelsWithLead]
  );

  const activeError =
    localError ?? modelValidationError ?? provisioningErrorsByTeam[request.teamName] ?? null;
  const effectivePrepare = useMemo(
    () =>
      deriveEffectiveProvisioningPrepareState({
        state: prepareState,
        message: prepareMessage,
        warnings: prepareWarnings,
        checks: prepareChecks,
        t,
      }),
    [prepareChecks, prepareMessage, prepareState, prepareWarnings, t]
  );
  const showCodexReconnectPrompt = shouldShowCodexReconnectPrompt({
    effectiveCliStatus,
    selectedProviderIds: selectedMemberProviders,
    prepareMessage: effectivePrepare.message,
    prepareChecks,
  });
  const canOpenExistingTeam =
    activeError?.includes('Team already exists') === true && request.teamName.length > 0;

  const conflictingTeam = useMemo(() => {
    if (!launchTeam) return null;
    if (!activeTeams?.length || !effectiveCwd) return null;
    const norm = normalizePath(effectiveCwd);
    return activeTeams.find((t) => normalizePath(t.projectPath) === norm) ?? null;
  }, [activeTeams, effectiveCwd, launchTeam]);

  // Reset dismiss when conflict target changes
  useEffect(() => {
    setConflictDismissed(false);
  }, [conflictingTeam?.teamName, effectiveCwd]);

  const handleSubmit = (): void => {
    if (allTakenTeamNames.includes(sanitizedTeamName)) {
      const msg = isNameProvisioning
        ? t('create.validation.teamLaunching')
        : t('create.validation.teamNameExists');
      setFieldErrors({ teamName: msg });
      setLocalError(msg);
      return;
    }
    const validation = validateRequest(request, t, { requireCwd: launchTeam });
    if (!validation.valid) {
      const errors = validation.errors ?? {};
      setFieldErrors(errors);
      const messages = Object.values(errors).filter(Boolean);
      setLocalError(messages.join(' · ') || t('create.validation.checkFormFields'));
      return;
    }
    if (modelValidationError) {
      setLocalError(modelValidationError);
      return;
    }
    if (teammateRuntimeCompatibility.blocksSubmission) {
      setLocalError(teammateRuntimeCompatibility.message);
      return;
    }
    if (worktreeGitBlockingMessage) {
      setLocalError(worktreeGitBlockingMessage);
      return;
    }
    setFieldErrors({});
    setLocalError(null);
    setIsSubmitting(true);

    if (!launchTeam) {
      void (async () => {
        try {
          if (!syncModelsWithLead) {
            persistCurrentMemberRuntimePreferences(members);
          }
          await api.teams.createConfig({
            teamName: request.teamName,
            displayName: request.displayName,
            description: request.description,
            color: request.color,
            members: request.members,
            cwd: effectiveCwd || undefined,
            prompt: request.prompt,
            providerId: request.providerId,
            providerBackendId: request.providerBackendId,
            model: request.model,
            effort: request.effort,
            fastMode: request.fastMode,
            limitContext: request.limitContext,
            skipPermissions: request.skipPermissions,
            worktree: request.worktree,
            extraCliArgs: request.extraCliArgs,
          });
          onOpenTeam(request.teamName, effectiveCwd || undefined);
          resetFormState();
          onClose();
        } catch (error) {
          setLocalError(
            error instanceof Error ? error.message : t('create.errors.createConfigFailed')
          );
        } finally {
          setIsSubmitting(false);
        }
      })();
      return;
    }

    void (async () => {
      try {
        if (!syncModelsWithLead) {
          persistCurrentMemberRuntimePreferences(members);
        }
        await onCreate(request);
        onOpenTeam(request.teamName, effectiveCwd || undefined);
        resetFormState();
        onClose();
      } catch {
        // error is shown via provisioningError prop
      } finally {
        setIsSubmitting(false);
      }
    })();
  };

  const handleTeamNameChange = (value: string): void => {
    setTeamName(value);
    setFieldErrors((prev) => {
      if (!prev.teamName) return prev;
      // eslint-disable-next-line sonarjs/no-unused-vars -- destructured to omit teamName from rest
      const { teamName: _teamName, ...rest } = prev;
      const remaining = Object.values(rest).filter(Boolean);
      if (remaining.length === 0) {
        setLocalError(null);
      } else {
        setLocalError(remaining.join(' · '));
      }
      return rest;
    });
  };

  const rosterHeaderTop = useMemo(
    () => (
      <div className="flex items-center gap-2">
        <Checkbox
          id="solo-team"
          checked={soloTeam}
          onCheckedChange={(checked) => setSoloTeam(checked === true)}
        />
        <Label
          htmlFor="solo-team"
          className="cursor-pointer text-xs font-normal text-text-secondary"
        >
          {t('create.solo.label')}
        </Label>
      </div>
    ),
    [setSoloTeam, soloTeam, t]
  );

  const rosterHeaderBottom = useMemo(
    () =>
      showRosterTeammateRuntimeCompatibility ||
      soloTeam ||
      (canCreate && hasSelectedWorktreeIsolation) ? (
        <div className="space-y-2">
          {showRosterTeammateRuntimeCompatibility ? (
            <TeammateRuntimeCompatibilityNotice
              analysis={teammateRuntimeCompatibility}
              onOpenDashboard={() => {
                onClose();
                openDashboard();
              }}
            />
          ) : null}
          {soloTeam ? (
            <div className="flex items-start gap-2 rounded-md border border-sky-500/20 bg-sky-500/5 px-3 py-2">
              <Info className="mt-0.5 size-3.5 shrink-0 text-sky-400" />
              <p className="text-[11px] leading-relaxed text-sky-300">
                {t('create.solo.description')}
              </p>
            </div>
          ) : null}
          {canCreate && hasSelectedWorktreeIsolation ? (
            <WorktreeGitReadinessBanner state={worktreeGitReadiness} />
          ) : null}
        </div>
      ) : null,
    [
      canCreate,
      hasSelectedWorktreeIsolation,
      onClose,
      openDashboard,
      showRosterTeammateRuntimeCompatibility,
      soloTeam,
      teammateRuntimeCompatibility,
      t,
      worktreeGitReadiness,
    ]
  );

  return (
    <Dialog
      open={open}
      onOpenChange={(nextOpen) => {
        if (!nextOpen) {
          resetUIState();
          onClose();
        }
      }}
    >
      <DialogContent className="max-w-[52rem]">
        <DialogHeader>
          <DialogTitle className="text-sm">
            {initialData ? t('create.title.copy') : t('create.title.create')}
          </DialogTitle>
          <DialogDescription className="text-xs">
            {initialData ? t('create.description.copy') : t('create.description.create')}
          </DialogDescription>
        </DialogHeader>

        {conflictingTeam && !conflictDismissed ? (
          <div
            className="rounded-md border p-3 text-xs"
            style={{
              backgroundColor: 'var(--warning-bg)',
              borderColor: 'var(--warning-border)',
              color: 'var(--warning-text)',
            }}
          >
            <div className="flex items-start gap-2">
              <AlertTriangle className="mt-0.5 size-4 shrink-0" />
              <div className="min-w-0 flex-1 space-y-1">
                <p className="font-medium">
                  {t('create.conflict.title', { team: conflictingTeam.displayName })}
                </p>
                <p className="opacity-80">{t('create.conflict.description')}</p>
                <p className="text-[11px] opacity-70">
                  {t('create.conflict.workingDirectory')}{' '}
                  <span className="font-mono">{effectiveCwd}</span>
                </p>
              </div>
              <button
                type="button"
                className="shrink-0 rounded p-0.5 opacity-60 transition-colors hover:opacity-100"
                onClick={() => setConflictDismissed(true)}
              >
                <X className="size-3.5" />
              </button>
            </div>
          </div>
        ) : null}

        {!canCreate ? (
          <p
            className="rounded border p-2 text-xs"
            style={{
              backgroundColor: 'var(--warning-bg)',
              borderColor: 'var(--warning-border)',
              color: 'var(--warning-text)',
            }}
          >
            {t('create.localOnly')}
          </p>
        ) : null}

        <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
          <div className="space-y-1.5 md:col-span-2">
            <Label htmlFor="team-name">{t('create.fields.teamName')}</Label>
            <Input
              id="team-name"
              className={cn(
                'h-8 text-xs',
                (fieldErrors.teamName || teamNameInlineError || isNameTakenByExistingTeam) &&
                  'border-[var(--field-error-border)] bg-[var(--field-error-bg)] focus-visible:ring-[var(--field-error-border)]'
              )}
              value={teamName}
              onChange={(event) => handleTeamNameChange(event.target.value)}
              placeholder={suggestedTeamName}
            />
            {isNameTakenByExistingTeam ? (
              <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
                {t('create.errors.nameExists')}
              </p>
            ) : teamNameInlineError ? (
              <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
                {teamNameInlineError}
              </p>
            ) : isNameProvisioning ? (
              <p className="text-[11px]" style={{ color: 'var(--warning-text)' }}>
                {t('create.errors.nameLaunching')}
              </p>
            ) : fieldErrors.teamName ? (
              <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
                {fieldErrors.teamName}
              </p>
            ) : null}
            {sanitizedTeamName && sanitizedTeamName !== teamName.trim() ? (
              <p className="text-[11px] text-[var(--color-text-muted)]">
                {t('create.onDisk')} <span className="font-mono">{sanitizedTeamName}</span>
              </p>
            ) : null}
          </div>

          <div className="md:col-span-2">
            <TeamRosterEditorSection
              members={members}
              onMembersChange={setMembers}
              fieldError={fieldErrors.members}
              validateMemberName={validateMemberNameInline}
              showWorkflow
              showJsonEditor
              draftKeyPrefix="createTeam"
              projectPath={effectiveCwd || null}
              taskSuggestions={taskSuggestions}
              teamSuggestions={teamMentionSuggestions}
              onWorkflowSuggestionsNeeded={enableWorkflowMentionSuggestions}
              defaultProviderId={selectedProviderId}
              inheritedProviderId={selectedProviderId}
              inheritedModel={selectedModel}
              inheritedEffort={(selectedEffortForCurrentSelection as EffortLevel) || undefined}
              inheritModelSettingsByDefault
              lockProviderModel={syncModelsWithLead}
              forceInheritedModelSettings={syncModelsWithLead}
              modelLockReason="This teammate is synced with the lead model. Turn off sync to set a custom provider, model, or effort."
              hideMembersContent={soloTeam}
              providerId={selectedProviderId}
              model={selectedModel}
              effort={(selectedEffortForCurrentSelection as EffortLevel) || undefined}
              limitContext={effectiveAnthropicRuntimeLimitContext}
              leadProviderNoticeById={teammateRuntimeProviderNoticeById}
              onProviderChange={setSelectedProviderId}
              onModelChange={setSelectedModel}
              onEffortChange={setSelectedEffort}
              onLimitContextChange={setLimitContext}
              syncModelsWithTeammates={syncModelsWithLead}
              onSyncModelsWithTeammatesChange={handleSyncModelsWithLeadChange}
              showWorktreeIsolationControls={!soloTeam}
              teammateWorktreeDefault={teammateWorktreeDefault}
              worktreeIsolationDisabledReason={worktreeIsolationDisabledReason}
              onTeammateWorktreeDefaultChange={setTeammateWorktreeDefault}
              disableGeminiOption={isGeminiUiFrozen()}
              leadModelIssueText={leadModelIssueText}
              memberWarningById={teammateRuntimeCompatibility.memberWarningById}
              memberModelIssueById={memberModelIssueById}
              modelAdvisoryReasonByProvider={
                shortLivedModelIssueReasons.modelAdvisoryReasonByProvider
              }
              modelIssueReasonByProvider={shortLivedModelIssueReasons.modelIssueReasonByProvider}
              modelUnavailableReasonByProvider={
                shortLivedModelIssueReasons.modelUnavailableReasonByProvider
              }
              headerTop={rosterHeaderTop}
              headerBottom={rosterHeaderBottom}
            />
          </div>

          <div
            className="rounded-lg border border-[var(--color-border-emphasis)] p-4 shadow-sm md:col-span-2"
            style={{
              backgroundColor: isLight
                ? 'color-mix(in srgb, var(--color-surface-overlay) 24%, white 76%)'
                : 'var(--color-surface-overlay)',
            }}
          >
            <div className="flex items-start gap-3">
              <Checkbox
                id="launch-team"
                className="mt-1 shrink-0"
                checked={launchTeam}
                onCheckedChange={(checked) => setLaunchTeam(checked === true)}
              />
              <div className="space-y-1">
                <Label htmlFor="launch-team" className="cursor-pointer text-sm font-semibold">
                  {t('create.launchAfterCreate.label')}
                </Label>
                <p
                  className="text-xs"
                  style={{
                    color: isLight
                      ? 'color-mix(in srgb, var(--color-text-muted) 54%, var(--color-text) 46%)'
                      : 'var(--color-text-muted)',
                  }}
                >
                  {t('create.launchAfterCreate.description')}
                </p>
              </div>
            </div>

            {launchTeam ? (
              <div className="mt-4 space-y-4">
                <ProjectPathSelector
                  cwdMode={cwdMode}
                  onCwdModeChange={setCwdMode}
                  selectedProjectPath={selectedProjectPath}
                  onSelectedProjectPathChange={setSelectedProjectPath}
                  customCwd={customCwd}
                  onCustomCwdChange={setCustomCwd}
                  projects={projects}
                  projectsLoading={projectsLoading}
                  projectsError={projectsError}
                  fieldError={fieldErrors.cwd}
                />

                <OptionalSettingsSection
                  title={t('create.optional.launchSettingsTitle')}
                  description={t('create.optional.launchSettingsDescription')}
                  summary={launchOptionalSummary}
                  onOpenChange={(isOpen) => {
                    if (isOpen) {
                      enableWorkflowMentionSuggestions();
                    }
                  }}
                >
                  <div className="space-y-4">
                    {selectedProviderId === 'anthropic' ? (
                      <div className="space-y-2">
                        <AnthropicFastModeSelector
                          value={selectedFastMode}
                          onValueChange={setSelectedFastMode}
                          providerFastModeDefault={anthropicProviderFastModeDefault}
                          model={selectedModel}
                          limitContext={effectiveAnthropicRuntimeLimitContext}
                          id="create-fast-mode"
                        />
                        {anthropicRuntimeNotice ? (
                          <div className="bg-amber-500/8 flex items-start gap-2 rounded-md border border-amber-500/25 px-3 py-2 text-[11px] leading-relaxed text-amber-200">
                            <Info className="mt-0.5 size-3.5 shrink-0 text-amber-300" />
                            <p>{anthropicRuntimeNotice}</p>
                          </div>
                        ) : null}
                      </div>
                    ) : null}
                    {selectedProviderId === 'codex' ? (
                      <div className="space-y-2">
                        <CodexFastModeSelector
                          value={selectedFastMode}
                          onValueChange={setSelectedFastMode}
                          model={selectedModel}
                          providerBackendId={
                            resolveUiOwnedProviderBackendId(
                              'codex',
                              runtimeProviderStatusById.get('codex')
                            ) ?? undefined
                          }
                          id="create-fast-mode"
                        />
                        {anthropicRuntimeNotice ? (
                          <div className="bg-amber-500/8 flex items-start gap-2 rounded-md border border-amber-500/25 px-3 py-2 text-[11px] leading-relaxed text-amber-200">
                            <Info className="mt-0.5 size-3.5 shrink-0 text-amber-300" />
                            <p>{anthropicRuntimeNotice}</p>
                          </div>
                        ) : null}
                      </div>
                    ) : null}

                    <div className="space-y-1.5">
                      <Label htmlFor="team-prompt" className="label-optional">
                        {t('create.fields.prompt')}
                      </Label>
                      <MentionableTextarea
                        id="team-prompt"
                        className="text-xs"
                        minRows={3}
                        maxRows={12}
                        value={prompt}
                        onValueChange={promptDraft.setValue}
                        suggestions={soloTeam ? [] : mentionSuggestions}
                        teamSuggestions={teamMentionSuggestions}
                        taskSuggestions={taskSuggestions}
                        projectPath={effectiveCwd || null}
                        chips={promptChipDraft.chips}
                        onChipRemove={promptChipDraft.removeChip}
                        onFileChipInsert={promptChipDraft.addChip}
                        placeholder={t('create.placeholders.prompt')}
                        footerRight={
                          promptDraft.isSaved ? (
                            <span className="text-[10px] text-[var(--color-text-muted)]">
                              {t('create.saved')}
                            </span>
                          ) : null
                        }
                      />
                    </div>

                    <SkipPermissionsCheckbox
                      id="create-skip-permissions"
                      checked={skipPermissions}
                      onCheckedChange={setSkipPermissions}
                    />

                    <AdvancedCliSection
                      teamName={advancedKey}
                      internalArgs={internalArgs}
                      worktreeEnabled={worktreeEnabled}
                      onWorktreeEnabledChange={setWorktreeEnabled}
                      worktreeName={worktreeName}
                      onWorktreeNameChange={setWorktreeName}
                      customArgs={customArgs}
                      onCustomArgsChange={setCustomArgs}
                    />
                  </div>
                </OptionalSettingsSection>
              </div>
            ) : null}
          </div>

          <div className="md:col-span-2">
            <OptionalSettingsSection
              title={t('create.optional.teamDetailsTitle')}
              description={t('create.optional.teamDetailsDescription')}
              summary={teamDetailsSummary}
            >
              <div className="space-y-4">
                <div className="space-y-1.5">
                  <Label htmlFor="team-description" className="label-optional">
                    {t('create.fields.description')}
                  </Label>
                  <AutoResizeTextarea
                    id="team-description"
                    className="text-xs"
                    minRows={2}
                    maxRows={8}
                    value={description}
                    onChange={(event) => descriptionDraft.setValue(event.target.value)}
                    placeholder={t('create.placeholders.description')}
                  />
                  {descriptionDraft.isSaved ? (
                    <span className="text-[10px] text-[var(--color-text-muted)]">
                      {t('create.saved')}
                    </span>
                  ) : null}
                </div>

                <div className="space-y-1.5">
                  <Label className="label-optional">{t('create.fields.color')}</Label>
                  <div className="flex flex-wrap gap-2">
                    {TEAM_COLOR_NAMES.map((colorName) => {
                      const colorSet = getTeamColorSet(colorName);
                      const isSelected = teamColor === colorName;
                      return (
                        <button
                          key={colorName}
                          type="button"
                          className={cn(
                            'flex size-7 items-center justify-center rounded-full border-2 transition-all',
                            isSelected ? 'scale-110' : 'opacity-70 hover:opacity-100'
                          )}
                          style={{
                            backgroundColor: getThemedBadge(colorSet, isLight),
                            borderColor: isSelected ? colorSet.border : 'transparent',
                          }}
                          title={colorName}
                          onClick={() => setTeamColor(isSelected ? '' : colorName)}
                        >
                          <span
                            className="size-3.5 rounded-full"
                            style={{ backgroundColor: colorSet.border }}
                          />
                        </button>
                      );
                    })}
                  </div>
                </div>
              </div>
            </OptionalSettingsSection>
          </div>
        </div>

        {activeError ? (
          <p
            className="rounded border p-2 text-xs"
            style={{
              color: 'var(--field-error-text)',
              borderColor: 'var(--field-error-border)',
              backgroundColor: 'var(--field-error-bg)',
            }}
          >
            {activeError}
          </p>
        ) : null}

        <DialogFooter className="pt-4 sm:justify-between">
          <div className="min-w-0">
            {canCreate && launchTeam ? (
              <ProviderActivityStatusStrip
                cliStatus={effectiveCliStatus}
                sourceCliStatus={loadingCliStatus}
                cliStatusLoading={cliStatusLoading}
                cliProviderStatusLoading={cliProviderStatusLoading}
                multimodelEnabled={multimodelEnabled}
                codexSnapshotPending={codexSnapshotPending}
                providerIds={selectedMemberProviders}
                className="mb-2"
                label="Selected providers"
                layout="stacked"
                showReadyProviders={
                  effectivePrepare.state === 'idle' || effectivePrepare.state === 'loading'
                }
                readyStatusText="Ready"
              />
            ) : null}
            {canCreate &&
            launchTeam &&
            (effectivePrepare.state === 'idle' || effectivePrepare.state === 'loading') ? (
              <>
                <div className="flex items-center gap-2 text-xs text-[var(--color-text-muted)]">
                  <span className="inline-block size-3.5 animate-spin rounded-full border-2 border-current border-t-transparent" />
                  <div>
                    <span>
                      {effectivePrepare.message ??
                        (effectivePrepare.state === 'idle'
                          ? t('create.prepare.checkingProviders')
                          : t('create.prepare.preparingEnvironment'))}
                    </span>
                    <p className="mt-0.5 text-[10px] text-[var(--color-text-muted)] opacity-70">
                      {t('launch.prepare.preflight', {
                        action: t('launch.prepare.action.launch'),
                      })}
                    </p>
                  </div>
                </div>
                <ProvisioningProviderStatusList
                  checks={prepareChecks}
                  className="mt-2"
                  onOpenProviderSettings={(providerId) => setProviderSettingsProviderId(providerId)}
                />
              </>
            ) : null}

            {canCreate && launchTeam && effectivePrepare.state === 'ready' ? (
              <div>
                <div className="flex items-center gap-1.5 text-xs font-medium text-emerald-400">
                  <CheckCircle2 className="size-3.5 shrink-0" />
                  <span>
                    {prepareChecks.some((check) => check.status === 'notes') ||
                    prepareWarnings.length > 0
                      ? t('create.prepare.selectedProvidersReadyWithNotes')
                      : t('create.prepare.selectedProvidersReady')}
                  </span>
                </div>
                {effectivePrepare.message ? (
                  <p className="mt-0.5 pl-5 text-[11px] text-[var(--color-text-muted)]">
                    {effectivePrepare.message}
                  </p>
                ) : null}
                <ProvisioningProviderStatusList
                  checks={prepareChecks}
                  className="mt-1"
                  onOpenProviderSettings={(providerId) => setProviderSettingsProviderId(providerId)}
                />
                {prepareWarnings.length > 0 && prepareChecks.length === 0 ? (
                  <div className="mt-0.5 space-y-0.5 pl-5">
                    {prepareWarnings.map((warning, index) => (
                      <p key={`${index}:${warning}`} className="text-[11px] text-sky-300">
                        {warning}
                      </p>
                    ))}
                  </div>
                ) : null}
              </div>
            ) : null}

            {canCreate && launchTeam && effectivePrepare.state === 'failed' ? (
              <div className="text-xs">
                <div className="flex items-start gap-2 text-red-300">
                  <AlertTriangle className="mt-0.5 size-4 shrink-0" />
                  <div className="min-w-0">
                    <p className="font-medium">
                      {t('launch.prepare.blocked', {
                        action: t('launch.prepare.action.launch'),
                      })}
                    </p>
                    <p className="mt-0.5 text-red-300/80">
                      {effectivePrepare.message ?? t('launch.prepare.failed')}
                    </p>
                    <p className="mt-0.5 text-[10px] text-[var(--color-text-muted)] opacity-70">
                      {t('launch.prepare.preflight', {
                        action: t('launch.prepare.action.launch'),
                      })}
                    </p>
                  </div>
                </div>
                {!shouldHideProvisioningProviderStatusList(prepareChecks, prepareMessage) ? (
                  <ProvisioningProviderStatusList
                    checks={prepareChecks}
                    className="mt-2"
                    suppressDetailsMatching={prepareMessage}
                    onOpenProviderSettings={(providerId) =>
                      setProviderSettingsProviderId(providerId)
                    }
                  />
                ) : null}
                {prepareWarnings.length > 0 && prepareChecks.length === 0 ? (
                  <div className="mt-1 space-y-0.5 pl-6">
                    {prepareWarnings.map((warning, index) => (
                      <p
                        key={`${index}:${warning}`}
                        className="text-[11px]"
                        style={{ color: 'var(--warning-text)' }}
                      >
                        {warning}
                      </p>
                    ))}
                  </div>
                ) : null}
                <p className="mt-1 pl-6 text-[11px] text-[var(--color-text-muted)]">
                  {getProvisioningFailureHint(effectivePrepare.message, prepareChecks, t)}
                </p>
                {showCodexReconnectPrompt ? (
                  <div className="pl-6">
                    <CodexReconnectPrompt
                      authUrl={codexAccount.snapshot?.login.authUrl ?? null}
                      userCode={codexAccount.snapshot?.login.userCode ?? null}
                      reconnectBusy={codexAccount.loading}
                      onReconnect={() => handleCodexReconnect('browser')}
                      onDeviceCodeReconnect={() => handleCodexReconnect('device_code')}
                    />
                  </div>
                ) : null}
              </div>
            ) : null}
          </div>

          <div className="flex shrink-0 items-center gap-2">
            {canOpenExistingTeam ? (
              <Button
                variant="outline"
                size="sm"
                onClick={() => {
                  onOpenTeam(request.teamName);
                  onClose();
                }}
              >
                {t('create.actions.openExisting')}
              </Button>
            ) : null}
            <Button
              size="lg"
              className="min-w-32 text-sm"
              disabled={!canCreate || !draftLoaded || isSubmitting || hasCreateFormErrors}
              onClick={handleSubmit}
            >
              {isSubmitting ? (
                <>
                  <Loader2 className="mr-1.5 size-3.5 animate-spin" />
                  {t('create.actions.creating')}
                </>
              ) : launchTeam &&
                (effectivePrepare.state === 'idle' || effectivePrepare.state === 'loading') ? (
                t('create.actions.skipPreflightAndCreate')
              ) : (
                t('create.actions.create')
              )}
            </Button>
          </div>
        </DialogFooter>
      </DialogContent>
      <ProvisioningProviderRuntimeSettingsDialog
        openProviderId={providerSettingsProviderId}
        onOpenProviderIdChange={(providerId) => setProviderSettingsProviderId(providerId)}
        providers={effectiveCliStatus?.providers ?? []}
        projectPath={effectiveCwd || null}
        disabled={isSubmitting}
        onProviderRuntimeChanged={invalidatePrepareProvider}
      />
    </Dialog>
  );
};
