import { useCallback, useState } from "react"
import type XLSX from "xlsx"
import { UploadStep } from "./UploadStep/UploadStep"
import { SelectHeaderStep } from "./SelectHeaderStep/SelectHeaderStep"
import { SelectSheetStep } from "./SelectSheetStep/SelectSheetStep"
import { mapWorkbook } from "../utils/mapWorkbook"
import { ValidationStepNew } from "./ValidationStepNew"
import { ImageUploadStep } from "./ImageUploadStep/ImageUploadStep"
import { MatchColumnsStep, type GlobalSelections } from "./MatchColumnsStep/MatchColumnsStep"
import { exceedsMaxRecords } from "../utils/exceedsMaxRecords"
import { useRsi } from "../hooks/useRsi"
import type { RawData, Data } from "../types"
import { Progress } from "@/components/ui/progress"
import { useToast } from "@/hooks/use-toast"
import { addErrorsAndRunHooks } from "./ValidationStepNew/utils/dataMutations"

export enum StepType {
  upload = "upload",
  selectSheet = "selectSheet",
  selectHeader = "selectHeader",
  matchColumns = "matchColumns",
  validateData = "validateData",
  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
    }
  | {
      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 { toast } = useToast()
  const errorToast = useCallback(
    (description: string) => {
      toast({
        variant: "destructive",
        title: translations.alerts.toast.error,
        description,
      })
    },
    [toast, translations],
  )

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


  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
              });
            }
          }}
        />
      )
    case StepType.selectSheet:
      return (
        <SelectSheetStep
          sheetNames={state.workbook.SheetNames}
          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}
          onContinue={async (values, rawData, columns, globalSelections) => {
            try {
              const data = await matchColumnsStepHook(values, rawData, columns)
              const dataWithMeta = await addErrorsAndRunHooks(data, fields, rowHook, tableHook)
              
              // Apply global selections to each row of data if they exist
              const dataWithGlobalSelections = globalSelections 
                ? dataWithMeta.map((row: Data<string> & { __index?: string }) => {
                    const newRow = { ...row };
                    if (globalSelections.supplier) newRow.supplier = globalSelections.supplier;
                    if (globalSelections.company) newRow.company = globalSelections.company;
                    return newRow;
                  })
                : dataWithMeta;
              
              setPersistedGlobalSelections(globalSelections)
              onNext({
                type: StepType.validateData,
                data: dataWithGlobalSelections,
                globalSelections,
              })
            } catch (e) {
              errorToast((e as Error).message)
            }
          }}
          onBack={onBack}
        />
      )
    case StepType.validateData:
      // Always use the new ValidationStepNew component
      return (
        <ValidationStepNew
          initialData={state.data} 
          file={uploadedFile || new File([], "empty.xlsx")} 
          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={onBack}
          onSubmit={(data, file) => {
            // Create a Result object from the array data
            const result = {
              validData: data as Data<string>[],
              invalidData: [] as Data<string>[],
              all: data as Data<string>[]
            };
            onSubmit(result, file);
          }}
        />
      )
    default:
      return <Progress value={33} className="w-full" />
  }
}
