import { Dispatch, SetStateAction, useEffect, useState, useRef, useCallback } from 'react'
import cx from 'classnames'

import {
  CheckboxField,
  ConsentField,
  FormField,
  HtmlField,
  NumberField,
  SelectField,
  TextField,
} from '@/lib/api/general-inquiry-form'
import { ChoiceFormData, FieldValue } from '@/components/forms/ContactForm'
import Icon from '@/components/shared/Icon'

type UseFormFieldProps = {
  setFormData: Dispatch<SetStateAction<FieldValue[]>>
  formField: TextField | ConsentField | SelectField | CheckboxField | HtmlField | NumberField
  formData: FieldValue[]
}

type CustomFormFieldProps = {
  setFormData: Dispatch<SetStateAction<FieldValue[]>>
  formField: TextField | ConsentField | SelectField | CheckboxField | HtmlField | NumberField
  formFields?: FormField[]
  formData: FieldValue[]
  errors: { id: string; message: string }[]
}

type CustomSelectFieldProps = CustomFormFieldProps & {
  formField: SelectField
}
type CustomConsentFieldProps = CustomFormFieldProps & {
  formField: ConsentField
}

type CustomCheckboxFieldProps = {
  checkboxField: CheckboxFieldType
  setFormData: Dispatch<SetStateAction<FieldValue[]>>
  formFields?: FormField[]
  formData: FieldValue[]
  errors: { id: string; message: string }[]
}

type CustomCheckboxFieldsProps = {
  data: CheckboxField[]
  setFormData: Dispatch<SetStateAction<FieldValue[]>>
  formFields?: FormField[]
  formData: FieldValue[]
  errors: { id: string; message: string }[]
}

type CheckboxFieldType = {
  id: string
  index: number
  text: string
  label: string
  isRequired: boolean
}

type CustomHtmlFieldProps = {
  formField: HtmlField
  cssClass?: string
}

const useFormField = ({ setFormData, formField, formData }: UseFormFieldProps) => {
  const [value, setValue] = useState<string | boolean>('')

  useEffect(() => {
    const existingField = formData.find(field => field.id === formField.id)
    if (existingField) {
      setValue(existingField.value)
    }
  }, [formData, formField.id])

  const handleChange = (changedVal: string | boolean) => {
    const updatedFormData = [...formData]
    const existingField = updatedFormData.find(field => field.id === formField.id) as FieldValue
    existingField.value = changedVal
    setFormData(updatedFormData)
    setValue(changedVal)
  }

  return { value, handleChange }
}

export const CustomTextField = ({ setFormData, formField, formData, errors }: CustomFormFieldProps) => {
  const errorMessage = errors.find(error => error.id === formField.id)?.message || ''
  const { value, handleChange } = useFormField({ setFormData, formField, formData })
  const hasValue = value !== ''

  return (
    <div className="relative z-[1] mb-[60px]">
      <input
        type={formField.type}
        id={formField.id}
        name="name"
        onChange={e => handleChange(e.target.value)}
        className={cx(
          'form-input text-label relative block w-full h-[3.125rem] border-0 border-b bg-transparent mb-2 py-[10px] px-0 focus:outline-none focus:ring-0 peer',
          { 'border-b-2 border-accent-red': errorMessage }
        )}
        value={value as string}
      />
      <label
        className={cx(
          'absolute block text-label select-none pointer-events-none origin-[0_0] transition duration-100 delay-75 ease-[cubic-bezier(0,0.25,0.5,1)] p-[0em] left-0 top-2.5 peer-focus:translate-y-[-1.25em] peer-focus:scale-75',
          { 'translate-y-[-1.25em]': hasValue, 'scale-75': hasValue }
        )}
        htmlFor={formField.id}
      >
        {formField.label}
        {formField.isRequired && <span className="text-accent-red">*</span>}
      </label>
      {errorMessage ? <div className="text-accent-red text-body-sm">{errorMessage}</div> : ''}
    </div>
  )
}

