import { useCallback, useState, useEffect } from "react"
import type XLSX from "xlsx"
import { useQueryClient } from "@tanstack/react-query"
import { UploadStep } from "./UploadStep/UploadStep"
import { SelectHeaderStep } from "./SelectHeaderStep/SelectHeaderStep"
import { SelectSheetStep } from "./SelectSheetStep/SelectSheetStep"
import { mapWorkbook } from "../utils/mapWorkbook"
import { ValidationStep } from "./ValidationStep"
import { ImageUploadStep } from "./ImageUploadStep/ImageUploadStep"
import { MatchColumnsStep } from "./MatchColumnsStep/MatchColumnsStep"
import type { GlobalSelections, Columns } from "./MatchColumnsStep/types"
import { exceedsMaxRecords } from "../utils/exceedsMaxRecords"
import { useRsi } from "../hooks/useRsi"
import type { RawData, Data } from "../types"
import { Progress } from "@/components/ui/progress"
import { toast } from "sonner"
import { addErrorsAndRunHooks } from "./ValidationStep/utils/dataMutations"
import { computeMappingSignature, type MappingSignature } from "./ValidationStep/utils/mappingSignature"
import { useValidationStore } from "./ValidationStep/store/validationStore"
import { useImportSession } from "@/contexts/ImportSessionContext"
import type { ImportSession } from "@/types/importSession"

export enum StepType {
  upload = "upload",
  selectSheet = "selectSheet",
  selectHeader = "selectHeader",
  matchColumns = "matchColumns",
  validateData = "validateData",
  validateDataNew = "validateDataNew",
  imageUpload = "imageUpload",
}

export type StepState =
  | {
      type: StepType.upload
    }
  | {
      type: StepType.selectSheet
      workbook: XLSX.WorkBook
    }
  | {
      type: StepType.selectHeader
      data: RawData[]
    }
  | {
      type: StepType.matchColumns
      data: RawData[]
      headerValues: RawData
      globalSelections?: GlobalSelections
    }
  | {
      type: StepType.validateData
      data: any[]
      globalSelections?: GlobalSelections
      isFromScratch?: boolean
      mappingSignature?: MappingSignature
    }
  | {
      type: StepType.validateDataNew
      data: any[]
      file?: File
      globalSelections?: GlobalSelections
      isFromScratch?: boolean
      mappingSignature?: MappingSignature
    }
  | {
      type: StepType.imageUpload
      data: any[]
      file: File
      globalSelections?: GlobalSelections
    }

interface Props {
  state: StepState
  onNext: (v: StepState) => void
  onBack?: () => void
}

