import React, { ReactNode, useContext } from 'react'
import {
  FormContext,
  FormFieldsType,
  FormFieldType,
  FormProps,
} from './Form.js'
import { FormField } from './FormField.js'
import { FormFieldGroup } from './FormFieldGroup.js'
import { TextInput } from '../TextInput/index.js'
import { TextAreaInput } from '../TextAreaInput/index.js'
import { SwitchInput } from '../SwitchInput/index.js'
import { CheckboxInput } from '../CheckboxInput/index.js'
import { NumberInput } from '../NumberInput/index.js'
import { DateInput } from '../DateInput/index.js'
import { SelectInput } from '../SelectInput/index.js'
import { RichTextEditor } from '../RichTextEditor/index.js'
import { getByPath, Path } from '@saulx/utils'
import { ReferenceInput } from '../ReferenceInput/index.js'
import { TagInput } from '../TagInput/index.js'

type FormFieldsProps = {}

function FormFields(_: FormFieldsProps) {
  const ctx = useContext(FormContext)

  if (!ctx) {
    throw new Error('missing form context')
  }

  const { fields, form, groups, activeGroup, endpoints } = ctx

  console.log('lefut', fields)

  function renderField(field: FormFieldType, path: Path) {
    return (
      <FormField
        key={path.toString()}
        label={field.label ?? path[path.length - 1].toString()}
        description={
          ['checkbox', 'switch'].includes(field.type)
            ? undefined
            : field.description
        }
        error={getByPath(form.errors, path)}
        note={field.note}
      >
        {(() => {
          switch (field.type) {
            case 'text':
              return (
                <TextInput
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  value={getByPath(form.values, path) as string | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  error={!!getByPath(form.errors, path)}
                  type={field.inputType}
                  placeholder={field.placeholder}
                />
              )
            case 'textarea':
              return (
                <TextAreaInput
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  value={getByPath(form.values, path) as string | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  error={!!getByPath(form.errors, path)}
                  placeholder={field.placeholder}
                />
              )
            case 'switch':
              return (
                <SwitchInput
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  value={getByPath(form.values, path) as boolean | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  description={
                    field.description ??
                    ((getByPath(form.values, path) as boolean | undefined)
                      ? 'On'
                      : 'Off')
                  }
                />
              )
            case 'checkbox':
              return (
                <CheckboxInput
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  value={getByPath(form.values, path) as boolean | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  error={!!getByPath(form.errors, path)}
                  description={
                    field.description ??
                    ((getByPath(form.values, path) as boolean | undefined)
                      ? 'On'
                      : 'Off')
                  }
                />
              )
            case 'number':
              return (
                <NumberInput
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  value={getByPath(form.values, path) as number | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  error={!!getByPath(form.errors, path)}
                  placeholder={field.placeholder}
                />
              )
            case 'date':
              return (
                <DateInput
                  variant="date"
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  value={getByPath(form.values, path) as number | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  error={!!getByPath(form.errors, path)}
                  placeholder={field.placeholder}
                />
              )
            case 'datetime':
              return (
                <DateInput
                  variant="date-time"
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  value={getByPath(form.values, path) as number | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  error={!!getByPath(form.errors, path)}
                  placeholder={field.placeholder}
                />
              )
            case 'select':
              return (
                <SelectInput
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  filterable={field.filterable}
                  options={field.options}
                  value={getByPath(form.values, path) as string | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  placeholder={field.placeholder}
                  error={!!getByPath(form.errors, path)}
                />
              )
            case 'richtext':
              return (
                <RichTextEditor
                  value={getByPath(form.values, path) as string | undefined}
                  onChange={(value) => form.setValue(path, value)}
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  error={!!getByPath(form.errors, path)}
                  placeholder={field.placeholder}
                />
              )
            case 'reference':
              return (
                <ReferenceInput
                  type={field.ref}
                  variant={field.variant}
                  value={getByPath(form.values, path)}
                  onChange={(value: string | string[]) =>
                    form.setValue(path, value)
                  }
                  endpoints={endpoints}
                  placeholder={field.placeholder}
                  placeholderIcon={field.placeholderIcon}
                  error={!!getByPath(form.errors, path)}
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                />
              )
            case 'tag':
              return (
                <TagInput
                  disabled={
                    field.disabled ||
                    form.isSubmitting ||
                    form.isDisabledFromOutside
                  }
                  variant={field.variant}
                  options={field.options}
                  value={getByPath(form.values, path)}
                  onChange={(value: any) => form.setValue(path, value)}
                  placeholder={field.placeholder}
                  placeholderIcon={field.placeholderIcon}
                  error={!!getByPath(form.errors, path)}
                />
              )

            default: {
              console.error('Form.Fields: unknown field type')
              throw new Error('Form.Fields: unknown field type')
            }
          }
        })()}
      </FormField>
    )
  }

  function renderFields(
    fields: FormFieldsType | FormFieldType,
    path: Path = [],
  ) {
    const children: JSX.Element[] = []
    console.log('lefut', children)

    for (const [key, field] of Object.entries(fields)) {
      if ('type' in field) {
        children.push(renderField(field, [...path, key]))
      } else {
        children.push(
          <FormFieldGroup key={key} label={key.toString()} nested>
            {...renderFields(field, [...path, key])}
          </FormFieldGroup>,
        )
      }
    }

    console.log(children)

    return children
  }

  if (activeGroup !== '__all') {
    const {
      label,
      description,
      fields: groupFields,
    } = groups.find((e) => e.label === activeGroup)

    return (
      <FormFieldGroup label={label} description={description}>
        {renderFields(
          Object.keys(fields).reduce((acc, curr) => {
            if (groupFields.includes(curr)) {
              acc[curr] = fields[curr]
            }

            return acc
          }, {} as FormFieldsType),
        )}
      </FormFieldGroup>
    )
  }

  return <FormFieldGroup>{renderFields(fields)}</FormFieldGroup>
}

export { FormFields }
export type { FormFieldsProps }