export const CustomPhoneField = ({ setFormData, formField, formData, errors }: CustomFormFieldProps) => {
  const inputElem = useRef<HTMLInputElement | null>(null)
  const errorMessage = errors.find(error => error.id === formField.id)?.message || ''
  const { value, handleChange } = useFormField({ setFormData, formField, formData })
  const hasValue = value !== ''

  const handleOnChange = useCallback(() => {
    if (inputElem.current !== null && inputElem.current.value !== null) {
      const inputValue = inputElem.current.value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/) || ''

      inputElem.current.value = !inputValue[2]
        ? inputValue[1]
        : `${inputValue[1]}-${inputValue[2]}${`${inputValue[3] ? `-${inputValue[3]}` : ''}`}`
      const numbers = inputElem.current.value
      handleChange(numbers)
    }
  }, [handleChange])

  useEffect(() => {
    handleOnChange()
  }, [handleOnChange])

  return (
    <div className="relative z-[1] mb-[60px]">
      <input
        ref={inputElem}
        type={formField.type}
        id={formField.id}
        name="name"
        onChange={handleOnChange}
        className={cx(
          'form-input text-label relative block w-full h-[3.125rem] border-0 border-b bg-transparent mb-2 py-[10px] px-0 focus:outline-none focus:ring-0 peer',
          { 'border-b-2 border-accent-red': errorMessage }
        )}
        value={value as string}
      />
      <label
        className={cx(
          'absolute block text-label select-none pointer-events-none origin-[0_0] transition duration-100 delay-75 ease-[cubic-bezier(0,0.25,0.5,1)] p-[0em] left-0 top-2.5 peer-focus:translate-y-[-1.25em] peer-focus:scale-75',
          { 'translate-y-[-1.25em]': hasValue, 'scale-75': hasValue }
        )}
        htmlFor={formField.id}
      >
        {formField.label}
        {formField.isRequired && <span className="text-accent-red">*</span>}
      </label>
      {errorMessage ? <div className="text-accent-red text-body-sm">{errorMessage}</div> : ''}
    </div>
  )
}

export const CustomTextAreaField = ({ setFormData, formField, formData, errors }: CustomFormFieldProps) => {
  const errorMessage = errors.find(error => error.id === formField.id)?.message || ''
  const { value, handleChange } = useFormField({ setFormData, formField, formData })
  const hasValue = value !== ''

  return (
    <div className="mb-[60px]">
      <label
        className={cx(
          'block mb-[10px] text-label origin-[0_0] transition duration-100 delay-75 ease-[cubic-bezier(0,0.25,0.5,1)]',
          { 'scale-75': hasValue }
        )}
        htmlFor={formField.id}
      >
        {formField.label}
        {formField.isRequired && <span className="text-accent-red"> *</span>}
      </label>
      <textarea
        className={cx('form-input text-label w-full min-h-[150px] border py-10px', {
          'border-4 border-accent-red': errorMessage,
        })}
        key={formField.id}
        id={formField.id}
        name="name"
        onChange={e => handleChange(e.target.value)}
        value={value as string}
      />
      {errorMessage ? <div className="text-accent-red text-body-sm">{errorMessage}</div> : ''}
    </div>
  )
}

export const CustomConsentField = ({ setFormData, formField, formData, errors }: CustomConsentFieldProps) => {
  const errorMessage = errors.find(error => error.id === formField.id)?.message || ''
  const { value, handleChange } = useFormField({ setFormData, formField, formData })

  return (
    <div className="mb-[60px]">
      <label
        key={formField.id}
        htmlFor={formField.id}
        className="text-label mb-[20px] grid grid-cols-[1em_auto] gap-[15px]"
      >
        <input
          type="checkbox"
          onChange={e => handleChange(e.target.checked)}
          id={formField.id}
          name={formField.label}
          value={value as string}
          className='appearance-none bg-white text-current w-[24px] h-[24px] translate-y-[-0.075em] grid place-content-center m-0 border border-solid border-black before:content-[""] before:w-[14px] before:h-[14px] before:transition-[120ms] before:duration-[transform] before:ease-[ease-in-out] before:shadow-[inset_1em_1em_black] before:bg-black before:scale-0 checked:!bg-white hover:!bg-white focus:!bg-white checked:!border-black hover:!border-black focus:!border-black checked:before:scale-100 focus:!outline-none focus:!ring-0 focus:!ring-transparent'
        />
        {formField.checkboxLabel}
        {formField.isRequired && <span className="text-accent-red">*</span>}
      </label>
      {errorMessage ? <div className="text-accent-red text-body-sm">{errorMessage}</div> : ''}
    </div>
  )
}

