"use client";

import * as React from "react";
import {
  DealImportVirtualGrid,
  type DealImportVirtualGridColumn,
} from "@/components/deals/deal-import-virtual-grid";
import { useDropzone } from "react-dropzone";
import { toast } from "sonner";
import {
  Download,
  Upload,
  Plus,
  Redo2,
  Undo2,
  X,
  Upload as UploadIcon,
  Trash2,
  ListChecks,
} from "lucide-react";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Tabs, TabsExtra, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
  LEAD_IMPORT_MAX_ROWS,
  LEAD_IMPORT_CHUNK_SIZE,
} from "@/features/leads/api/deal-import-limits";
import { invalidateLeadsBoardColumnsForStages } from "@/features/leads/api/invalidate-leads-board-columns";
import { leadsKeys } from "@/features/leads/api/query-keys";
import {
  getFirstLeadStageIdFromPipelinesCache,
  useBulkCreateLeadsMutation,
} from "@/features/leads/hooks/use-bulk-create-leads-mutation";
import { useQueryClient } from "@tanstack/react-query";
import { buildDealsImportSampleUrl } from "@/features/leads/api/fetch-deals-import-sample-client";
import { normalizeLeadImportRow } from "@/features/leads/api/normalize-lead-import-row";
import { normalizeBusinessDealImportRow } from "@/features/business-deals/api/normalize-business-deal-import-row";
import { buildBusinessDealsImportSampleUrl } from "@/features/business-deals/api/fetch-business-deals-import-sample-client";
import { useBulkCreateBusinessDealsMutation } from "@/features/business-deals/hooks/use-bulk-create-business-deals-mutation";
import { useGetAllUsersQuery } from "@/api/rtk/teams-api";
import type {
  ExcelParseRequest,
  ExcelParseResponse,
} from "@/workers/excel-import.worker";
import { useAuthToken } from "@/hooks/use-auth-token";
import { useImportSampleExportWorker } from "@/hooks/use-import-sample-export-worker";
import { useBlobExportWorker } from "@/hooks/use-blob-export-worker";
import { buildImportSampleFilename } from "@/lib/build-import-sample-filename";
import { GridIcon } from "./deal-form-helpers";
import { Can } from "@/components/providers/ability-provider";
import { useAppDispatch, useAppSelector } from "@/store/hooks";
import {
  selectBusinessDealDialog,
  closeBusinessDealDialog,
  setBusy,
} from "@/store/slices/business-deal-dialog-slice";
import {
  clearDealImportGridHistory,
  clearDealImportSelectedRowIndexes,
  commitDealImportGridSnapshot,
  redoDealImportGrid,
  replaceDealImportGridSnapshot,
  resetDealImportGridSession,
  selectDealImportGridSession,
  setDealImportSelectedRowIndexes,
  undoDealImportGrid,
} from "@/store/slices/deal-import-grid-slice";

type GridRow = { isImported?: boolean; error?: string } & Record<string, any>;

function yieldToMainThread() {
  return new Promise<void>((resolve) => {
    setTimeout(resolve, 0);
  });
}

/** Above this row count, download server-built XLSX instead of JSON + client build. */
const IMPORT_SAMPLE_JSON_MAX_ROWS = 500;

const EXCEL_MIME =
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

function isEditableShortcutTarget(target: EventTarget | null): boolean {
  if (!(target instanceof HTMLElement)) return false;
  return (
    target.isContentEditable ||
    target.tagName === "INPUT" ||
    target.tagName === "TEXTAREA" ||
    target.tagName === "SELECT"
  );
}

function areIndexArraysEqual(a: number[], b: number[]): boolean {
  if (a.length !== b.length) return false;
  for (let i = 0; i < a.length; i++) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}

interface AddDealImportTabProps {
  pipelineId: string | null;
  onClose: () => void;
  onSuccess?: () => void;
  onUiLockedChange?: (locked: boolean) => void;
  sessionKey?: string;
  defaultTargetType?: "LEAD" | "DEAL";
  hideTargetSelection?: boolean;
}

