'use client';

/**
 * /admin/sync/route53 — AWS Route 53 DNS sync detail page (D-09).
 *
 * Follows the app/admin/sync/veeam/page.tsx shape: 'use client', plain
 * useState/useEffect/fetch — no client-side data-fetching library, no
 * server-only actions (CLAUDE.md) — a header with a manual "Sync Now"
 * trigger, and tabbed detail views built on the shared DataTable /
 * DetailModal / SyncScheduler vocabulary.
 *
 * Record values (from AWS) and history before/after JSONB are rendered only
 * through React's default text escaping — no raw-HTML injection helper, no
 * anchor/src injection from record content (T-24-25).
 */

import { useState, useEffect, useCallback } from 'react';
import Link from 'next/link';
import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { StatusBadge } from '@/components/ui/status-badge';
import { EmptyState } from '@/components/ui/empty-state';
import DataTable, { type Column } from '@/components/admin/DataTable';
import DetailModal from '@/components/admin/DetailModal';
import SyncScheduler from '@/components/admin/SyncScheduler';
import {
  RecordEditorDialog,
  RecordDeleteConfirm,
} from '@/components/admin/route53/record-editor-dialog';
import { useUserTimezone } from '@/lib/hooks/use-user-timezone';
import {
  ArrowLeft,
  RefreshCw,
  Loader2,
  Plus,
  Pencil,
  Trash2,
  History as HistoryIcon,
  Globe,
  ShieldOff,
  X,
} from 'lucide-react';
import type {
  Route53Zone,
  Route53Record,
  Route53RecordHistory,
  Route53HistorySource,
} from '@/lib/types/route53';

// ── Constants ────────────────────────────────────────────────────────────────

/** D-01: the closed allowlist of writable record types — must match
 * lib/services/route53-record-validation.ts WRITABLE_RECORD_TYPES exactly.
 * NS and SOA are deliberately absent from this list; they render read-only. */
const WRITABLE_TYPES = ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'SRV'] as const;
const RECORD_TYPE_FILTERS = [...WRITABLE_TYPES, 'NS', 'SOA'];

const PAGE_SIZE = 25;
const HISTORY_PAGE_SIZE = 25;
const SYNC_POLL_INTERVAL_MS = 3000;
const SYNC_POLL_MAX_ATTEMPTS = 20;

interface SyncHistoryEntry {
  id: string;
  sync_type: string;
  status: string;
  started_at: string;
  completed_at: string | null;
  error_message: string | null;
  triggered_by: string;
}

interface SyncStatusResponse {
  inProgress: boolean;
  counts: { zones: number; records: number; historyRows: number };
  history: SyncHistoryEntry[];
}

// ── Helpers ──────────────────────────────────────────────────────────────────

function fmtDate(d: string | null | undefined, tz: string): string {
  if (!d) return 'Never';
  return new Date(d).toLocaleString(undefined, {
    month: 'short',
    day: 'numeric',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
    timeZone: tz,
  });
}

function paginate<T>(rows: T[], page: number, pageSize: number): T[] {
  const start = (page - 1) * pageSize;
  return rows.slice(start, start + pageSize);
}

function isWritableType(type: string): boolean {
  return (WRITABLE_TYPES as readonly string[]).includes(type);
}

function syncStatusTone(status: string): 'ok' | 'error' | 'info' | 'warn' {
  if (status === 'completed') return 'ok';
  if (status === 'failed') return 'error';
  if (status === 'started') return 'info';
  return 'warn';
}

function changeActionTone(action: string): 'ok' | 'info' | 'error' | 'neutral' {
  if (action === 'create') return 'ok';
  if (action === 'update') return 'info';
  if (action === 'delete') return 'error';
  return 'neutral';
}

/** D-06: visually distinguish a Pulse-initiated write from a change AWS
 * detected outside Pulse — this is the whole point of drift detection. */
function sourceTone(source: Route53HistorySource): 'info' | 'warn' {
  return source === 'sync_detected_drift' ? 'warn' : 'info';
}

function sourceLabel(source: Route53HistorySource): string {
  return source === 'sync_detected_drift' ? 'Drift detected' : 'Pulse';
}

