'use client';

import React, { useState, useEffect, useMemo, useRef } from 'react';
import { Deployment, Project } from '@/lib/vfs/types';
import { vfs } from '@/lib/vfs';
import { getLoginUrl } from '@/lib/config/storage';
import { getSyncManager } from '@/lib/vfs/sync-manager';
import { DeploymentCard } from '../deployment-card';
import { DeploymentSettingsModal } from '../deployment-settings';
import { ServerSettingsModal } from '../server-settings';
import { CreateDeploymentModal } from '../create-deployment-modal';
import { AnalyticsDashboard } from '../analytics-dashboard';
import { TemplateExportDialog } from '../templates/template-export-dialog';
import { ProjectSwapDialog } from '../project-swap-dialog';
import { Globe, Plus, Search, ArrowUpDown } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { Input } from '@/components/ui/input';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { toast } from 'sonner';
import { logger } from '@/lib/utils';
import { track } from '@/lib/telemetry';
import { usePagination } from '@/lib/hooks/use-pagination';
import { Pagination, PaginationRange } from '@/components/ui/pagination';

type SortOption = 'updated' | 'created' | 'name' | 'published';

interface DeploymentsViewProps {
  onProjectSelect: (project: Project) => void;
  workspaceId?: string;
}

export function DeploymentsView({ onProjectSelect, workspaceId }: DeploymentsViewProps) {
  const apiBase = workspaceId ? `/api/w/${workspaceId}` : '/api';
  const [deployments, setDeployments] = useState<Deployment[]>([]);
  const [projects, setProjects] = useState<Project[]>([]);
  const [loading, setLoading] = useState(true);
  const [publishingStates, setPublishingStates] = useState<Record<string, boolean>>({});
  const [selectedDeployment, setSelectedDeployment] = useState<Deployment | null>(null);
  const [showSettingsModal, setShowSettingsModal] = useState(false);
  const [showServerSettingsModal, setShowServerSettingsModal] = useState(false);
  const [showAnalyticsModal, setShowAnalyticsModal] = useState(false);
  const [showCreateModal, setShowCreateModal] = useState(false);
  const [showTemplateExportModal, setShowTemplateExportModal] = useState(false);
  const [templateExportDeployment, setTemplateExportDeployment] = useState<Deployment | null>(null);
  const [searchQuery, setSearchQuery] = useState('');
  const [sortBy, setSortBy] = useState<SortOption>('updated');
  const [swapDialogState, setSwapDialogState] = useState<{
    deploymentId: string;
    deploymentName: string;
    currentProjectId: string;
    newProjectId: string;
    newProjectName: string;
    pendingSettings: Partial<Deployment>;
  } | null>(null);
  const isServerMode = process.env.NEXT_PUBLIC_SERVER_MODE === 'true';

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

  const loadData = async () => {
    try {
      setLoading(true);

      if (!isServerMode) {
        setLoading(false);
        return;
      }

      const [deploymentsResponse, projectsResponse] = await Promise.all([
        fetch(`${apiBase}/deployments`),
        fetch(`${apiBase}/projects?fields=id,name`), // Only fetch id and name fields
      ]);

      // Redirect to login if unauthorized
      if (deploymentsResponse.status === 401 || projectsResponse.status === 401) {
        window.location.href = getLoginUrl();
        return;
      }

      if (!deploymentsResponse.ok) {
        throw new Error('Failed to fetch deployments');
      }
      if (!projectsResponse.ok) {
        throw new Error('Failed to fetch projects');
      }

      const [fetchedDeployments, fetchedProjects] = await Promise.all([
        deploymentsResponse.json(),
        projectsResponse.json(),
      ]);

      setDeployments(fetchedDeployments);
      setProjects(fetchedProjects);
    } catch (error) {
      logger.error('[DeploymentsView] Failed to load data:', error);
    } finally {
      setLoading(false);
    }
  };

  // Helper function to update a single deployment in state (optimistic updates)
  const updateDeploymentInState = (deploymentId: string, updates: Partial<Deployment>) => {
    setDeployments(prevDeployments =>
      prevDeployments.map(deployment =>
        deployment.id === deploymentId ? { ...deployment, ...updates } : deployment
      )
    );
  };

  const handleOpenSettings = (deployment: Deployment) => {
    setSelectedDeployment(deployment);
    setShowSettingsModal(true);
  };

  const handleOpenServerSettings = (deployment: Deployment) => {
    setSelectedDeployment(deployment);
    setShowServerSettingsModal(true);
  };

  const handleViewAnalytics = (deployment: Deployment) => {
    setSelectedDeployment(deployment);
    setShowAnalyticsModal(true);
  };

  const handleEditProject = async (deployment: Deployment) => {
    try {
      await vfs.init();
      const project = await vfs.getProject(deployment.projectId);
      if (!project) {
        toast.error('Project not found in local storage');
        return;
      }
      onProjectSelect(project);
    } catch (error) {
      logger.error('[DeploymentsView] Failed to load project:', error);
      toast.error('Failed to load project');
    }
  };

  const [templateExportProject, setTemplateExportProject] = useState<Project | null>(null);

  const handleExportAsTemplate = async (deployment: Deployment) => {
    try {
      await vfs.init();
      const project = await vfs.getProject(deployment.projectId);
      if (!project) {
        toast.error('Project not found in local storage');
        return;
      }
      setTemplateExportDeployment(deployment);
      setTemplateExportProject(project);
      setShowTemplateExportModal(true);
    } catch (error) {
      logger.error('[DeploymentsView] Failed to load project for template export:', error);
      toast.error('Failed to load project');
    }
  };

  const handleSaveSettings = async (settings: Partial<Deployment>) => {
    if (!selectedDeployment) return;

    try {
      // If projectId changed in server mode, show swap dialog for conflict analysis
      const projectIdChanged = settings.projectId && settings.projectId !== selectedDeployment.projectId;
      if (projectIdChanged && isServerMode && selectedDeployment.publishedAt) {
        const newProject = projects.find(p => p.id === settings.projectId);
        setSwapDialogState({
          deploymentId: selectedDeployment.id,
          deploymentName: selectedDeployment.name,
          currentProjectId: selectedDeployment.projectId,
          newProjectId: settings.projectId!,
          newProjectName: newProject?.name || 'Unknown',
          pendingSettings: settings,
        });
        return; // Don't save yet — swap dialog will handle it
      }

      if (projectIdChanged) {
        // Non-server mode or first deploy: update directly
        const deploymentResponse = await fetch(`${apiBase}/deployments/${selectedDeployment.id}`, {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ projectId: settings.projectId }),
        });

        if (!deploymentResponse.ok) {
          const error = await deploymentResponse.json();
          throw new Error(error.error || 'Failed to update project');
        }
      }

      // Save publishing settings (exclude projectId — handled above)
      const { projectId: _projectId, ...publishSettings } = settings;

      const response = await fetch(`${apiBase}/deployments/${selectedDeployment.id}/settings`, {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(publishSettings),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.error || 'Failed to save settings');
      }

      const result = await response.json();

      // Fire only on the empty -> set transition, never on every save and
      // never with the domain value itself.
      if (!selectedDeployment.customDomain && settings.customDomain) {
        track('custom_domain_set');
      }

      // Update local deployment state in the selected deployment modal
      setSelectedDeployment({
        ...selectedDeployment,
        ...settings,
        settingsVersion: result.settingsVersion,
        lastPublishedVersion: result.lastPublishedVersion,
      });

      // Update the deployment in the main list (optimistic update - no full reload)
      updateDeploymentInState(selectedDeployment.id, {
        ...settings,
        settingsVersion: result.settingsVersion,
        updatedAt: new Date(),
      });
    } catch (error) {
      logger.error('[DeploymentsView] Failed to save deployment settings:', error);
      throw error;
    }
  };

  const handleSwapComplete = async () => {
    if (!swapDialogState) return;

    // Swap + republish completed via the swap API.
    // Now save any remaining publishing settings.
    const { deploymentId, pendingSettings } = swapDialogState;
    const { projectId: _projectId, ...publishSettings } = pendingSettings;

    try {
      const response = await fetch(`${apiBase}/deployments/${deploymentId}/settings`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(publishSettings),
      });

      if (response.ok) {
        const result = await response.json();
        updateDeploymentInState(deploymentId, {
          ...pendingSettings,
          settingsVersion: result.settingsVersion,
          updatedAt: new Date(),
          publishedAt: new Date(),
        });
      }
    } catch (err) {
      logger.error('[DeploymentsView] Failed to save settings after swap:', err);
    }

    setSwapDialogState(null);
    setShowSettingsModal(false);
    setSelectedDeployment(null);
    toast.success('Project swapped and deployment republished');
    await loadData();
  };

  const handlePublish = async (deploymentId: string) => {
    const deployment = deployments.find(s => s.id === deploymentId);
    if (!deployment) return;

    if (!confirm('Publish this deployment with the current settings?')) {
      return;
    }

    // Set publishing state
    setPublishingStates(prev => ({ ...prev, [deploymentId]: true }));

    let trackedRuntime = 'unknown';

    try {
      // First, sync files from IndexedDB to server
      toast.info('Syncing project files...');

      await vfs.init();
      const project = await vfs.getProject(deployment.projectId);
      if (!project) {
        throw new Error('Project not found in local storage');
      }

      // Block publishing for terminal-mode runtimes (Python, Lua) — they can't be
      // served as static sites. Use ZIP export instead.
      const { isRuntimeBundled, getRuntimeConfig } = await import('@/lib/runtimes/registry');
      const runtime = project.settings?.runtime;
      trackedRuntime = runtime ?? 'unknown';
      if (runtime && getRuntimeConfig(runtime).previewMode === 'terminal') {
        throw new Error(`${getRuntimeConfig(runtime).label} projects cannot be published as static sites. Use ZIP export instead.`);
      }

      let files = await vfs.listFiles(deployment.projectId);

      if (runtime && isRuntimeBundled(runtime)) {
        // Always compile fresh — generated files may be stale or absent
        // (e.g. user publishes without opening the preview first)
        toast.info('Compiling project bundles...');
        const { VirtualServer } = await import('@/lib/preview/virtual-server');
        const vs = new VirtualServer(vfs as any, deployment.projectId, { runtime });
        await vs.compileProject();
        vs.cleanupBlobUrls();

        const generatedFiles = vfs.getGeneratedFiles();
        if (generatedFiles.length > 0) {
          const withProjectId = generatedFiles.map(f => ({ ...f, projectId: deployment.projectId }));
          files = [...files, ...withProjectId];
        }
      }

      const syncManager = getSyncManager();

      // Push project and files to server
      const syncResult = await syncManager.pushProjectWithFiles(project, files);
      if (!syncResult.success) {
        throw new Error(syncResult.error || 'Failed to sync files to server');
      }

      // Sync backend features from IndexedDB to server
      const adapter = await vfs.getStorageAdapter();
      const edgeFunctions = adapter.listEdgeFunctions ? await adapter.listEdgeFunctions(deployment.projectId) : [];
      const serverFunctions = adapter.listServerFunctions ? await adapter.listServerFunctions(deployment.projectId) : [];
      const secrets = adapter.listSecrets ? await adapter.listSecrets(deployment.projectId) : [];
      const scheduledFunctions = adapter.listScheduledFunctions ? await adapter.listScheduledFunctions(deployment.projectId) : [];

      if (edgeFunctions.length > 0 || serverFunctions.length > 0 ||
          secrets.length > 0 || scheduledFunctions.length > 0) {
        toast.info('Syncing backend features...');
        const featuresSyncResult = await syncManager.pushBackendFeatures(deployment.projectId, {
          edgeFunctions,
          serverFunctions,
          secrets,
          scheduledFunctions,
        });
        if (!featuresSyncResult.success) {
          throw new Error(featuresSyncResult.error || 'Failed to sync backend features');
        }
      }

      toast.info('Building deployment...');

      // Call publish API to trigger build
      const response = await fetch(`${apiBase}/deployments/${deploymentId}/publish`, {
        method: 'POST',
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.error || 'Failed to publish');
      }

      const result = await response.json();

      track('deployment_publish', {
        runtime: runtime ?? 'unknown',
        result: 'success',
        has_custom_domain: !!deployment.customDomain,
      });

      toast.success(`Deployment published! ${result.filesWritten} files written.`);

      // Update state optimistically with publish data
      updateDeploymentInState(deploymentId, {
        lastPublishedVersion: result.lastPublishedVersion,
        publishedAt: new Date(),
        updatedAt: new Date(),
        databaseEnabled: true,
        ...(result.slug && { slug: result.slug }),
      });

      // Clear publishing state immediately after successful publish
      setPublishingStates(prev => ({ ...prev, [deploymentId]: false }));
    } catch (error) {
      logger.error('Failed to publish:', error);
      track('deployment_publish', {
        runtime: trackedRuntime,
        result: 'fail',
        has_custom_domain: !!deployment.customDomain,
      });
      toast.error(error instanceof Error ? error.message : 'Failed to publish. Please try again.');
      // Clear publishing state on error
      setPublishingStates(prev => ({ ...prev, [deploymentId]: false }));
    }
  };

  const handleDeploymentThumbnailChange = async (deploymentId: string, image: string | undefined) => {
    try {
      const response = await fetch(`${apiBase}/deployments/${deploymentId}/thumbnail`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ previewImage: image ?? null }),
      });
      if (!response.ok) throw new Error('Failed to update thumbnail');

      updateDeploymentInState(deploymentId, {
        previewImage: image,
        previewUpdatedAt: image ? new Date() : undefined,
      });
    } catch (err) {
      logger.error('[DeploymentsView] Failed to update deployment thumbnail:', err);
      toast.error('Failed to update thumbnail');
    }
  };

  const handleDisable = async (deploymentId: string) => {
    const deployment = deployments.find(s => s.id === deploymentId);
    if (!deployment) return;

    if (!confirm('Disable this deployment? It will no longer be publicly accessible.')) {
      return;
    }

    try {
      const response = await fetch(`${apiBase}/deployments/${deploymentId}`, {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          enabled: false,
        }),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.error || 'Failed to disable deployment');
      }

      // Update state optimistically (no full reload)
      updateDeploymentInState(deploymentId, {
        enabled: false,
        updatedAt: new Date(),
      });
    } catch (error) {
      logger.error('Failed to disable deployment:', error);
      alert('Failed to disable deployment. Please try again.');
    }
  };

  const handleEnable = async (deploymentId: string) => {
    const deployment = deployments.find(s => s.id === deploymentId);
    if (!deployment) return;

    try {
      const response = await fetch(`${apiBase}/deployments/${deploymentId}`, {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          enabled: true,
        }),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.error || 'Failed to enable deployment');
      }

      // Update state optimistically (no full reload)
      updateDeploymentInState(deploymentId, {
        enabled: true,
        updatedAt: new Date(),
      });
    } catch (error) {
      logger.error('Failed to enable deployment:', error);
      alert('Failed to enable deployment. Please try again.');
    }
  };

  const handleDelete = async (deploymentId: string) => {
    const deployment = deployments.find(s => s.id === deploymentId);
    if (!deployment) return;

    if (!confirm(`Delete deployment "${deployment.name}"? This cannot be undone.`)) {
      return;
    }

    try {
      const response = await fetch(`${apiBase}/deployments/${deploymentId}`, {
        method: 'DELETE',
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.error || 'Failed to delete deployment');
      }

      track('deployment_delete');

      await loadData();
    } catch (error) {
      logger.error('Failed to delete deployment:', error);
      alert('Failed to delete deployment. Please try again.');
    }
  };

  const handleCreateDeployment = async (data: { projectId: string; name: string; slug?: string }) => {
    try {
      const response = await fetch(`${apiBase}/deployments`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.error || 'Failed to create deployment');
      }

      track('deployment_create');

      await loadData();
      setShowCreateModal(false);
    } catch (error) {
      logger.error('Failed to create deployment:', error);
      throw error;
    }
  };

  // Filter and sort deployments
  const filteredAndSortedDeployments = useMemo(() => {
    let filtered = deployments;

    // Apply search filter
    if (searchQuery) {
      const query = searchQuery.toLowerCase();
      filtered = deployments.filter(deployment => {
        const project = projects.find(p => p.id === deployment.projectId);
        return (
          deployment.name.toLowerCase().includes(query) ||
          deployment.slug?.toLowerCase().includes(query) ||
          project?.name.toLowerCase().includes(query)
        );
      });
    }

    // Apply sorting
    const sorted = [...filtered].sort((a, b) => {
      switch (sortBy) {
        case 'name':
          return a.name.localeCompare(b.name);
        case 'created':
          return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
        case 'published':
          if (!a.publishedAt && !b.publishedAt) return 0;
          if (!a.publishedAt) return 1;
          if (!b.publishedAt) return -1;
          return new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime();
        case 'updated':
        default:
          return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
      }
    });

    return sorted;
  }, [deployments, projects, searchQuery, sortBy]);

  const deploymentsPagination = usePagination(filteredAndSortedDeployments, {
    perPage: 24,
    resetOn: [searchQuery, sortBy],
  });
  const listScrollRef = useRef<HTMLDivElement | null>(null);

  if (!isServerMode) {
    return (
      <div className="h-full flex items-center justify-center">
        <div className="text-center text-muted-foreground">
          <p>Deployments feature is only available in Server Mode</p>
        </div>
      </div>
    );
  }

  if (loading) {
    return (
      <div className="h-full flex items-center justify-center">
        <div className="text-center">
          <Spinner size={48} color="#f97316" className="mx-auto" />
          <p className="mt-4">Loading deployments...</p>
        </div>
      </div>
    );
  }

  return (
    <>
      <div className="h-full flex flex-col">
        {/* Toolbar */}
        <div className="pt-4 px-4 pb-3 sm:pt-6 sm:px-6 sm:pb-3 shrink-0">
          <div className="mx-auto max-w-7xl flex flex-col sm:flex-row gap-3">
            {/* Search */}
            <div className="relative flex-1">
              <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
              <Input
                placeholder="Search deployments..."
                value={searchQuery}
                onChange={(e) => setSearchQuery(e.target.value)}
                className="pl-9"
              />
            </div>

            {/* Controls */}
            <div className="flex items-center gap-2">
              {/* Sort */}
              <Popover>
                <PopoverTrigger asChild>
                  <Button variant="outline" size="sm" className="gap-2">
                    <ArrowUpDown className="h-4 w-4" />
                    <span className="hidden sm:inline">Sort</span>
                  </Button>
                </PopoverTrigger>
                <PopoverContent className="w-48" align="end">
                  <div className="space-y-2">
                    <h4 className="font-semibold text-sm">Sort by</h4>
                    <Select value={sortBy} onValueChange={(value) => setSortBy(value as SortOption)}>
                      <SelectTrigger>
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="updated">Last Updated</SelectItem>
                        <SelectItem value="published">Last Published</SelectItem>
                        <SelectItem value="created">Date Created</SelectItem>
                        <SelectItem value="name">Name</SelectItem>
                      </SelectContent>
                    </Select>
                  </div>
                </PopoverContent>
              </Popover>

              {/* New Deployment */}
              <Button onClick={() => setShowCreateModal(true)} size="sm" className="gap-2">
                <Plus className="h-4 w-4" />
                <span>New</span>
              </Button>
            </div>
          </div>
        </div>

        {/* Deployments Grid/List */}
        <div ref={listScrollRef} className="flex-1 px-4 pt-3 pb-4 sm:px-6 sm:pt-3 sm:pb-6 overflow-auto">
          <div className="mx-auto max-w-7xl">
            {filteredAndSortedDeployments.length === 0 ? (
              <div className="flex flex-col items-center justify-center py-16 text-center">
                <Globe className="h-16 w-16 text-muted-foreground mb-4" />
                {deployments.length === 0 ? (
                  <>
                    <h2 className="text-xl font-semibold mb-2">No Deployments Yet</h2>
                    <p className="text-muted-foreground mb-4 max-w-md">
                      Create your first deployment by clicking the "New" button above.
                      Deployments let you publish projects and manage their public settings independently.
                    </p>
                  </>
                ) : (
                  <>
                    <h2 className="text-xl font-semibold mb-2">No deployments found</h2>
                    <p className="text-muted-foreground mb-4 max-w-md">
                      Try adjusting your search or filter criteria
                    </p>
                  </>
                )}
              </div>
            ) : (
              <>
                <PaginationRange
                  total={deploymentsPagination.total}
                  rangeStart={deploymentsPagination.rangeStart}
                  rangeEnd={deploymentsPagination.rangeEnd}
                  totalPages={deploymentsPagination.totalPages}
                  className="mb-2"
                />
                <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
                  {deploymentsPagination.pageItems.map((deployment) => {
                    const project = projects.find(p => p.id === deployment.projectId);
                    return (
                      <DeploymentCard
                        key={deployment.id}
                        deployment={deployment}
                        project={project}
                        isPublishing={publishingStates[deployment.id] || false}
                        onOpenSettings={handleOpenSettings}
                        onOpenServerSettings={handleOpenServerSettings}
                        onViewAnalytics={handleViewAnalytics}
                        onEditProject={handleEditProject}
                        onPublish={handlePublish}
                        onDisable={handleDisable}
                        onEnable={handleEnable}
                        onDelete={handleDelete}
                        onExportAsTemplate={handleExportAsTemplate}
                        onThumbnailChange={handleDeploymentThumbnailChange}
                      />
                    );
                  })}
                </div>
                <Pagination
                  page={deploymentsPagination.page}
                  totalPages={deploymentsPagination.totalPages}
                  onPageChange={deploymentsPagination.setPage}
                  scrollTarget={listScrollRef}
                />
              </>
            )}
          </div>
        </div>
      </div>

      {selectedDeployment && (
        <>
          <DeploymentSettingsModal
            deployment={selectedDeployment}
            projects={projects}
            isOpen={showSettingsModal}
            onClose={() => {
              setShowSettingsModal(false);
              setSelectedDeployment(null);
            }}
            onSave={handleSaveSettings}
          />

          <ServerSettingsModal
            deployment={selectedDeployment}
            isOpen={showServerSettingsModal}
            onClose={() => {
              setShowServerSettingsModal(false);
              setSelectedDeployment(null);
            }}
            workspaceId={workspaceId}
          />

          <AnalyticsDashboard
            deployment={selectedDeployment}
            isOpen={showAnalyticsModal}
            onClose={() => {
              setShowAnalyticsModal(false);
              setSelectedDeployment(null);
            }}
          />
        </>
      )}

      <CreateDeploymentModal
        projects={projects}
        isOpen={showCreateModal}
        onClose={() => setShowCreateModal(false)}
        onCreate={handleCreateDeployment}
      />

      <TemplateExportDialog
        project={templateExportProject}
        open={showTemplateExportModal}
        onOpenChange={(open) => {
          setShowTemplateExportModal(open);
          if (!open) {
            setTemplateExportDeployment(null);
            setTemplateExportProject(null);
          }
        }}
      />

      {swapDialogState && (
        <ProjectSwapDialog
          isOpen={true}
          onClose={() => setSwapDialogState(null)}
          deploymentId={swapDialogState.deploymentId}
          deploymentName={swapDialogState.deploymentName}
          currentProjectId={swapDialogState.currentProjectId}
          newProjectId={swapDialogState.newProjectId}
          newProjectName={swapDialogState.newProjectName}
          onSwapComplete={handleSwapComplete}
          workspaceId={workspaceId}
        />
      )}
    </>
  );
}