export function AddDealImportTab({
  pipelineId,
  onClose,
  onSuccess,
  onUiLockedChange,
  sessionKey,
  defaultTargetType = "LEAD",
  hideTargetSelection = false,
}: AddDealImportTabProps) {
  const dispatch = useAppDispatch();
  const queryClient = useQueryClient();
  const resolvedSessionKey = sessionKey || "default-deal-import";
  const importSession = useAppSelector((state) =>
    selectDealImportGridSession(state, resolvedSessionKey),
  );

  const { downloadFromUrl, exporting: sampleExporting } =
    useImportSampleExportWorker();
  const { downloadFromUrl: downloadXlsxFromUrl, exporting: xlsxExporting } =
    useBlobExportWorker();
  const bulkCreateBusinessDeals = useBulkCreateBusinessDealsMutation();
  const bulkCreateLeads = useBulkCreateLeadsMutation();
  const { token: accessToken } = useAuthToken();
  const {
    data: importUsers = [],
    isSuccess: importUsersLoaded,
    isLoading: importUsersLoading,
    isFetching: importUsersFetching,
    isError: importUsersError,
  } = useGetAllUsersQuery(undefined, { skip: !accessToken });
  const [targetType, setTargetType] = React.useState<"LEAD" | "DEAL">(
    defaultTargetType,
  );
  const [leadImportInFlight, setLeadImportInFlight] = React.useState(false);

  // --- Web Worker for Excel parsing (off-main-thread) ---
  const excelWorkerRef = React.useRef<Worker | null>(null);
  const [isParsingFile, setIsParsingFile] = React.useState(false);

  // Pending resolver for the current parse request (one at a time)
  const pendingParseRef = React.useRef<{
    resolve: (result: { headers: string[]; rows: Record<string, string>[] }) => void;
    reject: (err: Error) => void;
  } | null>(null);

  function getExcelWorker(): Worker {
    if (!excelWorkerRef.current) {
      excelWorkerRef.current = new Worker(
        new URL("@/workers/excel-import.worker.ts", import.meta.url),
        { type: "module" },
      );

      excelWorkerRef.current.onmessage = (event: MessageEvent<ExcelParseResponse>) => {
        const msg = event.data;
        const pending = pendingParseRef.current;

        if (!pending) return;

        if (msg.type === "PARSE_SUCCESS") {
          pending.resolve({ headers: msg.headers, rows: msg.rows });
        } else if (msg.type === "PARSE_ERROR") {
          pending.reject(new Error(msg.message));
        }

        pendingParseRef.current = null;
        setIsParsingFile(false);
      };

      excelWorkerRef.current.onerror = (err) => {
        const pending = pendingParseRef.current;
        if (pending) {
          pending.reject(new Error("Excel worker failed: " + (err?.message || err)));
          pendingParseRef.current = null;
        }
        setIsParsingFile(false);
      };
    }
    return excelWorkerRef.current;
  }

  React.useEffect(() => {
    return () => {
      // Cleanup worker on unmount
      if (excelWorkerRef.current) {
        excelWorkerRef.current.terminate();
        excelWorkerRef.current = null;
      }
      pendingParseRef.current = null;
    };
  }, []);

  const gridHeaders = importSession.present.headers;
  const gridRows = importSession.present.rows as GridRow[];
  const gridReady = importSession.present.gridReady;
  const selectedRowIndexList = importSession.selectedRowIndexes;
  const selectedRowIndexes = React.useMemo(
    () => new Set(selectedRowIndexList),
    [selectedRowIndexList],
  );

  const [findReplaceOpen, setFindReplaceOpen] = React.useState(false);
  const [importedFileName, setImportedFileName] = React.useState<string | null>(
    null,
  );
  const [activeImportTabIndex, setActiveImportTabIndex] = React.useState(0);
  const [findReplaceMode, setFindReplaceMode] = React.useState<"find" | "replace">("find");
  const [findQuery, setFindQuery] = React.useState("");
  const [replaceQuery, setReplaceQuery] = React.useState("");
  const findInputRef = React.useRef<HTMLInputElement>(null);
  const [selectedPosition, setSelectedPosition] = React.useState<{ rowIdx: number; colIdx: number } | null>(null);

  const importFileInputRef = React.useRef<HTMLInputElement>(null);
  const gridRowsRef = React.useRef(gridRows);
  const selectedPositionRef = React.useRef(selectedPosition);
  const finalColumnsRef = React.useRef<DealImportVirtualGridColumn<GridRow>[]>(
    [],
  );

  React.useEffect(() => { gridRowsRef.current = gridRows; }, [gridRows]);
  React.useEffect(() => { selectedPositionRef.current = selectedPosition; }, [selectedPosition]);
  const canUndo = importSession.past.length > 0;
  const canRedo = importSession.future.length > 0;
  const sampleLoading = sampleExporting || xlsxExporting;
  const importing =
    targetType === "DEAL"
      ? bulkCreateBusinessDeals.isPending
      : leadImportInFlight;

  React.useEffect(() => {
    setTargetType(defaultTargetType);
  }, [defaultTargetType]);

  const CHUNK_SIZE = LEAD_IMPORT_CHUNK_SIZE;
  const [importProgress, setImportProgress] = React.useState<{
    processed: number;
    total: number;
  } | null>(null);

  const [bulkExcelImportActive, setBulkExcelImportActive] = React.useState(false);
  const importUiLocked = importing || importProgress != null || bulkExcelImportActive || isParsingFile;
  const selectableRowIndexes = React.useMemo(
    () =>
      gridRows.reduce<number[]>((indexes, row, index) => {
        if (!row.isImported) {
          indexes.push(index);
        }
        return indexes;
      }, []),
    [gridRows],
  );
  const selectedRowCount = React.useMemo(
    () =>
      selectableRowIndexes.filter((index) => selectedRowIndexes.has(index)).length,
    [selectableRowIndexes, selectedRowIndexes],
  );
  const allSelectableRowsSelected =
    selectableRowIndexes.length > 0 &&
    selectableRowIndexes.every((index) => selectedRowIndexes.has(index));
  const someSelectableRowsSelected =
    selectedRowCount > 0 && !allSelectableRowsSelected;

  const importTabs = React.useMemo(() => {
    if (!gridRows.length) return [];
    const tabs: Array<{ index: number; start: number; end: number }> = [];
    for (let start = 0; start < gridRows.length; start += CHUNK_SIZE) {
      tabs.push({
        index: tabs.length,
        start,
        end: Math.min(start + CHUNK_SIZE, gridRows.length),
      });
    }
    return tabs;
  }, [gridRows.length, CHUNK_SIZE]);

  const activeImportTab =
    importTabs[activeImportTabIndex] ?? importTabs[0] ?? null;
  const importRowOffset = activeImportTab?.start ?? 0;

  const visibleGridRows = React.useMemo(
    () =>
      activeImportTab
        ? gridRows.slice(activeImportTab.start, activeImportTab.end)
        : gridRows,
    [gridRows, activeImportTab],
  );

  const currentTabSelectableIndexes = React.useMemo(() => {
    if (!activeImportTab) return [];
    const indexes: number[] = [];
    for (let i = activeImportTab.start; i < activeImportTab.end; i++) {
      if (!gridRows[i]?.isImported) {
        indexes.push(i);
      }
    }
    return indexes;
  }, [activeImportTab, gridRows]);

  const allCurrentTabRowsSelected =
    currentTabSelectableIndexes.length > 0 &&
    currentTabSelectableIndexes.every((index) =>
      selectedRowIndexes.has(index),
    );
  const someCurrentTabRowsSelected =
    currentTabSelectableIndexes.some((index) =>
      selectedRowIndexes.has(index),
    ) && !allCurrentTabRowsSelected;
  const useImportTabs = importTabs.length > 1;

  const currentChunkUnimportedCount = React.useMemo(() => {
    if (!activeImportTab) return 0;
    return gridRows
      .slice(activeImportTab.start, activeImportTab.end)
      .filter((row) => !row.isImported).length;
  }, [activeImportTab, gridRows]);

  const currentChunkAllImported = React.useMemo(() => {
    if (!activeImportTab) return false;
    const tabRows = gridRows.slice(activeImportTab.start, activeImportTab.end);
    return tabRows.length > 0 && tabRows.every((row) => row.isImported);
  }, [activeImportTab, gridRows]);

  const allRowsImported =
    gridRows.length > 0 && gridRows.every((row) => row.isImported);

  React.useEffect(() => {
    if (activeImportTabIndex >= importTabs.length) {
      setActiveImportTabIndex(Math.max(0, importTabs.length - 1));
    }
  }, [activeImportTabIndex, importTabs.length]);

  const dealImportUserValidationReady =
    targetType !== "DEAL" || Boolean(accessToken) && importUsersLoaded;
  const importUserLookup = React.useMemo(() => {
    const ids = new Set<string>();
    const emails = new Set<string>();
    const names = new Set<string>();

    importUsers.forEach((user) => {
      const id = String(user.id ?? "").trim();
      const email = String(user.email ?? "").trim().toLowerCase();
      const name = String(user.name ?? "").trim().toLowerCase();

      if (id) ids.add(id);
      if (email) emails.add(email);
      if (name) names.add(name);
    });

    return { ids, emails, names };
  }, [importUsers]);

  React.useEffect(() => {
    dispatch(setBusy(importUiLocked));
  }, [importUiLocked, dispatch]);

  React.useEffect(() => {
    onUiLockedChange?.(importUiLocked);
  }, [importUiLocked, onUiLockedChange]);

  React.useEffect(() => {
    return () => {
      onUiLockedChange?.(false);
    };
  }, [onUiLockedChange]);

  React.useEffect(() => {
    const normalizedIndexes = selectedRowIndexList.filter(
      (index) => index < gridRows.length && !gridRows[index]?.isImported,
    );

    if (areIndexArraysEqual(normalizedIndexes, selectedRowIndexList)) {
      return;
    }

    dispatch(
      setDealImportSelectedRowIndexes({
        sessionKey: resolvedSessionKey,
        indexes: normalizedIndexes,
      }),
    );
  }, [dispatch, gridRows, resolvedSessionKey, selectedRowIndexList]);

  React.useEffect(() => {
    return () => {
      dispatch(resetDealImportGridSession({ sessionKey: resolvedSessionKey }));
    };
  }, [dispatch, resolvedSessionKey]);

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    disabled: importUiLocked,
    accept: {
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [".xlsx"],
      "application/vnd.ms-excel": [".xls"],
    },
    maxFiles: 1,
    onDrop: async (acceptedFiles) => {
      const file = acceptedFiles[0];
      if (!file) return;
      await parseFileToGrid(file);
    },
    onDropRejected: (fileRejections) => {
      const errors = fileRejections[0]?.errors || [];
      if (errors.some((e) => e.code === "file-invalid-type")) {
        toast.error("Please upload an Excel file (.xlsx or .xls)");
      } else if (errors.some((e) => e.code === "too-many-files")) {
        toast.error("Please upload only one file at a time");
      } else {
        toast.error("File upload failed");
      }
    },
  });

  const buildColumns = React.useCallback(
    (
      headers: string[],
      startIdx: number = 0,
    ): DealImportVirtualGridColumn<GridRow>[] => [
      {
        key: "__rowNum__",
        name: "#",
        width: 48,
        frozen: true,
        renderHeaderCell: () => (
          <div className="flex h-full w-full items-center justify-center font-bold text-[11px]">
            #
          </div>
        ),
        renderCell: ({ rowIdx, row }) => (
          <div className="relative flex h-full flex-col items-center justify-center">
            <span
              style={{
                fontSize: 11,
                color: row.isImported ? "#10b981" : "#9ca3af",
                fontWeight: row.isImported ? "bold" : "normal",
              }}
            >
              {startIdx + rowIdx + 1}
            </span>
            {row.isImported && (
              <div className="absolute -top-1 -right-1 h-2 w-2 rounded-full border border-white bg-emerald-500" />
            )}
          </div>
        ),
      },
      ...headers.map((h) => ({
        key: h,
        name: h,
        width: 160,
        minWidth: 120,
        editable: true,
        renderCell: ({ row }: { row: GridRow; rowIdx: number; globalRowIdx: number }) => {
          const val = row[h];
          const displayVal = val != null ? String(val) : "";
          const isMatch =
            findReplaceOpen &&
            findQuery.length > 0 &&
            displayVal.toLowerCase().includes(findQuery.toLowerCase());

          return (
            <div
              className={cn(
                "flex h-full items-center truncate px-2 transition-colors",
                isMatch &&
                  "border-x border-yellow-200 bg-yellow-100 font-bold text-yellow-900",
              )}
            >
              {displayVal}
            </div>
          );
        },
      })),
    ],
    [findReplaceOpen, findQuery],
  );


  const replaceGridSnapshot = React.useCallback(
    (snapshot: { headers: string[]; rows: GridRow[]; gridReady: boolean }) => {
      dispatch(
        replaceDealImportGridSnapshot({
          sessionKey: resolvedSessionKey,
          snapshot,
        }),
      );
    },
    [dispatch, resolvedSessionKey],
  );

  const commitGridSnapshot = React.useCallback(
    (snapshot: { headers: string[]; rows: GridRow[]; gridReady: boolean }) => {
      dispatch(
        commitDealImportGridSnapshot({
          sessionKey: resolvedSessionKey,
          snapshot,
        }),
      );
    },
    [dispatch, resolvedSessionKey],
  );

  const setSelectionIndexes = React.useCallback(
    (indexes: number[]) => {
      dispatch(
        setDealImportSelectedRowIndexes({
          sessionKey: resolvedSessionKey,
          indexes,
        }),
      );
    },
    [dispatch, resolvedSessionKey],
  );

  const clearSelection = React.useCallback(() => {
    dispatch(
      clearDealImportSelectedRowIndexes({ sessionKey: resolvedSessionKey }),
    );
  }, [dispatch, resolvedSessionKey]);

  const buildCurrentGridSnapshot = React.useCallback(
    (rows: GridRow[]) => ({
      headers: gridHeaders,
      rows,
      gridReady,
    }),
    [gridHeaders, gridReady],
  );


  React.useEffect(() => {
    if (!gridReady) {
      return;
    }

    const handleKeyDown = (event: KeyboardEvent) => {
      if (importUiLocked) {
        return;
      }

      const isModifierPressed = event.ctrlKey || event.metaKey;

      // Handle Ctrl+F and Ctrl+H even if focus is in an input (standard behavior)
      if (isModifierPressed && !event.altKey) {
        const key = event.key.toLowerCase();

        if (key === "f") {
          event.preventDefault();
          setFindReplaceMode("find");
          setFindReplaceOpen(true);
          setTimeout(() => findInputRef.current?.focus(), 10);
          return;
        }
        if (key === "h") {
          event.preventDefault();
          setFindReplaceMode("replace");
          setFindReplaceOpen(true);
          setTimeout(() => findInputRef.current?.focus(), 10);
          return;
        }

        // Excel-style Copy/Paste
        if (key === "c" && selectedPositionRef.current) {
          const row = gridRowsRef.current[selectedPositionRef.current.rowIdx];
          const column = finalColumnsRef.current[selectedPositionRef.current.colIdx];
          if (row && column && !column.key.startsWith("__")) {
            const value = row[column.key];
            navigator.clipboard.writeText(value != null ? String(value) : "");
            // Note: Not calling preventDefault here to allow browser copy if text is highlighted
          }
        }

        if (key === "v" && selectedPositionRef.current) {
          const row = gridRowsRef.current[selectedPositionRef.current.rowIdx];
          const column = finalColumnsRef.current[selectedPositionRef.current.colIdx];
          if (row && column && !column.key.startsWith("__") && !row.isImported) {
            event.preventDefault();
            navigator.clipboard.readText().then((text) => {
              if (text != null) {
                const newRows = [...gridRowsRef.current];
                newRows[selectedPositionRef.current!.rowIdx] = {
                  ...row,
                  [column.key]: text
                };
                commitGridSnapshot(buildCurrentGridSnapshot(newRows));
              }
            });
            return;
          }
        }
      }

      if (isEditableShortcutTarget(event.target)) {
        return;
      }

      if (!isModifierPressed || event.altKey) {
        if (event.key === "Escape" && findReplaceOpen) {
          setFindReplaceOpen(false);
        }
        return;
      }

      const key = event.key.toLowerCase();
      const shouldRedo = key === "y" || (key === "z" && event.shiftKey);
      const shouldUndo = key === "z" && !event.shiftKey;

      if (shouldUndo && canUndo) {
        event.preventDefault();
        dispatch(undoDealImportGrid({ sessionKey: resolvedSessionKey }));
        return;
      }

      if (shouldRedo && canRedo) {
        event.preventDefault();
        dispatch(redoDealImportGrid({ sessionKey: resolvedSessionKey }));
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => {
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [canRedo, canUndo, dispatch, gridReady, importUiLocked, resolvedSessionKey, findReplaceOpen, commitGridSnapshot, buildCurrentGridSnapshot]);

  const handleReplaceAll = () => {
    const query = findQuery;
    if (!query) {
      toast.error("Please enter a value to find");
      return;
    }

    let count = 0;
    const newRows = gridRows.map((row) => {
      if (row.isImported) return row;
      const newRow = { ...row };
      let rowChanged = false;

      Object.keys(row).forEach((key) => {
        if (key.startsWith("__")) return; // skip internal keys
        const val = row[key];
        if (typeof val === "string" && val.includes(query)) {
          newRow[key] = val.split(query).join(replaceQuery);
          rowChanged = true;
          count++;
        } else if (typeof val === "number" && String(val).includes(query)) {
          newRow[key] = String(val).split(query).join(replaceQuery);
          rowChanged = true;
          count++;
        }
      });
      return newRow;
    });

    if (count > 0) {
      dispatch(commitDealImportGridSnapshot({
        sessionKey: resolvedSessionKey,
        snapshot: buildCurrentGridSnapshot(newRows)
      }));
      toast.success(`Replaced ${count} occurrences`);
    } else {
      toast.info("No matches found");
    }
  };

  const handleReplace = () => {
    const query = findQuery;
    if (!query) {
      toast.error("Please enter a value to find");
      return;
    }

    let replaced = false;
    const newRows = gridRows.map((row) => {
      if (replaced || row.isImported) return row;
      const newRow = { ...row };

      const keys = Object.keys(row);
      for (const key of keys) {
        if (key.startsWith("__")) continue;
        const val = row[key];
        if (typeof val === "string" && val.includes(query)) {
          newRow[key] = val.replace(query, replaceQuery);
          replaced = true;
          break;
        } else if (typeof val === "number" && String(val).includes(query)) {
          newRow[key] = String(val).replace(query, replaceQuery);
          replaced = true;
          break;
        }
      }
      return newRow;
    });

    if (replaced) {
      dispatch(commitDealImportGridSnapshot({
        sessionKey: resolvedSessionKey,
        snapshot: buildCurrentGridSnapshot(newRows)
      }));
    } else {
      toast.info("No more matches found");
    }
  };

  const invalidateLeadsCachesAfterImport = React.useCallback(() => {
    void queryClient.invalidateQueries({ queryKey: leadsKeys.lists() });
    const importStageId = getFirstLeadStageIdFromPipelinesCache(
      queryClient,
      pipelineId ?? undefined,
    );
    const listParams = {
      pipelineId: pipelineId ?? undefined,
      stageType: "Lead" as const,
    };
    if (importStageId && pipelineId) {
      invalidateLeadsBoardColumnsForStages(
        queryClient,
        listParams,
        [importStageId],
        { invalidateCounts: true, invalidateList: true },
      );
      return;
    }
    void queryClient.invalidateQueries({
      queryKey: leadsKeys.boardCounts(listParams),
    });
  }, [pipelineId, queryClient]);

  const parseFileToGrid = async (file: File) => {
    if (isParsingFile) return;

    setIsParsingFile(true);

    try {
      const buf = await file.arrayBuffer();

      const worker = getExcelWorker();

      const result = await new Promise<{ headers: string[]; rows: Record<string, string>[] }>(
        (resolve, reject) => {
          // Store resolver so the onmessage handler can call it
          pendingParseRef.current = { resolve, reject };

          // Transfer the ArrayBuffer (zero-copy). Main thread buffer becomes unusable after this.
          const request: ExcelParseRequest = { type: "PARSE_EXCEL", buffer: buf };
          worker.postMessage(request, [buf]);
        },
      );

      if (result.rows.length > LEAD_IMPORT_MAX_ROWS) {
        toast.error(
          `This file has ${result.rows.length.toLocaleString()} rows. Maximum is ${LEAD_IMPORT_MAX_ROWS.toLocaleString()} per import.`,
        );
        return;
      }

      // Convert worker rows (Record<string,string>) to GridRow shape expected by the grid
      const gridRows: GridRow[] = result.rows.map((r) => ({ ...r }));

      replaceGridSnapshot({
        headers: result.headers,
        rows: gridRows,
        gridReady: true,
      });
      dispatch(clearDealImportGridHistory({ sessionKey: resolvedSessionKey }));
      setImportedFileName(file.name);
      setActiveImportTabIndex(0);
      clearSelection();
    } catch (err: any) {
      console.error("Excel parse via worker failed", err);
      toast.error(err?.message || "Failed to parse Excel file");
    } finally {
      setIsParsingFile(false);
    }
  };

  const getLeadClientError = React.useCallback(
    (row: Record<string, unknown>): string | null => {
      const normalized = normalizeLeadImportRow(row);
      const customerName = normalized.customerName;
      if (
        customerName === undefined ||
        customerName === null ||
        String(customerName).trim() === ""
      ) {
        return "Customer Name is required";
      }
      return null;
    },
    [],
  );

  const getBusinessDealClientError = React.useCallback(
    (row: Record<string, unknown>): string | null => {
      const normalized = normalizeBusinessDealImportRow(row);
      const title = String(normalized.Title ?? "").trim();
      const relatedTo = String(normalized["Related To"] ?? "")
        .trim()
        .toLowerCase();
      const leadId = String(normalized["Lead ID"] ?? "").trim();
      const leadName = String(normalized["Lead Name"] ?? "").trim();
      const leadEmail = String(normalized["Lead Email"] ?? "").trim();
      const customerId = String(normalized["Customer ID"] ?? "").trim();
      const customerName = String(normalized["Customer Name"] ?? "").trim();
      const customerEmail = String(normalized["Customer Email"] ?? "").trim();
      const companyName = String(normalized["Company Name"] ?? "").trim();
      const aeValues = Array.isArray(normalized["AE Emails"])
        ? normalized["AE Emails"]
        : [];
      const bdrValues = Array.isArray(normalized["BDR Emails"])
        ? normalized["BDR Emails"]
        : [];

      const findInvalidImportUserValue = (values: unknown[]): string | null => {
        if (!importUsersLoaded) return null;

        for (const value of values) {
          const trimmedValue = String(value ?? "").trim();
          if (!trimmedValue) continue;

          const lowerValue = trimmedValue.toLowerCase();
          const isKnownUser =
            importUserLookup.ids.has(trimmedValue) ||
            importUserLookup.emails.has(lowerValue) ||
            importUserLookup.names.has(lowerValue);

          if (!isKnownUser) {
            return trimmedValue;
          }
        }

        return null;
      };

      if (!title) return "Title is required";
      if (relatedTo !== "lead" && relatedTo !== "customer") {
        return 'Related To must be "Lead" or "Customer"';
      }

      if (relatedTo === "lead") {
        if (customerId || customerName || customerEmail) {
          return "Lead-linked rows must not also fill customer-specific columns";
        }
        if (!leadId && !leadName && !leadEmail) {
          return "Lead-linked rows need Lead Email, Lead Name, or Lead ID";
        }
      }

      if (relatedTo === "customer") {
        if (leadId || leadName || leadEmail) {
          return "Customer-linked rows must not also fill lead-specific columns";
        }
        if (!customerId && !customerName && !customerEmail && !companyName) {
          return "Customer-linked rows need Customer Email, Customer Name, Company Name, or Customer ID";
        }
      }

      const invalidAeValue = findInvalidImportUserValue(aeValues);
      if (invalidAeValue) {
        return `AE value "${invalidAeValue}" does not match any CRM user`;
      }

      const invalidBdrValue = findInvalidImportUserValue(bdrValues);
      if (invalidBdrValue) {
        return `BDR value "${invalidBdrValue}" does not match any CRM user`;
      }

      return null;
    },
    [importUserLookup, importUsersLoaded],
  );

  const getGridRowCheckpointError = React.useCallback(
    (row: GridRow): string | null => {
      if (row.isImported) {
        return null;
      }

      if (targetType === "DEAL" && !dealImportUserValidationReady) {
        return "Waiting for AE/BDR validation";
      }

      const { isImported, __rowNum__, __status__, error, ...rest } = row;
      const clientError =
        targetType === "DEAL"
          ? getBusinessDealClientError(rest as Record<string, unknown>)
          : getLeadClientError(rest as Record<string, unknown>);

      if (clientError) {
        return clientError;
      }

      return typeof error === "string" && error.trim() ? error : null;
    },
    [
      dealImportUserValidationReady,
      getBusinessDealClientError,
      getLeadClientError,
      targetType,
    ],
  );

  const handleGridFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    if (
      !file.name.endsWith(".xlsx") &&
      !file.name.endsWith(".xls") &&
      !file.name.endsWith(".csv")
    ) {
      toast.error("Please upload an Excel or CSV file");
      return;
    }
    await parseFileToGrid(file);
    if (importFileInputRef.current) importFileInputRef.current.value = "";
  };

  const handleBulkImport = async (chunkTabIndex?: number) => {
    if (targetType === "DEAL") {
      if (importUsersError) {
        toast.error("Could not load CRM users for AE/BDR pre-check. Please try again.");
        return;
      }

      if (!accessToken || importUsersLoading || importUsersFetching || !importUsersLoaded) {
        toast.error("AE/BDR pre-check is still loading CRM users. Please wait a moment and try again.");
        return;
      }
    }

    if (!pipelineId) {
      toast.error("Pipeline is required for import");
      return;
    }

    const scopedTab =
      chunkTabIndex !== undefined ? importTabs[chunkTabIndex] : undefined;
    const unimportedRows = scopedTab
      ? gridRows
          .slice(scopedTab.start, scopedTab.end)
          .map((row, offset) => ({
            ...row,
            originalIdx: scopedTab.start + offset,
          }))
          .filter((row) => !row.isImported)
      : gridRows
          .map((row, index) => ({ ...row, originalIdx: index }))
          .filter((row) => !row.isImported);

    if (!unimportedRows.length) {
      toast.error(
        scopedTab
          ? `Chunk ${scopedTab.index + 1} has no ${targetType === "DEAL" ? "deals" : "leads"} left to import`
          : `No ${targetType === "DEAL" ? "deals" : "leads"} to import or all rows are already imported`,
      );
      return;
    }
    if (gridRows.length > LEAD_IMPORT_MAX_ROWS) {
      toast.error(
        `Cannot import more than ${LEAD_IMPORT_MAX_ROWS.toLocaleString()} rows at once`,
      );
      return;
    }

    setBulkExcelImportActive(true);
    if (targetType === "LEAD") {
      setLeadImportInFlight(true);
    }
    const totalUnimported = unimportedRows.length;
    setImportProgress({ processed: 0, total: totalUnimported });
    if (!scopedTab) {
      dispatch(clearDealImportGridHistory({ sessionKey: resolvedSessionKey }));
    }
    clearSelection();

    const nextRows = [...gridRows];
    let successfulCount = 0;
    let failedCount = 0;
    let processedCount = 0;
    const entityLabelPlural = targetType === "DEAL" ? "deals" : "leads";

    try {
      for (let i = 0; i < unimportedRows.length; i += CHUNK_SIZE) {
        const chunk = unimportedRows.slice(i, i + CHUNK_SIZE);
        const validChunkRows: Array<Record<string, unknown>> = [];
        const validChunkMeta: typeof chunk = [];

        for (let rowIndex = 0; rowIndex < chunk.length; rowIndex += 1) {
          const row = chunk[rowIndex] as any;
          if (rowIndex > 0 && rowIndex % 64 === 0) {
            await yieldToMainThread();
          }

          const { isImported, __rowNum__, originalIdx, error, ...rest } = row;
          const clientError =
            targetType === "DEAL"
              ? getBusinessDealClientError(rest as Record<string, unknown>)
              : getLeadClientError(rest as Record<string, unknown>);

          if (clientError) {
            nextRows[row.originalIdx] = {
              ...nextRows[row.originalIdx],
              error: clientError,
            };
            failedCount += 1;
            processedCount += 1;
            continue;
          }

          nextRows[row.originalIdx] = {
            ...nextRows[row.originalIdx],
            error: undefined,
          };

          validChunkRows.push(
            targetType === "DEAL"
              ? normalizeBusinessDealImportRow(rest as Record<string, unknown>)
              : normalizeLeadImportRow(rest as Record<string, unknown>),
          );
          validChunkMeta.push(row);
        }

        setImportProgress((prev) =>
          prev ? { ...prev, processed: processedCount } : null,
        );

        if (!validChunkRows.length) {
          commitGridSnapshot(buildCurrentGridSnapshot([...nextRows]));
          continue;
        }

        try {
          if (targetType === "DEAL") {
            const result = await bulkCreateBusinessDeals.mutateAsync({
              deals: validChunkRows,
              pipelineId,
            });
            const resultByIndex = new Map(
              (result.results ?? []).map((rowResult) => [
                rowResult.rowIndex,
                rowResult,
              ]),
            );

            validChunkMeta.forEach((row, rowIndex) => {
              const rowResult = resultByIndex.get(rowIndex);
              if (rowResult?.status === "imported") {
                successfulCount += 1;
                nextRows[row.originalIdx] = {
                  ...nextRows[row.originalIdx],
                  isImported: true,
                  error: undefined,
                };
                return;
              }

              failedCount += 1;
              nextRows[row.originalIdx] = {
                ...nextRows[row.originalIdx],
                error: rowResult?.message ?? "Could not import this row",
              };
            });
          } else {
            const result = await bulkCreateLeads.mutateAsync({
              deals: validChunkRows,
              pipelineId,
              targetType,
            });
            const importedCount =
              result.stats?.dealsImported ?? validChunkMeta.length;
            successfulCount += importedCount;
            validChunkMeta.forEach((row) => {
              nextRows[row.originalIdx] = {
                ...nextRows[row.originalIdx],
                isImported: true,
                error: undefined,
              };
            });
          }

          processedCount = successfulCount + failedCount;
          commitGridSnapshot(buildCurrentGridSnapshot([...nextRows]));
          setImportProgress((prev) =>
            prev ? { ...prev, processed: processedCount } : null,
          );
        } catch (err: unknown) {
          console.error("Bulk import error at chunk start index", i, err);
          const msg = err instanceof Error ? err.message : "Batch import failed";
          toast.error(msg);

          validChunkMeta.forEach((row) => {
            nextRows[row.originalIdx] = {
              ...nextRows[row.originalIdx],
              error: msg,
            };
          });
          failedCount += validChunkMeta.length;
          processedCount = successfulCount + failedCount;
          commitGridSnapshot(buildCurrentGridSnapshot([...nextRows]));
          setImportProgress((prev) =>
            prev ? { ...prev, processed: processedCount } : null,
          );
          break;
        }
      }

      setImportProgress(null);
      if (successfulCount > 0) {
        if (scopedTab) {
          toast.success(
            `Chunk ${scopedTab.index + 1}: ${successfulCount} ${entityLabelPlural} imported`,
          );
        } else {
          toast.success(`${successfulCount} ${entityLabelPlural} imported successfully`);
        }
        if (targetType === "LEAD") {
          void Promise.resolve().then(() => {
            invalidateLeadsCachesAfterImport();
          });
        }
        onSuccess?.();
      }

      const allDone = nextRows.every((r) => r.isImported);
      if (allDone && successfulCount > 0) {
        toast.success(`All ${entityLabelPlural} imported successfully`);
        await new Promise<void>((resolve) => {
          setTimeout(resolve, 1000);
        });
        dispatch(resetDealImportGridSession({ sessionKey: resolvedSessionKey }));
        dispatch(closeBusinessDealDialog());
      }
    } finally {
      setBulkExcelImportActive(false);
      setLeadImportInFlight(false);
    }
  };

  const addGridRow = () => {
    if (!gridHeaders.length) return;
    const empty: GridRow = {};
    gridHeaders.forEach((header) => {
      empty[header] = "";
    });
    replaceGridSnapshot(buildCurrentGridSnapshot([...gridRows, empty]));
  };

  const toggleGridRowSelection = (idx: number, checked: boolean) => {
    const next = new Set(selectedRowIndexes);
    if (checked) {
      next.add(idx);
    } else {
      next.delete(idx);
    }

    setSelectionIndexes(Array.from(next));
  };

  const toggleSelectAllRows = (checked: boolean) => {
    setSelectionIndexes(checked ? selectableRowIndexes : []);
  };

  const toggleSelectAllRowsInTab = (checked: boolean) => {
    const next = new Set(selectedRowIndexes);
    currentTabSelectableIndexes.forEach((index) => {
      if (checked) {
        next.add(index);
      } else {
        next.delete(index);
      }
    });
    setSelectionIndexes(Array.from(next));
  };

  const deleteSelectedRows = () => {
    if (!selectedRowCount) return;

    replaceGridSnapshot(
      buildCurrentGridSnapshot(
        gridRows.filter((_, index) => !selectedRowIndexes.has(index)),
      ),
    );
    clearSelection();
  };

  const deleteGridRow = (idx: number) => {
    replaceGridSnapshot(
      buildCurrentGridSnapshot(gridRows.filter((_, index) => index !== idx)),
    );
    clearSelection();
  };

  const downloadSampleExcel = async (rows?: number) => {
    const filename = buildImportSampleFilename({
      kind: targetType === "DEAL" ? "business-deals" : "leads",
      rows,
    });
    const useServerXlsx =
      rows != null && rows > IMPORT_SAMPLE_JSON_MAX_ROWS;
    const url =
      targetType === "DEAL"
        ? buildBusinessDealsImportSampleUrl({
            rows,
            pipelineId,
            format: useServerXlsx ? "xlsx" : "json",
          })
        : buildDealsImportSampleUrl({
            rows,
            targetType,
            format: useServerXlsx ? "xlsx" : "json",
          });
    const toastId = toast.loading("Preparing sample file…");

    try {
      if (useServerXlsx) {
        await downloadXlsxFromUrl(url, filename, EXCEL_MIME);
      } else {
        await downloadFromUrl(url, filename);
      }
      toast.success("Sample downloaded — check your downloads", { id: toastId });
    } catch (err) {
      toast.dismiss(toastId);
      const message =
        err instanceof Error && err.message.trim()
          ? err.message
          : "Failed to download sample excel file";
      toast.error(message);
      console.error(err);
    }
  };

  const finalColumns = React.useMemo(() => {
    const baseColumns = buildColumns(gridHeaders, importRowOffset);
    const headerAllSelected = useImportTabs
      ? allCurrentTabRowsSelected
      : allSelectableRowsSelected;
    const headerSomeSelected = useImportTabs
      ? someCurrentTabRowsSelected
      : someSelectableRowsSelected;
    const onToggleSelectAll = useImportTabs
      ? toggleSelectAllRowsInTab
      : toggleSelectAllRows;

    const rowNumberColumn = {
      ...baseColumns[0],
    };
    const dataColumns = baseColumns.slice(1);

    return [
      rowNumberColumn,
      {
        key: "__select__",
        name: "",
        width: 56,
        minWidth: 56,
        frozen: true,
        renderHeaderCell: () => (
          <div className="flex h-full w-full items-center justify-center">
            <input
              type="checkbox"
              aria-label="Select all rows"
              checked={headerAllSelected}
              disabled={
                importUiLocked ||
                (useImportTabs
                  ? currentTabSelectableIndexes.length === 0
                  : selectableRowIndexes.length === 0)
              }
              ref={(input) => {
                if (input) {
                  input.indeterminate = headerSomeSelected;
                }
              }}
              onClick={(e) => e.stopPropagation()}
              onChange={(e) =>
                onToggleSelectAll(e.target.checked)
              }
              className="h-4 w-4 cursor-pointer accent-[#6C63FF] disabled:cursor-not-allowed"
              title="Select all removable rows"
            />
          </div>
        ),
        renderCell: ({
          row,
          globalRowIdx,
        }: {
          row: GridRow;
          rowIdx: number;
          globalRowIdx: number;
        }) => (
          <div className="flex h-full w-full items-center justify-center">
            <input
              type="checkbox"
              aria-label={`Select row ${globalRowIdx + 1}`}
              checked={selectedRowIndexes.has(globalRowIdx)}
              disabled={importUiLocked || row.isImported}
              onClick={(e) => e.stopPropagation()}
              onChange={(e) =>
                toggleGridRowSelection(
                  globalRowIdx,
                  e.target.checked,
                )
              }
              className="h-4 w-4 cursor-pointer accent-[#6C63FF] disabled:cursor-not-allowed"
              title={
                row.isImported
                  ? "Imported rows cannot be deleted"
                  : "Select row"
              }
            />
          </div>
        ),
      },
      {
        key: "__options__",
        name: "Options",
        width: 70,
        minWidth: 70,
        frozen: true,
        renderHeaderCell: () => (
          <div className="flex h-full w-full items-center justify-center text-[11px] font-bold text-gray-800">
            Options
          </div>
        ),
        renderCell: ({
          row,
          globalRowIdx,
        }) => (
          <div className="flex h-full w-full items-center justify-center">
            <button
              type="button"
              onClick={(e) => {
                e.stopPropagation();
                deleteGridRow(globalRowIdx);
              }}
              disabled={importUiLocked || row.isImported}
              className="p-1 text-gray-400 transition-colors hover:text-red-500 disabled:cursor-not-allowed disabled:opacity-30"
              title="Delete Row"
            >
              <Trash2 size={14} />
            </button>
          </div>
        ),
      },
      ...dataColumns,
      {
        key: "__status__",
        name: "Status",
        width: 240,
        renderCell: ({
          row,
          globalRowIdx,
        }: {
          row: GridRow;
          rowIdx: number;
          globalRowIdx: number;
        }) => {
          const checkpointError = getGridRowCheckpointError(row);
          const rowHeader =
            row.Title ||
            row.title ||
            row.customerName ||
            row["Customer Name"] ||
            row.Name ||
            row.name ||
            `Row ${globalRowIdx + 1}`;

          const statusText = row.isImported
            ? "Imported"
            : checkpointError
              ? `[${rowHeader}] ${checkpointError}`
              : "Ready to import";
          const statusClass = row.isImported
            ? "text-emerald-600"
            : checkpointError
              ? "text-red-600"
              : "text-gray-500";
          return (
            <div
              className={cn(
                "flex h-full w-full cursor-help items-center truncate px-1 text-[12px] font-medium",
                statusClass,
              )}
              title={statusText}
            >
              {!row.isImported && checkpointError && (
                <span className="mr-1.5 shrink-0">⚠</span>
              )}
              <span className="truncate">{statusText}</span>
            </div>
          );
        },
      },
    ];
  }, [
    buildColumns,
    gridHeaders,
    importRowOffset,
    useImportTabs,
    allCurrentTabRowsSelected,
    allSelectableRowsSelected,
    importUiLocked,
    currentTabSelectableIndexes.length,
    selectableRowIndexes.length,
    someCurrentTabRowsSelected,
    someSelectableRowsSelected,
    toggleSelectAllRows,
    toggleSelectAllRowsInTab,
    selectedRowIndexes,
    toggleGridRowSelection,
    deleteGridRow,
    getGridRowCheckpointError,
  ]);

  React.useEffect(() => { finalColumnsRef.current = finalColumns; }, [finalColumns]);

  return (
    <div className="flex flex-col h-full bg-white">
      {/* Target Selector */}
      {!hideTargetSelection && (
        <div className="px-5 md:px-7 py-4 border-b border-gray-100 bg-[#fcfcff]">
          <div className="flex flex-col gap-3">
            <div className="flex flex-col gap-1">
              <h3 className="text-[14px] font-bold text-gray-900">What are you importing?</h3>
              <p className="text-[12px] text-gray-500">Choose the destination for your data. This updates the required fields and instructions.</p>
            </div>
            <div className="flex flex-col gap-2 sm:flex-row">
              <button
                onClick={() => setTargetType("LEAD")}
                disabled={importUiLocked}
                className={cn(
                  "flex-1 p-3 rounded-xl border-2 transition-all text-left flex flex-col gap-1",
                  targetType === "LEAD"
                    ? "border-[#6C63FF] bg-[#6C63FF]/5 ring-1 ring-[#6C63FF]/20"
                    : "border-gray-100 bg-white hover:border-gray-200"
                )}
              >
                <div className="flex items-center justify-between">
                  <span className={cn("text-[13px] font-bold", targetType === "LEAD" ? "text-[#6C63FF]" : "text-gray-700")}>New Leads</span>
                  {targetType === "LEAD" && <div className="w-2 h-2 rounded-full bg-[#6C63FF]" />}
                </div>
                <span className="text-[11px] text-gray-500 leading-tight">Import new inquiries, prospects, or early-stage contacts.</span>
              </button>
              <button
                onClick={() => setTargetType("DEAL")}
                disabled={importUiLocked}
                className={cn(
                  "flex-1 p-3 rounded-xl border-2 transition-all text-left flex flex-col gap-1",
                  targetType === "DEAL"
                    ? "border-[#6C63FF] bg-[#6C63FF]/5 ring-1 ring-[#6C63FF]/20"
                    : "border-gray-100 bg-white hover:border-gray-200"
                )}
              >
                <div className="flex items-center justify-between">
                  <span className={cn("text-[13px] font-bold", targetType === "DEAL" ? "text-[#6C63FF]" : "text-gray-700")}>Sales Deals</span>
                  {targetType === "DEAL" && <div className="w-2 h-2 rounded-full bg-[#6C63FF]" />}
                </div>
                <span className="text-[11px] text-gray-500 leading-tight">Import qualified opportunities for existing customers or leads.</span>
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Toolbar */}
      <div className="shrink-0 border-b border-gray-100 px-5 py-4 md:px-7">
        <input
          ref={importFileInputRef}
          type="file"
          accept=".xlsx,.xls,.csv"
          className="hidden"
          onChange={handleGridFileChange}
        />
        <div className="flex flex-col gap-3">
          {!pipelineId && (
            <p className="w-full text-[12px] font-semibold text-amber-600">
              ⚠ Select a pipeline first to import.
            </p>
          )}
          <div className="flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between">
            <div className="flex min-w-0 flex-wrap items-center gap-2">
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={() => downloadSampleExcel()}
                disabled={sampleLoading}
                className="h-8 min-w-0 shrink gap-2 rounded-xl border-gray-200 text-[11px] md:h-9 md:text-[12px]"
              >
                <Download size={14} className="shrink-0" />
                <span className="truncate">
                  {sampleLoading ? "Downloading..." : `Sample (10 ${targetType === "LEAD" ? "leads" : "deals"})`}
                </span>
              </Button>
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={() => downloadSampleExcel(500)}
                disabled={sampleLoading}
                className="h-8 min-w-0 shrink gap-2 rounded-xl border-gray-200 text-[11px] md:h-9 md:text-[12px]"
              >
                <Download size={14} className="shrink-0" />
                <span className="truncate">
                  {sampleLoading ? "Downloading..." : `Sample (500 ${targetType === "LEAD" ? "leads" : "deals"})`}
                </span>
              </Button>
              <Can action="manage" subject="all">
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={() => downloadSampleExcel(4000)}
                  disabled={sampleLoading}
                  className="h-8 min-w-0 shrink gap-2 rounded-xl border-gray-200 text-[11px] md:h-9 md:text-[12px]"
                  title="Large file for load testing."
                >
                  <Download size={14} className="shrink-0" />
                  <span className="truncate">
                    {sampleLoading
                      ? "Downloading..."
                      : `Sample (4k ${targetType === "LEAD" ? "leads" : "deals"})`}
                  </span>
                </Button>
              </Can>
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={() => importFileInputRef.current?.click()}
                disabled={!pipelineId || importUiLocked}
                className="h-8 gap-2 rounded-xl border-dashed border-[#6C63FF] text-[11px] text-[#6C63FF] hover:bg-[#6C63FF]/5 md:h-9 md:text-[12px]"
              >
                <Upload size={14} className="shrink-0" />
                {gridReady ? "Replace" : "Upload File"}
              </Button>
              {gridReady && importedFileName ? (
                <span
                  className="inline-flex min-w-0 max-w-full items-center rounded-lg border border-gray-200 bg-white px-2.5 py-1 text-[11px] font-medium text-gray-600 md:max-w-[240px]"
                  title={importedFileName}
                >
                  <span className="truncate">{importedFileName}</span>
                </span>
              ) : null}
            </div>
            {gridReady && (
              <div className="flex min-w-0 flex-wrap items-center gap-2 border-t border-gray-100 pt-3 xl:border-t-0 xl:pt-0 xl:justify-end">
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  onClick={addGridRow}
                  disabled={importUiLocked}
                  className="h-8 gap-1.5 rounded-xl text-[11px] text-gray-600 hover:bg-gray-100 hover:text-gray-900 md:h-9 md:text-[12px]"
                >
                  <Plus size={14} /> Add Row
                </Button>
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  onClick={() =>
                    dispatch(undoDealImportGrid({ sessionKey: resolvedSessionKey }))
                  }
                  disabled={importUiLocked || !canUndo}
                  className="h-8 gap-1.5 rounded-xl text-[11px] text-gray-600 hover:bg-gray-100 hover:text-gray-900 md:h-9 md:text-[12px]"
                >
                  <Undo2 size={14} /> Undo
                </Button>
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  onClick={() =>
                    dispatch(redoDealImportGrid({ sessionKey: resolvedSessionKey }))
                  }
                  disabled={importUiLocked || !canRedo}
                  className="h-8 gap-1.5 rounded-xl text-[11px] text-gray-600 hover:bg-gray-100 hover:text-gray-900 md:h-9 md:text-[12px]"
                >
                  <Redo2 size={14} /> Redo
                </Button>
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  onClick={() => {
                    replaceGridSnapshot({
                      headers: [],
                      rows: [],
                      gridReady: false,
                    });
                    setImportedFileName(null);
                    clearSelection();
                  }}
                  disabled={importUiLocked}
                  className="h-8 gap-1.5 rounded-xl text-[11px] text-red-500 hover:bg-red-50 hover:text-red-600 md:h-9 md:text-[12px]"
                >
                  <X size={14} /> Clear
                </Button>
              </div>
            )}
          </div>
        </div>
      </div>

      {targetType === "DEAL" && (
        <div className="border-b border-[#6C63FF]/10 bg-[#6C63FF]/5 px-5 py-3 md:px-7">
          <p className="text-[12px] leading-relaxed text-gray-700 break-words">
            Start by filling the <span className="font-semibold">Title</span> for each deal. Then set{" "}
            <span className="font-semibold">Related To</span> to{" "}
            <span className="font-semibold">Lead</span> or{" "}
            <span className="font-semibold">Customer</span>. For lead-linked rows, fill{" "}
            <span className="font-semibold">Lead Email</span> or{" "}
            <span className="font-semibold">Lead Name</span>. For customer-linked rows, fill{" "}
            <span className="font-semibold">Customer Email</span>,{" "}
            <span className="font-semibold">Customer Name</span>, or{" "}
            <span className="font-semibold">Company Name</span>.
          </p>
        </div>
      )}

      {/* Grid area */}
      <div className="flex-1 min-h-0 overflow-hidden flex flex-col">
        {!gridReady ? (
          <div
            {...getRootProps()}
            className="flex flex-col items-center justify-center h-full gap-4 text-center px-8 py-12 cursor-pointer border-2 border-dashed border-gray-300 rounded-xl m-4 hover:border-[#6C63FF] hover:bg-[#6C63FF]/5 transition-colors"
          >
            <input {...getInputProps()} />
            <div className="w-16 h-16 rounded-2xl bg-[#6C63FF]/10 flex items-center justify-center">
              {isDragActive ? (
                <UploadIcon size={24} className="text-[#6C63FF]" />
              ) : (
                <GridIcon />
              )}
            </div>
            <div>
              <p className="text-[14px] font-bold text-gray-800 mb-1">
                {isDragActive
                  ? "Drop Excel file here"
                  : isParsingFile
                    ? "Parsing Excel…"
                    : "No data loaded"}
              </p>
              <p className="text-[12px] text-gray-500 max-w-xs">
                {isDragActive
                  ? "Release to upload the file"
                  : isParsingFile
                    ? "Reading spreadsheet. Large files may take a few seconds."
                    : targetType === "DEAL"
                      ? "Drag & drop an Excel or CSV file here, or click to browse. Use Related To plus lead/customer name or email values from the sample."
                      : "Drag & drop an Excel or CSV file here, or click to browse. Customer Name is required; Stage is optional (see sample)."}
              </p>
            </div>
            <Button
              type="button"
              size="sm"
              onClick={(e) => {
                e.stopPropagation();
                const input = document.createElement("input");
                input.type = "file";
                input.accept = ".xlsx,.xls,.csv";
                input.onchange = async (e) => {
                  const file = (e.target as HTMLInputElement)
                    .files?.[0];
                  if (file) await parseFileToGrid(file);
                };
                input.click();
              }}
              disabled={!pipelineId || importUiLocked}
              className="gap-2 rounded-xl bg-[#6C63FF] hover:bg-[#5a52e0] text-white font-semibold text-[12px] h-9 px-5"
            >
              <UploadIcon size={14} /> Browse Files
            </Button>
            {!pipelineId && (
              <p className="text-amber-500 text-[11px] font-medium">
                Please select a pipeline to enable import.
              </p>
            )}
          </div>
        ) : (
          <div className="h-full flex flex-col min-h-0">
            <div className="px-5 md:px-7 py-3 bg-gray-50/50 border-b border-gray-100 flex flex-col sm:flex-row items-center justify-between gap-3 shrink-0">
              <div className="flex flex-col gap-0.5">
                <h4 className="flex min-w-0 items-baseline gap-1 text-[13px] font-bold text-gray-800">
                  <span className="shrink-0">Review Data</span>
                  {importedFileName ? (
                    <span
                      className="min-w-0 truncate font-medium text-gray-500"
                      title={importedFileName}
                    >
                      · {importedFileName}
                    </span>
                  ) : null}
                </h4>
                <div className="flex flex-col">
                  <p className="text-[11px] text-gray-500 font-medium">
                    Double-click any cell to edit. Select rows to delete them in bulk.
                    Use <span className="text-[#6C63FF] font-semibold">Ctrl+F</span> to Find and <span className="text-[#6C63FF] font-semibold">Ctrl+H</span> to Replace values.
                  </p>
                  {(() => {
                    const errorRows = gridRows.filter(
                      (r) => !r.isImported && getGridRowCheckpointError(r),
                    );
                    const count = errorRows.length;
                    if (count === 0) return null;
                    const firstMsg = getGridRowCheckpointError(errorRows[0]);
                    return (
                      <p className="text-[11px] text-red-600 font-bold mt-0.5 flex items-center gap-1">
                        <span className="shrink-0">⚠</span>
                        <span className="truncate max-w-[400px]">
                          {count} row{count > 1 ? "s" : ""} need
                          {count === 1 ? "s" : ""} review: {firstMsg}
                        </span>
                      </p>
                    );
                  })()}
                </div>
              </div>
              <div className="flex items-center gap-2 shrink-0">
                <Button
                  type="button"
                  size="sm"
                  variant="outline"
                  onClick={deleteSelectedRows}
                  disabled={importUiLocked || selectedRowCount === 0}
                  className="gap-2 rounded-xl border-red-200 text-red-600 hover:bg-red-50 hover:text-red-700 text-[12px] h-9 px-4"
                >
                  <Trash2 size={14} />
                  {selectedRowCount > 0
                    ? `Delete Selected (${selectedRowCount})`
                    : "Delete Selected"}
                </Button>
                {!useImportTabs ? (
                  <Button
                    type="button"
                    size="sm"
                    onClick={() => handleBulkImport()}
                    disabled={
                      importUiLocked ||
                      !gridRows.length ||
                      !pipelineId ||
                      !dealImportUserValidationReady ||
                      allRowsImported
                    }
                    className={cn(
                      "gap-2 rounded-xl font-bold text-[12px] h-9 px-5 shadow-sm transition-all shadow-[#6C63FF]/20",
                      allRowsImported
                        ? "bg-emerald-50 text-emerald-600 border border-emerald-100 shadow-none cursor-default"
                        : "bg-[#6C63FF] hover:bg-[#5a52e0] text-white",
                    )}
                  >
                    {allRowsImported ? (
                      <>
                        <ListChecks size={16} /> All Imported
                      </>
                    ) : (
                      <>
                        <Upload size={16} />
                        {importUiLocked
                          ? "Importing..."
                          : `Import ${gridRows.filter((r) => !r.isImported).length} ${targetType === "LEAD" ? "Leads" : "Deals"}`}
                      </>
                    )}
                  </Button>
                ) : null}
              </div>
            </div>
            <div className="relative flex min-h-0 flex-1 flex-col overflow-hidden">
              {importUiLocked && (
                <div className="absolute inset-0 bg-white/70 backdrop-blur-[2px] z-[100] flex flex-col items-center justify-center gap-4 text-center">
                  <div className="relative">
                    <div className="w-16 h-16 rounded-full border-4 border-[#6C63FF]/10 border-t-[#6C63FF] animate-spin" />
                    <div className="absolute inset-0 flex items-center justify-center">
                      <Upload
                        className="text-[#6C63FF] animate-bounce"
                        size={20}
                      />
                    </div>
                  </div>
                  <div className="space-y-1">
                    <p className="text-[16px] font-extrabold text-gray-900 tracking-tight">
                      Importing {targetType === "LEAD" ? "Leads" : "Deals"}...
                    </p>
                    {importProgress ? (
                      <p className="text-[12px] text-gray-500 font-medium">
                        Processing {importProgress.processed} of{" "}
                        {importProgress.total} {targetType === "LEAD" ? "leads" : "deals"}. Please wait.
                      </p>
                    ) : (
                      <p className="text-[12px] text-gray-500 font-medium">
                        Wait a moment while we process your request.
                      </p>
                    )}
                  </div>
                  <div className="flex items-center gap-1.5 px-4 py-1.5 bg-[#6C63FF]/5 rounded-full border border-[#6C63FF]/10">
                    {importProgress && (
                      <div className="w-48 h-1.5 bg-gray-100 rounded-full overflow-hidden">
                        <div
                          className="h-full bg-[#6C63FF] transition-all duration-300"
                          style={{
                            width: `${(importProgress.processed / importProgress.total) * 100}%`,
                          }}
                        />
                      </div>
                    )}
                  </div>
                </div>
              )}
              {findReplaceOpen && (
                <div className="flex items-center gap-3 px-4 py-2 bg-gray-50 border-b border-gray-100 animate-in slide-in-from-top-2 duration-200">
                  <div className="flex items-center gap-2">
                    <span className="text-[11px] font-bold text-gray-400 uppercase tracking-wider">Find</span>
                    <input
                      ref={findInputRef}
                      type="text"
                      placeholder="Text to find..."
                      value={findQuery}
                      onChange={(e) => setFindQuery(e.target.value)}
                      className="h-8 w-48 px-2 bg-white border border-gray-200 rounded-md text-sm focus:outline-none focus:ring-1 focus:ring-[#6C63FF] focus:border-transparent transition-all"
                    />
                  </div>

                  {findReplaceMode === "replace" && (
                    <div className="flex items-center gap-2">
                      <span className="text-[11px] font-bold text-gray-400 uppercase tracking-wider">Replace</span>
                      <input
                        type="text"
                        placeholder="Replace with..."
                        value={replaceQuery}
                        onChange={(e) => setReplaceQuery(e.target.value)}
                        className="h-8 w-48 px-2 bg-white border border-gray-200 rounded-md text-sm focus:outline-none focus:ring-1 focus:ring-[#6C63FF] focus:border-transparent transition-all"
                      />
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={handleReplace}
                        className="h-8 px-3 text-[12px] font-bold bg-white border-gray-200 hover:bg-gray-50 text-gray-700"
                      >
                        Replace
                      </Button>
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={handleReplaceAll}
                        className="h-8 px-3 text-[12px] font-bold bg-white border-gray-200 hover:bg-gray-50 text-[#6C63FF] border-[#6C63FF]/20"
                      >
                        Replace All
                      </Button>
                    </div>
                  )}

                  <div className="flex-1" />

                  <button
                    onClick={() => setFindReplaceOpen(false)}
                    className="p-1.5 text-gray-400 hover:text-gray-600 hover:bg-gray-200 rounded-md transition-all"
                    title="Close (Esc)"
                  >
                    <X size={16} />
                  </button>
                </div>
              )}

              {useImportTabs ? (
                <div className="shrink-0 border-b border-gray-100 bg-white px-4 py-2">
                  <Tabs
                    value={String(activeImportTabIndex)}
                    onValueChange={(value) =>
                      setActiveImportTabIndex(Number(value))
                    }
                    className="gap-0"
                  >
                    <div className="flex min-w-0 items-center gap-2">
                      <div className="min-w-0 flex-1 overflow-x-auto scrollbar-themed [-ms-overflow-style:none] [scrollbar-width:thin] [&::-webkit-scrollbar]:h-1.5">
                        <TabsList className="h-auto w-max flex-nowrap justify-start gap-1">
                          {importTabs.map((tab) => {
                            const tabRows = gridRows.slice(tab.start, tab.end);
                            const errorCount = tabRows.filter(
                              (row) =>
                                !row.isImported &&
                                Boolean(getGridRowCheckpointError(row)),
                            ).length;
                            const tabUnimportedCount = tabRows.filter(
                              (row) => !row.isImported,
                            ).length;
                            const tabAllImported =
                              tabRows.length > 0 &&
                              tabRows.every((row) => row.isImported);
                            return (
                              <TabsTrigger
                                key={tab.index}
                                value={String(tab.index)}
                                className="h-8 shrink-0 flex-none px-3 text-[11px] font-semibold"
                              >
                                Chunk {tab.index + 1}
                                <span className="text-[10px] font-medium text-gray-500">
                                  ({tab.start + 1}–{tab.end})
                                </span>
                                {errorCount > 0 ? (
                                  <span className="rounded-full bg-red-100 px-1.5 py-0.5 text-[10px] font-bold text-red-600">
                                    {errorCount}
                                  </span>
                                ) : tabAllImported ? (
                                  <span className="rounded-full bg-emerald-100 px-1.5 py-0.5 text-[10px] font-bold text-emerald-600">
                                    Done
                                  </span>
                                ) : tabUnimportedCount > 0 ? (
                                  <span className="rounded-full bg-amber-100 px-1.5 py-0.5 text-[10px] font-bold text-amber-700">
                                    {tabUnimportedCount}
                                  </span>
                                ) : null}
                              </TabsTrigger>
                            );
                          })}
                        </TabsList>
                      </div>
                      <TabsExtra className="shrink-0 border-l border-gray-100 pl-2">
                        <Button
                          type="button"
                          size="sm"
                          onClick={() =>
                            void handleBulkImport(activeImportTabIndex)
                          }
                          disabled={
                            importUiLocked ||
                            !pipelineId ||
                            !dealImportUserValidationReady ||
                            currentChunkAllImported ||
                            currentChunkUnimportedCount === 0
                          }
                          className={cn(
                            "h-8 gap-1.5 rounded-xl px-3 text-[11px] font-bold shadow-sm whitespace-nowrap",
                            currentChunkAllImported
                              ? "border border-emerald-100 bg-emerald-50 text-emerald-600 shadow-none"
                              : "bg-[#6C63FF] text-white hover:bg-[#5a52e0] shadow-[#6C63FF]/20",
                          )}
                        >
                          {currentChunkAllImported ? (
                            <ListChecks size={14} />
                          ) : (
                            <Upload size={14} />
                          )}
                          {importUiLocked
                            ? "Importing..."
                            : currentChunkAllImported
                              ? "Chunk done"
                              : `Import chunk ${activeImportTabIndex + 1} (${currentChunkUnimportedCount})`}
                        </Button>
                      </TabsExtra>
                    </div>
                  </Tabs>
                  <p className="mt-1.5 text-[10px] font-medium text-gray-400">
                    Up to {LEAD_IMPORT_CHUNK_SIZE.toLocaleString()} rows per
                    chunk · scroll to switch chunks · import the active one
                  </p>
                </div>
              ) : null}

              <DealImportVirtualGrid
                columns={finalColumns}
                rows={visibleGridRows}
                rowOffset={importRowOffset}
                locked={importUiLocked}
                selectedPosition={selectedPosition}
                onSelectedCellChange={setSelectedPosition}
                onRowsChange={(newTabRows) => {
                  if (importUiLocked) return;
                  const nextRows = [...gridRows];
                  newTabRows.forEach((row, index) => {
                    nextRows[importRowOffset + index] = row;
                  });
                  replaceGridSnapshot(buildCurrentGridSnapshot(nextRows));
                }}
                getRowClassName={(row) =>
                  row.isImported
                    ? "bg-emerald-50/30 text-emerald-900/60 transition-colors"
                    : getGridRowCheckpointError(row)
                      ? "bg-red-50"
                      : ""
                }
                isRowEditable={(row) => !row.isImported}
              />
            </div>
          </div>
        )}
      </div>
      <div className="px-5 md:px-7 py-3 border-t border-gray-100 bg-gray-50 flex flex-col md:flex-row items-center justify-between gap-4 shrink-0">
        <div className="flex flex-wrap items-center justify-center md:justify-start gap-x-4 gap-y-2 text-[11px] text-gray-500">
          <div className="flex items-center gap-4">
            <span>
              Total:{" "}
              <span className="font-bold text-gray-800">
                {gridRows.length}
              </span>{" "}
              {targetType === "DEAL" ? "deals" : "leads"}
            </span>
            <span className="text-gray-300">|</span>
            <span>
              Imported:{" "}
              <span className="font-bold text-emerald-600">
                {gridRows.filter((r) => r.isImported).length}
              </span>
            </span>
            <span className="text-gray-300">|</span>
            <span>
              Remaining:{" "}
              <span className="font-bold text-amber-600">
                {gridRows.filter((r) => !r.isImported).length}
              </span>
            </span>
            <span className="text-gray-300">|</span>
            <span>
              Needs review:{" "}
              <span className="font-bold text-red-600">
                {gridRows.filter((r) => Boolean(getGridRowCheckpointError(r))).length}
              </span>
            </span>
          </div>

        </div>
        <div className="text-[11px] text-gray-400 font-medium whitespace-nowrap">
          Up to {LEAD_IMPORT_MAX_ROWS.toLocaleString()} rows per file · Click cell to edit · Ctrl+C/V copy/paste · Ctrl+F find · Ctrl+H replace · Ctrl+Z undo · Ctrl+Y redo
        </div>
      </div>
    </div>
  );
}