// ── Page ─────────────────────────────────────────────────────────────────────

export default function Route53SyncPage() {
  const tz = useUserTimezone();
  const [activeTab, setActiveTab] = useState('zones');
  const [refreshKey, setRefreshKey] = useState(0);

  // ── Sync status ──
  const [syncStatus, setSyncStatus] = useState<SyncStatusResponse | null>(null);
  const [unconfigured, setUnconfigured] = useState(false);
  const [syncing, setSyncing] = useState(false);

  const fetchSyncStatus = useCallback(async () => {
    try {
      const res = await fetch('/api/route53/sync');
      if (res.status === 503) {
        setUnconfigured(true);
        return;
      }
      if (res.ok) {
        setUnconfigured(false);
        setSyncStatus(await res.json());
      }
    } catch (err) {
      console.error('Failed to fetch Route 53 sync status:', err);
    }
  }, []);

  useEffect(() => {
    fetchSyncStatus();
  }, [fetchSyncStatus, refreshKey]);

  const handleSyncNow = async () => {
    setSyncing(true);
    try {
      const res = await fetch('/api/route53/sync', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ syncType: 'full' }),
      });
      if (res.status === 503) {
        setUnconfigured(true);
        toast.error('AWS Route 53 is not configured');
        setSyncing(false);
        return;
      }
      if (res.status === 409) {
        toast.info('Route 53 sync is already in progress');
        setSyncing(false);
        return;
      }
      if (!res.ok) {
        const body = await res.json().catch(() => ({}) as Record<string, string>);
        toast.error(body.message || body.error || 'Failed to start Route 53 sync');
        setSyncing(false);
        return;
      }
      toast.success('Route 53 sync started');

      let attempts = 0;
      const poll = setInterval(async () => {
        attempts += 1;
        try {
          const r = await fetch('/api/route53/sync');
          if (r.ok) {
            const d: SyncStatusResponse = await r.json();
            setSyncStatus(d);
            if (!d.inProgress) {
              clearInterval(poll);
              setSyncing(false);
              setRefreshKey((k) => k + 1);
              return;
            }
          }
        } catch {
          /* keep polling */
        }
        if (attempts >= SYNC_POLL_MAX_ATTEMPTS) {
          clearInterval(poll);
          setSyncing(false);
        }
      }, SYNC_POLL_INTERVAL_MS);
    } catch (err) {
      console.error(err);
      toast.error('Failed to start Route 53 sync');
      setSyncing(false);
    }
  };

  // ── Zones tab ──
  const [zones, setZones] = useState<Route53Zone[]>([]);
  const [zonesLoading, setZonesLoading] = useState(true);
  const [zonePage, setZonePage] = useState(1);
  const [zoneDetail, setZoneDetail] = useState<Route53Zone | null>(null);
  const [zoneDetailOpen, setZoneDetailOpen] = useState(false);

  const fetchZones = useCallback(async () => {
    setZonesLoading(true);
    try {
      const res = await fetch('/api/route53/zones');
      if (res.ok) {
        const d = await res.json();
        setZones(d.items ?? []);
      }
    } catch (err) {
      console.error('Failed to fetch Route 53 zones:', err);
    } finally {
      setZonesLoading(false);
    }
  }, []);

  useEffect(() => {
    if (!unconfigured) fetchZones();
  }, [fetchZones, refreshKey, unconfigured]);

  // ── Records tab ──
  const [selectedZoneId, setSelectedZoneId] = useState('');
  const [records, setRecords] = useState<Route53Record[]>([]);
  const [recordsLoading, setRecordsLoading] = useState(false);
  const [recordPage, setRecordPage] = useState(1);
  const [typeFilter, setTypeFilter] = useState('all');
  const [searchQuery, setSearchQuery] = useState('');

  const fetchRecords = useCallback(async (zoneId: string, type: string, search: string) => {
    if (!zoneId) {
      setRecords([]);
      return;
    }
    setRecordsLoading(true);
    try {
      const params = new URLSearchParams();
      if (type && type !== 'all') params.set('type', type);
      if (search) params.set('search', search);
      const qs = params.toString();
      const res = await fetch(`/api/route53/zones/${zoneId}/records${qs ? `?${qs}` : ''}`);
      if (res.ok) {
        const d = await res.json();
        setRecords(d.items ?? []);
      }
    } catch (err) {
      console.error('Failed to fetch Route 53 records:', err);
    } finally {
      setRecordsLoading(false);
    }
  }, []);

  useEffect(() => {
    if (selectedZoneId) fetchRecords(selectedZoneId, typeFilter, searchQuery);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedZoneId, typeFilter, refreshKey]);

  const handleSelectZone = (zone: Route53Zone) => {
    setSelectedZoneId(zone.id);
    setRecordPage(1);
    setSearchQuery('');
    setTypeFilter('all');
    setActiveTab('records');
  };

  const handleZoneSelectChange = (zoneId: string) => {
    setSelectedZoneId(zoneId);
    setRecordPage(1);
    setSearchQuery('');
    setTypeFilter('all');
  };

  const handleRecordSearch = (q: string) => {
    setSearchQuery(q);
    setRecordPage(1);
    fetchRecords(selectedZoneId, typeFilter, q);
  };

  // ── History tab ──
  const [selectedRecord, setSelectedRecord] = useState<Route53Record | null>(null);
  const [historyRows, setHistoryRows] = useState<Route53RecordHistory[]>([]);
  const [historyLoading, setHistoryLoading] = useState(false);
  const [historyPage, setHistoryPage] = useState(1);
  const [historyDetail, setHistoryDetail] = useState<Route53RecordHistory | null>(null);
  const [historyDetailOpen, setHistoryDetailOpen] = useState(false);

  const fetchHistory = useCallback(async (zoneId: string, recordKey: string) => {
    setHistoryLoading(true);
    try {
      const res = await fetch(
        `/api/route53/zones/${zoneId}/records/${encodeURIComponent(recordKey)}/history?limit=100`
      );
      if (res.ok) {
        const d = await res.json();
        setHistoryRows(d.items ?? []);
      }
    } catch (err) {
      console.error('Failed to fetch Route 53 record history:', err);
    } finally {
      setHistoryLoading(false);
    }
  }, []);

  const handleViewHistory = (record: Route53Record) => {
    setSelectedRecord(record);
    setHistoryPage(1);
    setActiveTab('history');
    fetchHistory(record.zoneId, record.recordKey);
  };

  const clearHistorySelection = () => {
    setSelectedRecord(null);
    setHistoryRows([]);
  };

  useEffect(() => {
    if (selectedRecord) fetchHistory(selectedRecord.zoneId, selectedRecord.recordKey);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [refreshKey]);

  // ── Record editor / delete dialogs ──
  const [editorOpen, setEditorOpen] = useState(false);
  const [editorMode, setEditorMode] = useState<'create' | 'edit'>('create');
  const [editingRecord, setEditingRecord] = useState<Route53Record | undefined>(undefined);
  const [deleteOpen, setDeleteOpen] = useState(false);
  const [deletingRecord, setDeletingRecord] = useState<Route53Record | undefined>(undefined);

  const openCreate = () => {
    setEditorMode('create');
    setEditingRecord(undefined);
    setEditorOpen(true);
  };
  const openEdit = (record: Route53Record) => {
    setEditorMode('edit');
    setEditingRecord(record);
    setEditorOpen(true);
  };
  const openDelete = (record: Route53Record) => {
    setDeletingRecord(record);
    setDeleteOpen(true);
  };

  const handleSaved = () => {
    fetchRecords(selectedZoneId, typeFilter, searchQuery);
    fetchZones();
    if (selectedRecord) fetchHistory(selectedRecord.zoneId, selectedRecord.recordKey);
  };

  // ── Column definitions ──

  const zoneColumns: Column<Route53Zone>[] = [
    { key: 'name', label: 'Zone Name', sortable: true },
    {
      key: 'id',
      label: 'Zone ID',
      render: (v: string) => <span className="font-mono text-xs">{v}</span>,
    },
    {
      key: 'privateZone',
      label: 'Private',
      render: (v: boolean) => (
        <StatusBadge tone={v ? 'info' : 'neutral'}>{v ? 'Private' : 'Public'}</StatusBadge>
      ),
    },
    {
      key: 'recordCount',
      label: 'Records',
      render: (v: number) => <span className="num">{v ?? 0}</span>,
    },
    {
      key: 'syncedAt',
      label: 'Synced At',
      render: (v: string) => (
        <span className="text-xs text-muted-foreground">{fmtDate(v, tz)}</span>
      ),
    },
    {
      key: 'authoritativeNameServers',
      label: 'Details',
      render: (_v: unknown, row: Route53Zone) => (
        <Button
          variant="outline"
          size="sm"
          onClick={(e) => {
            e.stopPropagation();
            setZoneDetail(row);
            setZoneDetailOpen(true);
          }}
        >
          <Globe className="w-3.5 h-3.5 mr-1.5" />
          NS records
        </Button>
      ),
    },
  ];

  const recordColumns: Column<Route53Record>[] = [
    { key: 'name', label: 'Name', sortable: true },
    {
      key: 'type',
      label: 'Type',
      render: (v: string) => (
        <StatusBadge tone={isWritableType(v) ? 'info' : 'neutral'}>{v}</StatusBadge>
      ),
    },
    { key: 'ttl', label: 'TTL', render: (v: number | null) => <span className="num">{v ?? '—'}</span> },
    {
      key: 'resourceRecords',
      label: 'Values',
      render: (v: Array<{ value: string }> | null) => {
        const joined = (v ?? []).map((r) => r.value).join(', ');
        return (
          <span className="text-xs truncate max-w-xs inline-block align-middle" title={joined}>
            {joined || '—'}
          </span>
        );
      },
    },
    {
      key: 'recordKey',
      label: 'Actions',
      render: (_v: unknown, row: Route53Record) => {
        const writable = isWritableType(row.type);
        return (
          <div className="flex items-center gap-1.5">
            <Button
              variant="ghost"
              size="sm"
              onClick={(e) => {
                e.stopPropagation();
                handleViewHistory(row);
              }}
              title="View change history"
            >
              <HistoryIcon className="w-3.5 h-3.5" />
            </Button>
            {writable ? (
              <>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={(e) => {
                    e.stopPropagation();
                    openEdit(row);
                  }}
                  title="Edit record"
                >
                  <Pencil className="w-3.5 h-3.5" />
                </Button>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={(e) => {
                    e.stopPropagation();
                    openDelete(row);
                  }}
                  title="Delete record"
                >
                  <Trash2 className="w-3.5 h-3.5 text-destructive" />
                </Button>
              </>
            ) : (
              <span
                className="inline-flex items-center gap-1 text-xs text-muted-foreground"
                title="NS and SOA are zone-delegation records excluded from the Pulse write path (D-01)"
              >
                <ShieldOff className="w-3.5 h-3.5" />
                Read-only
              </span>
            )}
          </div>
        );
      },
    },
  ];

  const historyColumns: Column<Route53RecordHistory>[] = [
    {
      key: 'changedAt',
      label: 'Changed At',
      sortable: true,
      render: (v: string) => (
        <span className="text-xs text-muted-foreground">{fmtDate(v, tz)}</span>
      ),
    },
    { key: 'recordName', label: 'Record' },
    {
      key: 'recordType',
      label: 'Type',
      render: (v: string) => <StatusBadge tone="neutral">{v}</StatusBadge>,
    },
    {
      key: 'changeAction',
      label: 'Action',
      render: (v: string) => <StatusBadge tone={changeActionTone(v)}>{v}</StatusBadge>,
    },
    {
      key: 'source',
      label: 'Source',
      render: (v: Route53HistorySource) => (
        <StatusBadge tone={sourceTone(v)}>{sourceLabel(v)}</StatusBadge>
      ),
    },
    {
      key: 'changedByEmail',
      label: 'Actor',
      render: (v: string | null) => <span className="text-xs">{v ?? '—'}</span>,
    },
  ];

  // ── Derived render values ──

  const lastSyncHistory = syncStatus?.history?.[0];
  const zoneCount = syncStatus?.counts?.zones ?? 0;
  const recordCount = syncStatus?.counts?.records ?? 0;
  const historyRowCount = syncStatus?.counts?.historyRows ?? 0;

  if (unconfigured) {
    return (
      <div className="container mx-auto py-4 md:py-8 px-4 space-y-6">
        <div className="flex items-center gap-4">
          <Link href="/admin/sync">
            <Button variant="outline" size="sm" className="gap-2">
              <ArrowLeft className="w-4 h-4" />
              Integrations
            </Button>
          </Link>
          <div className="flex items-center gap-3">
            <img src="/logos/route53.svg" alt="AWS Route 53" className="w-9 h-9 shrink-0" />
            <div>
              <h1 className="text-2xl font-bold">AWS Route 53</h1>
              <p className="text-sm text-muted-foreground">Hosted zones, DNS records, change history</p>
            </div>
          </div>
        </div>
        <EmptyState
          icon={ShieldOff}
          title="AWS Route 53 is not configured"
          description="AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not set for this container. Credentials are injected via Bitwarden Secrets Manager (BWS) at the container entrypoint — see docker-entrypoint.sh — not set directly in .env."
        />
      </div>
    );
  }

  return (
    <div className="container mx-auto py-4 md:py-8 px-4 space-y-6">
      <div className="flex items-center gap-4">
        <Link href="/admin/sync">
          <Button variant="outline" size="sm" className="gap-2">
            <ArrowLeft className="w-4 h-4" />
            Integrations
          </Button>
        </Link>
        <div className="flex items-center gap-3">
          <img src="/logos/route53.svg" alt="AWS Route 53" className="w-9 h-9 shrink-0" />
          <div>
            <h1 className="text-2xl font-bold">AWS Route 53</h1>
            <p className="text-sm text-muted-foreground">Hosted zones, DNS records, change history</p>
          </div>
        </div>
        <div className="ml-auto">
          <Button onClick={handleSyncNow} disabled={syncing || syncStatus?.inProgress}>
            {syncing || syncStatus?.inProgress ? (
              <Loader2 className="w-4 h-4 mr-2 animate-spin" />
            ) : (
              <RefreshCw className="w-4 h-4 mr-2" />
            )}
            Sync Now
          </Button>
        </div>
      </div>

      <div className="flex items-center justify-between rounded-lg border p-4 bg-muted/30">
        <div className="space-y-0.5">
          <p className="text-sm font-medium">
            {zoneCount.toLocaleString()} zones · {recordCount.toLocaleString()} records ·{' '}
            {historyRowCount.toLocaleString()} history rows
          </p>
          <p className="text-xs text-muted-foreground flex items-center gap-2">
            Last sync:{' '}
            {lastSyncHistory ? (
              <>
                <StatusBadge tone={syncStatusTone(lastSyncHistory.status)}>
                  {lastSyncHistory.status}
                </StatusBadge>
                {fmtDate(lastSyncHistory.completed_at ?? lastSyncHistory.started_at, tz)}
              </>
            ) : (
              'Never'
            )}
          </p>
        </div>
      </div>

      <Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
        <TabsList className="grid w-full max-w-2xl grid-cols-4">
          <TabsTrigger value="zones">Zones</TabsTrigger>
          <TabsTrigger value="records">Records</TabsTrigger>
          <TabsTrigger value="history">History</TabsTrigger>
          <TabsTrigger value="schedule">Schedule</TabsTrigger>
        </TabsList>

        {/* ── Zones tab ── */}
        <TabsContent value="zones" className="mt-6">
          <DataTable
            columns={zoneColumns}
            data={paginate(zones, zonePage, PAGE_SIZE)}
            totalCount={zones.length}
            page={zonePage}
            pageSize={PAGE_SIZE}
            onPageChange={setZonePage}
            onRowClick={handleSelectZone}
            isLoading={zonesLoading}
            emptyTitle="No hosted zones synced yet"
            emptyDescription="Run a sync to pull hosted zones from AWS Route 53."
          />
        </TabsContent>

        {/* ── Records tab ── */}
        <TabsContent value="records" className="mt-6 space-y-4">
          <div className="flex flex-wrap items-center gap-3">
            <div className="w-64">
              <Select value={selectedZoneId} onValueChange={handleZoneSelectChange}>
                <SelectTrigger>
                  <SelectValue placeholder="Select a zone" />
                </SelectTrigger>
                <SelectContent>
                  {zones.map((z) => (
                    <SelectItem key={z.id} value={z.id}>
                      {z.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className="w-40">
              <Select
                value={typeFilter}
                onValueChange={(v) => {
                  setTypeFilter(v);
                  setRecordPage(1);
                }}
              >
                <SelectTrigger>
                  <SelectValue placeholder="All types" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="all">All types</SelectItem>
                  {RECORD_TYPE_FILTERS.map((t) => (
                    <SelectItem key={t} value={t}>
                      {t}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <Button onClick={openCreate} disabled={!selectedZoneId} className="ml-auto">
              <Plus className="w-4 h-4 mr-2" />
              New record
            </Button>
          </div>

          {!selectedZoneId ? (
            <EmptyState
              icon={Globe}
              title="Select a zone"
              description="Choose a hosted zone above to view its DNS records."
            />
          ) : (
            <DataTable
              columns={recordColumns}
              data={paginate(records, recordPage, PAGE_SIZE)}
              totalCount={records.length}
              page={recordPage}
              pageSize={PAGE_SIZE}
              onPageChange={setRecordPage}
              onSearch={handleRecordSearch}
              isLoading={recordsLoading}
              emptyTitle="No records found"
              emptyDescription="Adjust the type filter or search, or create a new record."
            />
          )}
        </TabsContent>

        {/* ── History tab ── */}
        <TabsContent value="history" className="mt-6 space-y-4">
          {!selectedRecord ? (
            <EmptyState
              icon={HistoryIcon}
              title="No record selected"
              description="Pick a record's History action on the Records tab to view its append-only change ledger (create/update/delete, before/after values, actor, and whether the change came from Pulse or was detected as drift from an external edit)."
            />
          ) : (
            <>
              <div className="flex items-center justify-between rounded-lg border p-3 bg-muted/30">
                <p className="text-sm">
                  History for <span className="font-medium">{selectedRecord.name}</span>{' '}
                  <StatusBadge tone="neutral">{selectedRecord.type}</StatusBadge>
                </p>
                <Button variant="ghost" size="sm" onClick={clearHistorySelection}>
                  <X className="w-3.5 h-3.5 mr-1.5" />
                  Clear
                </Button>
              </div>
              <DataTable
                columns={historyColumns}
                data={paginate(historyRows, historyPage, HISTORY_PAGE_SIZE)}
                totalCount={historyRows.length}
                page={historyPage}
                pageSize={HISTORY_PAGE_SIZE}
                onPageChange={setHistoryPage}
                onRowClick={(row) => {
                  setHistoryDetail(row);
                  setHistoryDetailOpen(true);
                }}
                isLoading={historyLoading}
                emptyTitle="No history yet"
                emptyDescription="Changes to this record — from Pulse or detected drift — will appear here."
              />
            </>
          )}
        </TabsContent>

        {/* ── Schedule tab ── */}
        <TabsContent value="schedule" className="mt-6">
          <SyncScheduler />
        </TabsContent>
      </Tabs>

      <DetailModal
        open={zoneDetailOpen}
        onOpenChange={setZoneDetailOpen}
        title={zoneDetail?.name ?? 'Hosted Zone'}
        data={zoneDetail}
      />

      <DetailModal
        open={historyDetailOpen}
        onOpenChange={setHistoryDetailOpen}
        title={historyDetail ? `${historyDetail.recordName} — ${historyDetail.changeAction}` : 'Record History'}
        data={historyDetail}
      />

      <RecordEditorDialog
        open={editorOpen}
        onOpenChange={setEditorOpen}
        zoneId={selectedZoneId}
        mode={editorMode}
        record={editingRecord}
        onSaved={handleSaved}
      />

      <RecordDeleteConfirm
        open={deleteOpen}
        onOpenChange={setDeleteOpen}
        zoneId={selectedZoneId}
        record={deletingRecord}
        onSaved={handleSaved}
      />
    </div>
  );
}