export const UploadFlow = ({ state, onNext, onBack }: Props) => {
  const {
    maxRecords,
    translations,
    uploadStepHook,
    selectHeaderStepHook,
    matchColumnsStepHook,
    fields,
    rowHook,
    tableHook,
    onSubmit  } = useRsi()
  const [uploadedFile, setUploadedFile] = useState<File | null>(null)
  const queryClient = useQueryClient()
  const resetValidationStore = useValidationStore((state) => state.reset)

  // Fresh taxonomy data per session:
  // Invalidate caches on mount and clear on unmount to ensure fresh data each import session
  useEffect(() => {
    // On mount - invalidate import-related query caches to fetch fresh data
    queryClient.invalidateQueries({ queryKey: ['field-options'] });
    queryClient.invalidateQueries({ queryKey: ['product-lines'] });
    queryClient.invalidateQueries({ queryKey: ['product-lines-mapped'] });
    queryClient.invalidateQueries({ queryKey: ['sublines'] });
    queryClient.invalidateQueries({ queryKey: ['sublines-mapped'] });

    return () => {
      // On unmount - remove queries from cache entirely and reset Zustand store
      queryClient.removeQueries({ queryKey: ['field-options'] });
      queryClient.removeQueries({ queryKey: ['product-lines'] });
      queryClient.removeQueries({ queryKey: ['product-lines-mapped'] });
      queryClient.removeQueries({ queryKey: ['sublines'] });
      queryClient.removeQueries({ queryKey: ['sublines-mapped'] });

      // Reset the validation store to clear productLinesCache and sublinesCache
      resetValidationStore();
    };
  }, [queryClient, resetValidationStore]);
  const errorToast = useCallback(
    (description: string) => {
      toast.error(translations.alerts.toast.error, { description })
    },
    [translations],
  )

  // Keep track of global selections across steps
  const [persistedGlobalSelections, setPersistedGlobalSelections] = useState<GlobalSelections | undefined>(
    state.type === StepType.validateData || state.type === StepType.validateDataNew || state.type === StepType.matchColumns
      ? state.globalSelections
      : undefined
  )

  // Keep the user's matched columns so navigating back to Match Columns restores them
  // (UploadFlow never unmounts during step nav, so this survives back-nav — same pattern
  // as persistedGlobalSelections above).
  const [persistedColumns, setPersistedColumns] = useState<Columns<string> | undefined>(undefined)

  // Import session context for session restoration
  const { loadSession, setGlobalSelections: setSessionGlobalSelections } = useImportSession()

  // Sync global selections to session context for autosave
  useEffect(() => {
    setSessionGlobalSelections(persistedGlobalSelections)
  }, [persistedGlobalSelections, setSessionGlobalSelections])

  // Handle restoring a saved session
  const handleRestoreSession = useCallback((session: ImportSession) => {
    // Load the session into context
    loadSession(session)

    // Update global selections if they exist
    if (session.global_selections) {
      setPersistedGlobalSelections(session.global_selections)
    }

    // Navigate to the appropriate step with session data
    if (session.current_step === 'imageUpload') {
      onNext({
        type: StepType.imageUpload,
        data: session.data,
        file: new File([], "restored-session.xlsx"),
        globalSelections: session.global_selections || undefined,
      })
    } else {
      // Default to validation step
      onNext({
        type: StepType.validateDataNew,
        data: session.data,
        globalSelections: session.global_selections || undefined,
        isFromScratch: true, // Treat restored sessions like "from scratch" for back navigation
      })
    }
  }, [loadSession, onNext])

  switch (state.type) {
    case StepType.upload:
      return (
        <UploadStep
          onContinue={async (workbook, file) => {
            setUploadedFile(file)
            const isSingleSheet = workbook.SheetNames.length === 1
            if (isSingleSheet) {
              if (maxRecords && exceedsMaxRecords(workbook.Sheets[workbook.SheetNames[0]], maxRecords)) {
                errorToast(translations.uploadStep.maxRecordsExceeded(maxRecords.toString()))
                return
              }
              try {
                const mappedWorkbook = await uploadStepHook(mapWorkbook(workbook))
                onNext({
                  type: StepType.selectHeader,
                  data: mappedWorkbook,
                })
              } catch (e) {
                errorToast((e as Error).message)
              }
            } else {
              onNext({ type: StepType.selectSheet, workbook })
            }
          }}
          setInitialState={(state) => {
            // Ensure the state has the correct type
            if (state.type === StepType.validateData) {
              onNext({
                type: StepType.validateData,
                data: state.data,
                isFromScratch: state.isFromScratch,
                globalSelections: undefined
              });
            }
          }}
          onRestoreSession={handleRestoreSession}
        />
      )
    case StepType.selectSheet:
      return (
        <SelectSheetStep
          sheetNames={state.workbook.SheetNames}
          workbook={state.workbook}
          onContinue={async (sheetName) => {
            if (maxRecords && exceedsMaxRecords(state.workbook.Sheets[sheetName], maxRecords)) {
              errorToast(translations.uploadStep.maxRecordsExceeded(maxRecords.toString()))
              return
            }
            try {
              const mappedWorkbook = await uploadStepHook(mapWorkbook(state.workbook, sheetName))
              onNext({
                type: StepType.selectHeader,
                data: mappedWorkbook,
              })
            } catch (e) {
              errorToast((e as Error).message)
            }
          }}
          onBack={onBack}
        />
      )
    case StepType.selectHeader:
      return (
        <SelectHeaderStep
          data={state.data}
          onContinue={async (...args) => {
            try {
              const { data, headerValues } = await selectHeaderStepHook(...args)
              onNext({
                type: StepType.matchColumns,
                data,
                headerValues,
                globalSelections: persistedGlobalSelections,
              })
            } catch (e) {
              errorToast((e as Error).message)
            }
          }}
          onBack={onBack}
        />
      )
    case StepType.matchColumns:
      return (
        <MatchColumnsStep
          data={state.data}
          headerValues={state.headerValues}
          initialGlobalSelections={persistedGlobalSelections}
          initialColumns={persistedColumns}
          onContinue={async (values, rawData, columns, globalSelections, useNewValidation) => {
            try {
              const data = await matchColumnsStepHook(values, rawData, columns)
              const dataWithMeta = await addErrorsAndRunHooks(data, fields, rowHook, tableHook, undefined, { costIsTotalCost: globalSelections?.costIsTotalCost })

              // Apply global selections to each row of data if they exist, and stamp a
              // stable positional id (__sourceRow) so the Validation store can align these
              // freshly-mapped rows with previously-edited rows on back-nav re-entry.
              const dataWithGlobalSelections = dataWithMeta.map(
                (row: Data<string> & { __index?: string }, rowIndex: number) => {
                  const newRow = { ...row } as any;
                  newRow.__sourceRow = rowIndex;
                  if (globalSelections?.supplier) newRow.supplier = globalSelections.supplier;
                  if (globalSelections?.company) newRow.company = globalSelections.company;
                  if (globalSelections?.line) newRow.line = globalSelections.line;
                  if (globalSelections?.subline) newRow.subline = globalSelections.subline;
                  return newRow;
                },
              );

              setPersistedGlobalSelections(globalSelections)
              setPersistedColumns(columns)

              // Route to new or old validation step based on user choice
              onNext({
                type: useNewValidation ? StepType.validateDataNew : StepType.validateData,
                data: dataWithGlobalSelections,
                globalSelections,
                mappingSignature: computeMappingSignature(columns, globalSelections),
              })
            } catch (e) {
              errorToast((e as Error).message)
            }
          }}
          onBack={onBack}
        />
      )
    case StepType.validateData:
    case StepType.validateDataNew:
      // Zustand-based ValidationStep component (both cases now use this)
      return (
        <ValidationStep
          initialData={state.data}
          file={uploadedFile || new File([], "empty.xlsx")}
          mappingSignature={state.mappingSignature}
          onBack={() => {
            // If we started from scratch, we need to go back to the upload step
            if (state.isFromScratch) {
              onNext({
                type: StepType.upload
              });
            } else if (onBack) {
              // Use the provided onBack function
              onBack();
            }
          }}
          onNext={(validatedData: any[]) => {
            // Go to image upload step with the validated data
            onNext({
              type: StepType.imageUpload,
              data: validatedData,
              file: uploadedFile || new File([], "empty.xlsx"),
              globalSelections: state.globalSelections
            });
          }}
          isFromScratch={state.isFromScratch}
        />
      )
    case StepType.imageUpload:
      return (
        <ImageUploadStep
          data={state.data}
          file={state.file}
          onBack={() => {
            // Go back to the validation step with the current data
            onNext({
              type: StepType.validateDataNew,
              data: state.data,
              file: state.file,
              globalSelections: state.globalSelections
            });
          }}
          onSubmit={(data, file, options) => {
            // Create a Result object from the array data
            const result = {
              validData: data as Data<string>[],
              invalidData: [] as Data<string>[],
              all: data as Data<string>[]
            };
            return onSubmit(result, file, options);
          }}
        />
      )
    default:
      return <Progress value={33} className="w-full" />
  }
}