export const CustomSelectField = ({ setFormData, formField, formData, errors }: CustomSelectFieldProps) => {
  const errorMessage = errors.find(error => error.id === formField.id)?.message || ''
  const [selectedValue, setSelectedValue] = useState<any>({
    selected: 'Select',
    value: '',
    isActive: false,
    isValid: false,
  })
  const { isActive, isValid, selected } = selectedValue
  const hasValue = selectedValue.value !== ''

  const toggleSelect = (e: any) => {
    e.preventDefault()
    setSelectedValue((prevState: any) => ({
      ...prevState,
      isActive: !isActive,
    }))
  }

  const handleChangeValue = (e: any, choice: any) => {
    e.preventDefault()
    const updatedFormData = [...formData]
    const existingField = updatedFormData.find(field => field.id === formField.id) as FieldValue
    existingField.value = choice.value
    setFormData(updatedFormData)
    setSelectedValue({ selected: choice.text, isActive: false, isValid: true })
  }

  return (
    <div id={formField.id} className="relative z-[1] mb-[60px]">
      <label
        id="select-label"
        htmlFor={formField.id}
        className={cx(
          'block text-label mb-3 block origin-[0_0] transition duration-100 delay-75 ease-[cubic-bezier(0,0.25,0.5,1)]',
          { 'scale-75': isActive || hasValue }
        )}
      >
        {formField.label}
        {formField.isRequired && <span className="text-accent-red">*</span>}
      </label>
      <div
        className={cx('w-full border border-black relative', {
          isActive: 'active',
          'border-4 border-[#FF2055]': errorMessage,
        })}
      >
        <button
          role="button"
          className="flex justify-between items-center w-full min-h-[50px] px-[25px] text-[20px] leading-[30px] text-left"
          onClick={e => toggleSelect(e)}
          tabIndex={0}
          aria-labelledby="select-label"
        >
          <span className={cx({ 'text-placeholder': !isValid })}>{selected}</span>
          <Icon
            name="arrow-down"
            className={cx('w-[21px] h-[21px] text-black transition ease-in-out duration-150', {
              'rotate-180': isActive,
            })}
          />
        </button>
        <ul aria-expanded={isActive} role="listbox" className={cx('', { block: isActive, hidden: !isActive })}>
          {formField.choices.map((choice: any, index) => (
            <li key={index}>
              <button
                tabIndex={0}
                // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
                role="option"
                className="group block w-full px-[25px] py-[10px] text-[20px] leading-[30px] text-left"
                onClick={e => handleChangeValue(e, choice)}
              >
                <span className="group-hover:border-b transition ease-in-out duration-150">{choice.text}</span>
              </button>
            </li>
          ))}
        </ul>
      </div>
      <div className="mb-4 text-accent-red italic">{errorMessage ? `Error: ${errorMessage}` : ''}</div>
    </div>
  )
}

export const CustomCheckboxFieldsGroup = ({ data, setFormData, formData, errors }: CustomCheckboxFieldsProps) => {
  return (
    <>
      {data.map(checkboxField => {
        return (
          <div key={checkboxField.label + checkboxField.id} className="mb-[60px]">
            <label className="block text-label border-b pb-[10px] mb-[30px]">{checkboxField.label}</label>
            {checkboxField.choices.map((choice, index) => {
              const formField = {
                id: checkboxField.id,
                index: index,
                text: choice.text,
                label: choice.text,
                isRequired: checkboxField.isRequired,
              } as CheckboxFieldType

              return (
                <CustomCheckboxField
                  key={checkboxField.id + index}
                  setFormData={setFormData}
                  checkboxField={formField}
                  formData={formData}
                  errors={errors}
                />
              )
            })}
          </div>
        )
      })}
    </>
  )
}

