import { ColumnType, type Columns } from "../types"
import type { Data, Fields, RawData } from "../../../types"
import { normalizeCheckboxValue } from "./normalizeCheckboxValue"

export const normalizeTableData = <T extends string>(columns: Columns<T>, data: RawData[], fields: Fields<T>) =>
  data.map((row) =>
    columns.reduce((acc, column) => {
      const curr = row[column.index]
      switch (column.type) {
        case ColumnType.matchedCheckbox: {
          const field = fields.find((field) => field.key === column.value)!
          if ("booleanMatches" in field.fieldType && Object.keys(field.fieldType).length) {
            const booleanMatchKey = Object.keys(field.fieldType.booleanMatches || []).find(
              (key) => key.toLowerCase() === curr?.toLowerCase(),
            )!
            const booleanMatch = field.fieldType.booleanMatches?.[booleanMatchKey]
            acc[column.value] = (booleanMatchKey ? booleanMatch : normalizeCheckboxValue(curr)) as Data<T>[T]
          } else {
            acc[column.value] = normalizeCheckboxValue(curr) as Data<T>[T]
          }
          return acc
        }
        case ColumnType.matched: {
          acc[column.value] = (curr === "" ? undefined : curr) as Data<T>[T]
          return acc
        }
        case ColumnType.matchedMultiInput: {
          const field = fields.find((field) => field.key === column.value)!
          if (curr) {
            const separator = field.fieldType.type === "multi-input" ? field.fieldType.separator || "," : ","
            acc[column.value] = curr.split(separator).map(v => v.trim()).filter(Boolean) as Data<T>[T]
          } else {
            acc[column.value] = undefined as Data<T>[T]
          }
          return acc
        }
        case ColumnType.matchedSelect:
        case ColumnType.matchedSelectOptions: {
          const matchedOption = column.matchedOptions.find(({ entry }) => entry === curr)
          acc[column.value] = (matchedOption?.value || undefined) as Data<T>[T]
          return acc
        }
        case ColumnType.matchedMultiSelect: {
          const field = fields.find((field) => field.key === column.value)!
          if (curr) {
            const separator = field.fieldType.type === "multi-select" ? field.fieldType.separator || "," : ","
            const entries = curr.split(separator).map(v => v.trim()).filter(Boolean)
            const values = entries.map(entry => {
              const matchedOption = column.matchedOptions.find(({ entry: optEntry }) => optEntry === entry)
              return matchedOption?.value
            }).filter(Boolean) as string[]
            acc[column.value] = (values.length ? values : undefined) as Data<T>[T]
          } else {
            acc[column.value] = undefined as Data<T>[T]
          }
          return acc
        }
        case ColumnType.empty:
        case ColumnType.ignored: {
          return acc
        }
        default:
          return acc
      }
    }, {} as Data<T>),
  )
