import { useState, useEffect, useCallback, useMemo, useRef } from "react";
import { useRsi } from "../../../hooks/useRsi";
import { ErrorType } from "../../../types";
import { RowSelectionState } from "@tanstack/react-table";
import { toast } from "sonner";
import { useQuery } from "@tanstack/react-query";
import config from "@/config";
import { useValidation } from "./useValidation";
import { useRowOperations } from "./useRowOperations";
import { useTemplateManagement } from "./useTemplateManagement";
import { useFilterManagement } from "./useFilterManagement";
import { useUniqueItemNumbersValidation } from "./useUniqueItemNumbersValidation";
import { useUpcValidation } from "./useUpcValidation";
import { useInitialValidation } from "./useInitialValidation";
import { Props, RowData } from "./validationTypes";
import { normalizeCountryCode } from "../utils/countryUtils";
import { cleanPriceField } from "../utils/priceUtils";
import { correctUpcValue } from "../utils/upcUtils";

export const useValidationState = <T extends string>({
  initialData,
  onBack,
  onNext,
}: Props<T>) => {
  const { fields, rowHook, tableHook } = useRsi<T>();

  // Import validateField and validateUniqueField from useValidation
  const { validateField: validateFieldFromHook, validateUniqueField } = useValidation<T>(
    fields,
    rowHook
  );

  // Add ref to track template application state
  const isApplyingTemplateRef = useRef(false);

  // Core data state
  const [data, setData] = useState<RowData<T>[]>(() => {
    // Clean price fields in initial data before setting state
    return initialData.map((row, index) => {
      const updatedRow = { ...row } as Record<string, any>;

      // Ensure each row has a stable __index key for downstream lookups
      if (updatedRow.__index === undefined || updatedRow.__index === null || updatedRow.__index === '') {
        updatedRow.__index = String(index);
      }

      // Clean price fields using utility
      if (updatedRow.msrp !== undefined) {
        updatedRow.msrp = cleanPriceField(updatedRow.msrp);
      }
      if (updatedRow.cost_each !== undefined) {
        updatedRow.cost_each = cleanPriceField(updatedRow.cost_each);
      }

      // Set default tax category if not already set
      if (
        updatedRow.tax_cat === undefined ||
        updatedRow.tax_cat === null ||
        updatedRow.tax_cat === ""
      ) {
        updatedRow.tax_cat = "0";
      }

      // Set default shipping restrictions if not already set
      if (
        updatedRow.ship_restrictions === undefined ||
        updatedRow.ship_restrictions === null ||
        updatedRow.ship_restrictions === ""
      ) {
        updatedRow.ship_restrictions = "0";
      }

      // Normalize country code (COO) to 2-letter ISO if possible
      if (typeof updatedRow.coo === "string") {
        const raw = updatedRow.coo.trim();
        const normalized = normalizeCountryCode(raw);
        if (normalized) {
          updatedRow.coo = normalized;
        } else {
          // Uppercase 2-letter values as fallback
          if (raw.length === 2) updatedRow.coo = raw.toUpperCase();
        }
      }

      if (updatedRow.upc !== undefined && updatedRow.upc !== null) {
        const { corrected, changed } = correctUpcValue(updatedRow.upc);
        if (changed) {
          updatedRow.upc = corrected;
        }
      }

      if (updatedRow.barcode !== undefined && updatedRow.barcode !== null) {
        const { corrected, changed } = correctUpcValue(updatedRow.barcode);
        if (changed) {
          updatedRow.barcode = corrected;
        }
      }

      return updatedRow as RowData<T>;
    });
  });


  // Row selection state
  const [rowSelection, setRowSelection] = useState<RowSelectionState>({});

  // Validation state
  const [validationErrors, setValidationErrors] = useState<
    Map<number, Record<string, any[]>>
  >(new Map());
  const [rowValidationStatus, setRowValidationStatus] = useState<
    Map<number, "pending" | "validating" | "validated" | "error">
  >(new Map());

  // Add state for tracking cells in loading state
  const [validatingCells, setValidatingCells] = useState<Set<string>>(new Set());

  // Add global editing state to prevent validation during editing
  const [editingCells, setEditingCells] = useState<Set<string>>(new Set());
  const hasEditingCells = editingCells.size > 0;

  // Track initial validation lifecycle
  const [initialValidationComplete, setInitialValidationComplete] = useState(false);
  // Track last seen item_number signature to drive targeted uniqueness checks
  const lastItemNumberSigRef = useRef<string | null>(null);

  // Use row operations hook
  const { validateRow, updateRow, revalidateRows, copyDown } = useRowOperations<T>(
    data,
    fields,
    setData,
    setValidationErrors,
    validateFieldFromHook
  );

  // Use UPC validation hook - MUST be initialized before template management
  const upcValidation = useUpcValidation(data, setData, setValidationErrors);

  // Use unique item numbers validation hook
  const { validateUniqueItemNumbers } = useUniqueItemNumbersValidation<T>(
    data, 
    fields, 
    setValidationErrors
  );

  // Use template management hook
  const templateManagement = useTemplateManagement<T>(
    data,
    setData,
    rowSelection,
    setValidationErrors,
    setRowValidationStatus,
    validateRow,
    isApplyingTemplateRef,
    upcValidation,
    setValidatingCells
  );

  // Use filter management hook
  const filterManagement = useFilterManagement<T>(data, fields, validationErrors);

  // Disable global full-table revalidation on any data change.
  // Field-level validation now runs inside updateRow/validateRow, and per-column
  // uniqueness is handled surgically where needed.
  // Intentionally left blank to avoid UI lock-ups on small edits.
  useEffect(() => {
    return; // no-op
  }, [data, fields, hasEditingCells]);

  // Add field options query
  const { data: fieldOptionsData } = useQuery({
    queryKey: ["import-field-options"],
    queryFn: async () => {
      const response = await fetch(`${config.apiUrl}/import/field-options`);
      if (!response.ok) {
        throw new Error("Failed to fetch field options");
      }
      return response.json();
    },
    staleTime: 5 * 60 * 1000, // Consider data fresh for 5 minutes
    gcTime: 30 * 60 * 1000, // Keep in cache for 30 minutes
  });

  // Get display text for a template
  const getTemplateDisplayText = useCallback(
    (templateId: string | null) => {
      if (!templateId) return "Select a template";

      const template = templateManagement.templates.find((t) => t.id.toString() === templateId);
      if (!template) return "Unknown template";

      try {
        const companyId = template.company || "";
        const productType = template.product_type || "Unknown Type";

        // Find company name from field options
        const companyName =
          fieldOptionsData?.companies?.find(
            (c: { value: string; label: string }) => c.value === companyId
          )?.label || companyId;

        return `${companyName} - ${productType}`;
      } catch (error) {
        console.error(
          "Error formatting template display text:",
          error,
          template
        );
        return "Error displaying template";
      }
    },
    [templateManagement.templates, fieldOptionsData]
  );

  // Check if there are any errors
  const hasErrors = useMemo(() => {
    for (const [_, status] of rowValidationStatus.entries()) {
      if (status === "error") return true;
    }
    return false;
  }, [rowValidationStatus]);

  // Create a function to handle button clicks (continue or back)
  const handleButtonClick = useCallback(
    async (direction: "next" | "back") => {
      if (direction === "back" && onBack) {
        // If a specific action is defined for back, use it
        onBack();
        return;
      }

      if (direction === "next") {
        // When proceeding to the next screen, check for unvalidated rows first
        const hasErrors = [...validationErrors.entries()].some(
          ([_, errors]) => {
            return Object.values(errors).some((errorSet) =>
              errorSet.some((error) => error.type !== ErrorType.Required)
            );
          }
        );

        if (hasErrors) {
          // We have validation errors - ask the user to fix them first or continue anyway
          const shouldContinue = window.confirm(
            "There are validation errors in your data. Do you want to continue anyway?"
          );

          if (!shouldContinue) {
            // User chose to fix errors
            return;
          }
        }

        // Prepare the data for the next step
        try {
          // No toast here - unnecessary and distracting

          // Call onNext with the cleaned data
          if (onNext) {
            // Remove metadata fields before passing to onNext
            const cleanedData = data.map((row) => {
              const {
                __index,
                __template,
                __original,
                __corrected,
                __changes,
                __aiSupplemental: _aiSupplemental,
                ...cleanRow
              } = row;
              return cleanRow as any;
            });

            onNext(cleanedData);
          }
        } catch (error) {
          console.error("Error proceeding to next step:", error);
          toast.error("Error saving data");
        }
      }
    },
    [data, onBack, onNext, validationErrors]
  );
  const { isValidating: isInitialValidationRunning } = useInitialValidation<T>({
    data,
    fields,
    setData,
    setValidationErrors,
    validateUniqueItemNumbers,
    upcValidationComplete: upcValidation.initialValidationDone,
    onComplete: () => {
      setInitialValidationComplete(true);
    },
  });

  useEffect(() => {
    if (initialValidationComplete) return;
    if ((!data || data.length === 0) && upcValidation.initialValidationDone) {
      setInitialValidationComplete(true);
    }
  }, [data, initialValidationComplete, upcValidation.initialValidationDone]);

  const hasPendingUpcValidation = upcValidation.validatingRows.size > 0;

  // Separate initial validation from subsequent validations
  // isInitializing should ONLY be true during the first load, never again
  const isInitializing =
    !initialValidationComplete ||
    isInitialValidationRunning ||
    templateManagement.isLoadingTemplates ||
    (hasPendingUpcValidation && !upcValidation.initialValidationDone);

  const isValidating = isInitialValidationRunning;

  // Track initialization task statuses for the progress UI
  const initializationTasks = {
    upcValidation: {
      label: 'Generating item numbers',
      status: upcValidation.initialValidationDone ? 'completed' :
              hasPendingUpcValidation ? 'in_progress' : 'pending'
    },
    fieldValidation: {
      label: 'Checking for field errors',
      status: initialValidationComplete ? 'completed' :
              isInitialValidationRunning ? 'in_progress' : 'pending'
    },
    templateLoading: {
      label: 'Loading product templates',
      status: !templateManagement.isLoadingTemplates ? 'completed' :
              'in_progress'
    }
  };

  // Targeted uniqueness revalidation: run only when item_number values change
  useEffect(() => {
    if (!data || data.length === 0) return;

    // Build a simple signature of the item_number column
    const sig = data.map((r) => String((r as Record<string, any>).item_number ?? '')).join('|');
    if (lastItemNumberSigRef.current === sig) return;
    lastItemNumberSigRef.current = sig;

    // Compute unique errors for item_number only and merge
    const uniqueMap = validateUniqueField(data, 'item_number');
    const rowsWithUnique = new Set<number>();
    uniqueMap.forEach((_, idx) => rowsWithUnique.add(idx));

    setValidationErrors((prev) => {
      const newMap = new Map(prev);

      // Apply unique errors
      uniqueMap.forEach((errorsForRow, rowIdx) => {
        const existing = { ...(newMap.get(rowIdx) || {}) } as Record<string, any[]>;
        const info = (errorsForRow as any)['item_number'];
        const currentValue = (data[rowIdx] as any)?.['item_number'];
        // Only apply uniqueness error when the value is non-empty
        if (info && currentValue !== undefined && currentValue !== null && String(currentValue) !== '') {
          existing['item_number'] = [
            {
              message: info.message,
              level: info.level,
              source: info.source,
              type: info.type,
            },
          ];
        }
        // If value is now present, make sure to clear any lingering Required error
        if (currentValue !== undefined && currentValue !== null && String(currentValue) !== '' && existing['item_number']) {
          existing['item_number'] = (existing['item_number'] as any[]).filter((e) => e.type !== ErrorType.Required);
          if ((existing['item_number'] as any[]).length === 0) delete existing['item_number'];
        }
        if (Object.keys(existing).length > 0) newMap.set(rowIdx, existing);
        else newMap.delete(rowIdx);
      });

      // Remove stale unique errors for rows no longer duplicated
      newMap.forEach((rowErrs, rowIdx) => {
        const currentValue = (data[rowIdx] as any)?.['item_number'];
        const shouldRemoveUnique = !rowsWithUnique.has(rowIdx) || currentValue === undefined || currentValue === null || String(currentValue) === '';
        if (shouldRemoveUnique && (rowErrs as any)['item_number']) {
          const filtered = (rowErrs as any)['item_number'].filter((e: any) => e.type !== ErrorType.Unique);
          if (filtered.length > 0) (rowErrs as any)['item_number'] = filtered;
          else delete (rowErrs as any)['item_number'];
        }
        // If value now present, also clear any lingering Required error for this field
        if (currentValue !== undefined && currentValue !== null && String(currentValue) !== '' && (rowErrs as any)['item_number']) {
          const nonRequired = (rowErrs as any)['item_number'].filter((e: any) => e.type !== ErrorType.Required);
          if (nonRequired.length > 0) (rowErrs as any)['item_number'] = nonRequired;
          else delete (rowErrs as any)['item_number'];
        }

        if (Object.keys(rowErrs).length > 0) newMap.set(rowIdx, rowErrs);
        else newMap.delete(rowIdx);
      });

      return newMap;
    });
  }, [data, validateUniqueField, setValidationErrors]);

  // Update fields with latest options
  const fieldsWithOptions = useMemo(() => {
    if (!fieldOptionsData) return fields;

    return fields.map((field) => {
      // Skip fields that aren't select or multi-select
      if (
        typeof field.fieldType !== "object" ||
        (field.fieldType.type !== "select" &&
          field.fieldType.type !== "multi-select")
      ) {
        return field;
      }

      // Get the correct options based on field key
      let options = [];
      switch (field.key) {
        case "company":
          options = [...(fieldOptionsData.companies || [])];
          break;
        case "supplier":
          options = [...(fieldOptionsData.suppliers || [])];
          break;
        case "categories":
          options = [...(fieldOptionsData.categories || [])];
          break;
        case "themes":
          options = [...(fieldOptionsData.themes || [])];
          break;
        case "colors":
          options = [...(fieldOptionsData.colors || [])];
          break;
        case "tax_cat":
          options = [...(fieldOptionsData.taxCategories || [])];
          // Ensure tax_cat is always a select, not multi-select
          return {
            ...field,
            fieldType: {
              type: "select",
              options,
            },
          };
        case "ship_restrictions":
          options = [...(fieldOptionsData.shippingRestrictions || [])];
          break;
        case "artist":
          options = [...(fieldOptionsData.artists || [])];
          break;
        case "size_cat":
          options = [...(fieldOptionsData.sizes || [])];
          break;
        default:
          options = [...(field.fieldType.options || [])];
      }

      return {
        ...field,
        fieldType: {
          ...field.fieldType,
          options,
        },
      };
    });
  }, [fields, fieldOptionsData]);

  // Load templates on mount
  useEffect(() => {
    templateManagement.loadTemplates();
  }, [templateManagement.loadTemplates]);

  return {
    // Data
    data,
    setData,
    filteredData: filterManagement.filteredData,

    // Validation
    isValidating,
    isInitializing,
    initializationTasks,
    validationErrors,
    rowValidationStatus,
    validateRow,
    hasErrors,

    // CRITICAL: Export validatingCells to make it available to ValidationContainer
    validatingCells,
    setValidatingCells,

    // PERFORMANCE FIX: Export editing state management
    editingCells,
    setEditingCells,

    // Row selection
    rowSelection,
    setRowSelection,

    // Row manipulation
    updateRow,
    copyDown,

    // Templates
    templates: templateManagement.templates,
    isLoadingTemplates: templateManagement.isLoadingTemplates,
    selectedTemplateId: templateManagement.templateState.selectedTemplateId,
    showSaveTemplateDialog: templateManagement.templateState.showSaveTemplateDialog,
    newTemplateName: templateManagement.templateState.newTemplateName,
    newTemplateType: templateManagement.templateState.newTemplateType,
    setTemplateState: templateManagement.setTemplateState,
    templateState: templateManagement.templateState,
    loadTemplates: templateManagement.loadTemplates,
    saveTemplate: templateManagement.saveTemplate,
    applyTemplate: templateManagement.applyTemplate,
    applyTemplateToSelected: templateManagement.applyTemplateToSelected,
    getTemplateDisplayText,
    refreshTemplates: templateManagement.refreshTemplates,

    // UPC validation
    upcValidation,

    // Filters
    filters: filterManagement.filters,
    filterFields: filterManagement.filterFields,
    filterValues: filterManagement.filterValues,
    updateFilters: filterManagement.updateFilters,
    resetFilters: filterManagement.resetFilters,

    // Fields reference
    fields: fieldsWithOptions, // Return updated fields with options

    // Hooks
    rowHook,
    tableHook,

    // Button handling
    handleButtonClick,
    revalidateRows,
  };
};