export const CustomCheckboxField = ({
  setFormData,
  checkboxField,
  formData,
}: // errors
CustomCheckboxFieldProps) => {
  const currentChoice = formData
    .find(field => field.id === checkboxField.id)
    ?.value.find((choice: ChoiceFormData) => choice.text === checkboxField.text)

  // const errorMessage = errors.find(error => error.id === checkboxField.id)?.message || ''

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const checkboxId = `${checkboxField.id}.${checkboxField.index + 1}`
    const updatedFormData = [...formData]
    const existingField: ChoiceFormData = updatedFormData
      .find(field => field.id === checkboxField.id)
      ?.value.find((choice: ChoiceFormData) => choice.inputId === checkboxId)

    existingField.value = e.target.checked

    setFormData(updatedFormData)
  }
  return (
    <div key={checkboxField.id}>
      <label
        key={checkboxField.id}
        htmlFor={checkboxField.id}
        className="text-label mb-[20px] grid grid-cols-[1em_auto] gap-[15px]"
      >
        <input
          type="checkbox"
          onChange={handleChange}
          id={checkboxField.id}
          name={checkboxField.label}
          checked={currentChoice.value}
          className='appearance-none bg-white text-current w-[24px] h-[24px] translate-y-[-0.075em] grid place-content-center m-0 border border-solid border-black before:content-[""] before:w-[14px] before:h-[14px] before:transition-[120ms] before:duration-[transform] before:ease-[ease-in-out] before:shadow-[inset_1em_1em_black] before:bg-black before:scale-0 checked:!bg-white hover:!bg-white focus:!bg-white checked:!border-black hover:!border-black focus:!border-black checked:before:scale-100 focus:!outline-none focus:!ring-0 focus:!ring-transparent'
        />
        {checkboxField.label}
        {checkboxField.isRequired && <span className="text-accent-red">*</span>}
      </label>
    </div>
  )
}

export const CustomHtmlField = ({ formField, cssClass }: CustomHtmlFieldProps) => {
  return <div key={formField.id} className={cx(cssClass)} dangerouslySetInnerHTML={{ __html: formField.content }} />
}

export const CustomRadioField = ({ setFormData, formField, formData, errors, formFields }: CustomSelectFieldProps) => {
  // filter just the ones that have "choices"
  const conditionalCheckboxFields = formFields?.filter((field: any) => {
    if (field.__typename === 'CheckboxField' && field.conditionalLogic) {
      return field.conditionalLogic.rules[0].fieldId === formField.id
    }
  }) as CheckboxField[]

  // filter just ones that have "content"
  const conditionalHtmlFields = formFields?.filter((field: FormField) => {
    if (field.__typename === 'HtmlField' && field.conditionalLogic) {
      return field.conditionalLogic.rules[0].fieldId === formField.id
    }
  }) as HtmlField[]

  // find the formData that has the same id as formField.id
  const formValue = formData.find((field: any) => field.id === formField.id)

  const errorMessage = errors.find(error => error.id === formField.id)?.message || ''
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const updatedFormData = [...formData]
    const existingField = updatedFormData.find(field => field.id === formField.id) as FieldValue
    existingField.value = e.target.value
    setFormData(updatedFormData)
  }

  return (
    <div key={formField.id}>
      <div className="mb-[60px]">
        <label className="block text-label border-b pb-[10px] mb-[30px]" htmlFor={formField.id}>
          {formField.label}
        </label>
        {formField.choices.map(choice => (
          <label
            key={formField.id + choice.value}
            htmlFor={choice.value}
            className="text-label mb-[20px] grid grid-cols-[1em_auto] gap-[15px]"
          >
            <input
              type="radio"
              id={choice.value}
              name={formField.label}
              value={choice.value}
              onChange={handleChange}
              className='appearance-none bg-white text-current w-[24px] h-[24px] translate-y-[-0.075em] grid place-content-center m-0 rounded-[50%] border border-solid border-black before:content-[""] before:w-[14px] before:h-[14px] before:transition-[120ms] before:duration-[transform] before:ease-[ease-in-out] before:shadow-[inset_1em_1em_black] before:bg-black before:rounded-[50%] before:scale-0 checked:!bg-white hover:!bg-white focus:!bg-white checked:!border-black hover:!border-black focus:!border-black checked:before:scale-100 focus:!outline-none focus:!ring-2'
            />
            {choice.text}
          </label>
        ))}
        <div className="mb-4 text-accent-red italic">{errorMessage ? `Error: ${errorMessage}` : ''}</div>
      </div>
      {conditionalHtmlFields?.length && formValue?.value === 'Yes'
        ? conditionalHtmlFields.map((field, index) => (
            <div key={index} className="bg-[#F8F8F8] p-[25px]">
              <CustomHtmlField key={field.id} formField={field} cssClass="text-label" />
            </div>
          ))
        : null}
      {conditionalCheckboxFields?.length && formValue?.value === 'Yes' ? (
        <div className="bg-[#F8F8F8] p-[25px] mb-[60px]">
          <CustomCheckboxFieldsGroup
            key={formField.label + formField.id}
            data={conditionalCheckboxFields}
            setFormData={setFormData}
            formData={formData}
            errors={errors}
          />
        </div>
      ) : null}
    </div>
  )
}
