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

import { api } from '@renderer/api';
import { ExtendedContextCheckbox } from '@renderer/components/team/dialogs/ExtendedContextCheckbox';
import { SkipPermissionsCheckbox } from '@renderer/components/team/dialogs/SkipPermissionsCheckbox';
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 { Label } from '@renderer/components/ui/label';
import { MentionableTextarea } from '@renderer/components/ui/MentionableTextarea';
import { useChipDraftPersistence } from '@renderer/hooks/useChipDraftPersistence';
import { useDraftPersistence } from '@renderer/hooks/useDraftPersistence';
import { useFileListCacheWarmer } from '@renderer/hooks/useFileListCacheWarmer';
import { useStore } from '@renderer/store';
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
import { normalizePath } from '@renderer/utils/pathNormalize';
import { AlertTriangle, CheckCircle2, Loader2, RotateCcw, X } from 'lucide-react';

import { EffortLevelSelector } from './EffortLevelSelector';
import { ProjectPathSelector } from './ProjectPathSelector';
import { computeEffectiveTeamModel, TeamModelSelector } from './TeamModelSelector';

import type { ActiveTeamRef } from './CreateTeamDialog';
import type { MentionSuggestion } from '@renderer/types/mention';
import type {
  EffortLevel,
  Project,
  ResolvedTeamMember,
  TeamLaunchRequest,
  TeamProvisioningPrepareResult,
} from '@shared/types';

interface LaunchTeamDialogProps {
  open: boolean;
  teamName: string;
  members: ResolvedTeamMember[];
  defaultProjectPath?: string;
  provisioningError: string | null;
  clearProvisioningError?: () => void;
  activeTeams?: ActiveTeamRef[];
  onClose: () => void;
  onLaunch: (request: TeamLaunchRequest) => Promise<void>;
}

export const LaunchTeamDialog = ({
  open,
  teamName,
  members,
  defaultProjectPath,
  provisioningError,
  clearProvisioningError,
  activeTeams,
  onClose,
  onLaunch,
}: LaunchTeamDialogProps): React.JSX.Element => {
  const [cwdMode, setCwdMode] = useState<'project' | 'custom'>('project');
  const [selectedProjectPath, setSelectedProjectPath] = useState('');
  const [customCwd, setCustomCwd] = useState('');
  const promptDraft = useDraftPersistence({ key: `launchTeam:${teamName}:prompt` });
  const chipDraft = useChipDraftPersistence(`launchTeam:${teamName}:chips`);
  const [projects, setProjects] = useState<Project[]>([]);
  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 [isSubmitting, setIsSubmitting] = useState(false);
  const [selectedModel, setSelectedModelRaw] = useState(() => {
    const stored = localStorage.getItem('team:lastSelectedModel') ?? '';
    return stored === '__default__' ? '' : stored;
  });
  const [extendedContext, setExtendedContextRaw] = useState(
    () => localStorage.getItem('team:lastExtendedContext') === 'true'
  );
  const [skipPermissions, setSkipPermissionsRaw] = useState(
    () => localStorage.getItem('team:lastSkipPermissions') !== 'false'
  );
  const [selectedEffort, setSelectedEffortRaw] = useState(
    () => localStorage.getItem('team:lastSelectedEffort') ?? ''
  );
  const [clearContext, setClearContext] = useState(false);
  const [conflictDismissed, setConflictDismissed] = useState(false);

  const setSelectedModel = (value: string): void => {
    setSelectedModelRaw(value);
    localStorage.setItem('team:lastSelectedModel', value);
  };

  const setExtendedContext = (value: boolean): void => {
    setExtendedContextRaw(value);
    localStorage.setItem('team:lastExtendedContext', String(value));
  };

  const setSkipPermissions = (value: boolean): void => {
    setSkipPermissionsRaw(value);
    localStorage.setItem('team:lastSkipPermissions', String(value));
  };

  const setSelectedEffort = (value: string): void => {
    setSelectedEffortRaw(value);
    localStorage.setItem('team:lastSelectedEffort', value);
  };

  const resetFormState = (): void => {
    setLocalError(null);
    setIsSubmitting(false);
    setPrepareState('idle');
    setPrepareMessage(null);
    setPrepareWarnings([]);
    setCwdMode('project');
    setSelectedProjectPath('');
    setCustomCwd('');
    setClearContext(false);
    setConflictDismissed(false);
    chipDraft.clearChipDraft();
  };

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

  // Warm up CLI on open
  useEffect(() => {
    if (!open) {
      return;
    }

    if (typeof api.teams.prepareProvisioning !== 'function') {
      setPrepareState('failed');
      setPrepareWarnings([]);
      setPrepareMessage(
        'Current preload version does not support team:prepareProvisioning. Restart the dev app.'
      );
      return;
    }

    let cancelled = false;
    setPrepareState('loading');
    setPrepareMessage('Warming up CLI environment...');
    setPrepareWarnings([]);

    void (async () => {
      try {
        const prepResult: TeamProvisioningPrepareResult = await api.teams.prepareProvisioning();
        if (cancelled) {
          return;
        }
        setPrepareState(prepResult.ready ? 'ready' : 'failed');
        setPrepareMessage(prepResult.message);
        setPrepareWarnings(prepResult.warnings ?? []);
      } catch (error) {
        if (cancelled) {
          return;
        }
        setPrepareState('failed');
        setPrepareWarnings([]);
        setPrepareMessage(
          error instanceof Error ? error.message : 'Failed to warm up Claude CLI environment'
        );
      }
    })();

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

  const repositoryGroups = useStore((s) => s.repositoryGroups);

  // Fetch projects on open, merging with repositoryGroups from store
  useEffect(() => {
    if (!open) {
      return;
    }

    setProjectsLoading(true);
    setProjectsError(null);

    let cancelled = false;
    void (async () => {
      try {
        const apiProjects = await api.getProjects();
        if (cancelled) {
          return;
        }

        // Merge repositoryGroups (may include synthetic folders without sessions)
        const pathSet = new Set(apiProjects.map((p) => p.path));
        const extras: Project[] = [];
        for (const repo of repositoryGroups) {
          for (const wt of repo.worktrees) {
            if (!pathSet.has(wt.path)) {
              pathSet.add(wt.path);
              extras.push({
                id: wt.id,
                path: wt.path,
                name: wt.name,
                sessions: [],
                totalSessions: 0,
                createdAt: wt.createdAt ?? Date.now(),
              });
            }
          }
        }

        setProjects([...apiProjects, ...extras]);
      } catch (error) {
        if (cancelled) {
          return;
        }
        setProjectsError(error instanceof Error ? error.message : 'Failed to load projects');
        setProjects([]);
      } finally {
        if (!cancelled) {
          setProjectsLoading(false);
        }
      }
    })();

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

  // Pre-select defaultProjectPath when projects loaded (only while dialog is open)
  useEffect(() => {
    if (!open) return;
    if (cwdMode !== 'project') {
      return;
    }
    if (selectedProjectPath || projects.length === 0) {
      return;
    }
    if (defaultProjectPath) {
      const match = projects.find((p) => p.path === defaultProjectPath);
      if (match) {
        setSelectedProjectPath(match.path);
        return;
      }
    }
    setSelectedProjectPath(projects[0].path);
  }, [open, cwdMode, projects, selectedProjectPath, defaultProjectPath]);

  const effectiveCwd = cwdMode === 'project' ? selectedProjectPath.trim() : customCwd.trim();

  // Pre-warm file list cache so @-mention file search is instant
  useFileListCacheWarmer(effectiveCwd || null);

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

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

  const colorMap = useMemo(() => buildMemberColorMap(members), [members]);
  const mentionSuggestions = useMemo<MentionSuggestion[]>(
    () =>
      members.map((m) => ({
        id: m.name,
        name: m.name,
        subtitle: formatAgentRole(m.role) ?? formatAgentRole(m.agentType) ?? undefined,
        color: colorMap.get(m.name),
      })),
    [members, colorMap]
  );

  const activeError = localError ?? provisioningError;

  const handleSubmit = (): void => {
    if (!effectiveCwd) {
      setLocalError('Select working directory (cwd)');
      return;
    }
    setLocalError(null);
    setIsSubmitting(true);

    void (async () => {
      try {
        await onLaunch({
          teamName,
          cwd: effectiveCwd,
          prompt: promptDraft.value.trim() || undefined,
          model: computeEffectiveTeamModel(selectedModel, extendedContext),
          effort: (selectedEffort as EffortLevel) || undefined,
          clearContext: clearContext || undefined,
          skipPermissions,
        });
        resetFormState();
        onClose();
      } catch {
        // error is shown via provisioningError prop
      } finally {
        setIsSubmitting(false);
      }
    })();
  };

  return (
    <Dialog
      open={open}
      onOpenChange={(nextOpen) => {
        if (!nextOpen) {
          resetFormState();
          onClose();
        }
      }}
    >
      <DialogContent className="max-w-2xl">
        <DialogHeader>
          <DialogTitle className="text-sm">Launch Team</DialogTitle>
          <DialogDescription className="text-xs">
            Start team <span className="font-mono font-medium">{teamName}</span> via local Claude
            CLI.
          </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">
                  Another team &ldquo;{conflictingTeam.displayName}&rdquo; is already running for
                  this working directory
                </p>
                <p className="opacity-80">
                  Running two teams in the same directory is risky — they may conflict editing the
                  same files. Consider using a different directory or a git worktree for isolation.
                </p>
                <p className="text-[11px] opacity-70">
                  Working directory: <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}

        {prepareState === 'failed' ? (
          <div className="rounded-md border border-red-500/40 bg-red-500/10 p-3 text-xs">
            <div className="flex items-start gap-2">
              <AlertTriangle className="mt-0.5 size-4 shrink-0 text-red-400" />
              <div className="min-w-0 space-y-1">
                <p className="font-medium text-red-300">
                  CLI environment is not available — launch is blocked
                </p>
                <p className="text-red-300/80">
                  {prepareMessage ?? 'Failed to prepare environment'}
                </p>
                {prepareWarnings.length > 0 ? (
                  <div className="space-y-0.5">
                    {prepareWarnings.map((warning) => (
                      <p
                        key={warning}
                        className="text-[11px]"
                        style={{ color: 'var(--warning-text)' }}
                      >
                        {warning}
                      </p>
                    ))}
                  </div>
                ) : null}
                <p className="text-[11px] text-[var(--color-text-muted)]">
                  Make sure <span className="font-mono">claude</span> CLI is installed and available
                  in PATH, then reopen this dialog.
                </p>
              </div>
            </div>
          </div>
        ) : null}

        <div className="space-y-4">
          <ProjectPathSelector
            cwdMode={cwdMode}
            onCwdModeChange={setCwdMode}
            selectedProjectPath={selectedProjectPath}
            onSelectedProjectPathChange={setSelectedProjectPath}
            customCwd={customCwd}
            onCustomCwdChange={setCustomCwd}
            projects={projects}
            projectsLoading={projectsLoading}
            projectsError={projectsError}
          />

          <div className="space-y-1.5">
            <Label htmlFor="launch-prompt" className="label-optional">
              Prompt for team lead (optional)
            </Label>
            <MentionableTextarea
              id="launch-prompt"
              className="min-h-[100px] text-xs"
              minRows={4}
              maxRows={12}
              value={promptDraft.value}
              onValueChange={promptDraft.setValue}
              suggestions={mentionSuggestions}
              projectPath={effectiveCwd || null}
              chips={chipDraft.chips}
              onChipRemove={chipDraft.removeChip}
              onFileChipInsert={chipDraft.addChip}
              placeholder="Instructions for team lead..."
              footerRight={
                promptDraft.isSaved ? (
                  <span className="text-[10px] text-[var(--color-text-muted)]">Draft saved</span>
                ) : null
              }
            />
          </div>

          <div>
            <TeamModelSelector
              value={selectedModel}
              onValueChange={setSelectedModel}
              id="launch-model"
            />
            <EffortLevelSelector
              value={selectedEffort}
              onValueChange={setSelectedEffort}
              id="launch-effort"
            />
            <ExtendedContextCheckbox
              id="launch-extended-context"
              checked={extendedContext}
              onCheckedChange={setExtendedContext}
              disabled={selectedModel === 'haiku'}
            />
            <SkipPermissionsCheckbox
              id="launch-skip-permissions"
              checked={skipPermissions}
              onCheckedChange={setSkipPermissions}
            />
          </div>

          <div className="space-y-2">
            <div className="flex items-center gap-2">
              <Checkbox
                id="clear-context"
                checked={clearContext}
                onCheckedChange={(checked) => setClearContext(checked === true)}
              />
              <Label
                htmlFor="clear-context"
                className="flex cursor-pointer items-center gap-1.5 text-xs font-normal text-text-secondary"
              >
                <RotateCcw className="size-3 shrink-0" />
                Clear context (fresh session)
              </Label>
            </div>
            {clearContext && (
              <div
                className="rounded-md border px-3 py-2 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-3.5 shrink-0" />
                  <p>
                    The team lead will start a new session without resuming previous context. All
                    accumulated session memory and conversation history will not be available.
                  </p>
                </div>
              </div>
            )}
          </div>
        </div>

        {activeError ? (
          <p className="rounded border border-red-500/40 bg-red-500/10 p-2 text-xs text-red-300">
            {activeError}
          </p>
        ) : null}

        <DialogFooter className="pt-4 sm:justify-between">
          <div className="min-w-0">
            {prepareState === 'idle' || prepareState === '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" />
                <span>
                  {prepareMessage ??
                    (prepareState === 'idle'
                      ? 'Warming up CLI environment...'
                      : 'Preparing environment...')}
                </span>
              </div>
            ) : null}

            {prepareState === '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>
                    {prepareWarnings.length > 0
                      ? 'CLI environment ready (with notes)'
                      : 'CLI environment ready'}
                  </span>
                </div>
                {prepareMessage ? (
                  <p className="mt-0.5 pl-5 text-[11px] text-[var(--color-text-muted)]">
                    {prepareMessage}
                  </p>
                ) : null}
                {prepareWarnings.length > 0 ? (
                  <div className="mt-0.5 space-y-0.5 pl-5">
                    {prepareWarnings.map((warning) => (
                      <p key={warning} className="text-[11px] text-sky-300">
                        {warning}
                      </p>
                    ))}
                  </div>
                ) : null}
              </div>
            ) : null}

            {prepareState === 'failed' ? <div /> : null}
          </div>

          <div className="flex shrink-0 items-center gap-2">
            <Button variant="outline" size="sm" onClick={onClose}>
              Close
            </Button>
            <Button
              size="sm"
              className="bg-emerald-600 text-white hover:bg-emerald-700"
              disabled={isSubmitting || prepareState !== 'ready'}
              onClick={handleSubmit}
            >
              {isSubmitting ? (
                <>
                  <Loader2 className="mr-1.5 size-3.5 animate-spin" />
                  Launching...
                </>
              ) : (
                'Launch'
              )}
            </Button>
          </div>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
};
