import { FC, FormEvent, RefObject, useEffect, useState } from 'react'
import cx from 'classnames'
import { useRouter } from 'next/router'

import { submitGeneralInquiryForm, GfForm, FormField, ConditionalFieldRule } from '@/lib/api/general-inquiry-form'
import type { PropsWithClassName } from '@/lib/types'
import {
  CustomTextField,
  CustomTextAreaField,
  CustomConsentField,
  CustomSelectField,
  CustomRadioField,
  CustomHtmlField,
  CustomPhoneField,
} from '@/components/forms/ContactFormFields'

export type FieldValue = {
  id: string
  values?: any
  value?: any
  emailValues?: { value: string }
}

export type CheckboxFieldValue = {
  id: string
  value: ChoiceFormData[]
  conditionalField: ConditionalFieldRule
}

type StepperProps = {
  totalSteps: number
  currentStep: number
  onStepChange: (step: number) => void
}

type Choice = {
  text: string
  value: string
}

export type ChoiceFormData = {
  inputId: string
  text: string
  choiceValue: string
  value: boolean
}

type ErrorType = { id: string; message: string }

type Props = PropsWithClassName & {
  formId: number
  form: GfForm
  contentRef: RefObject<HTMLElement>
}

const Stepper: FC<StepperProps> = ({ totalSteps, currentStep, onStepChange }) => {
  const steps = Array.from({ length: totalSteps }, (_, index) => index + 1)
  return (
    <div className="flex row mb-[60px]">
      {steps.map((step, index) => {
        const isDisabled = step > currentStep
        return (
          <div key={index} className={cx('flex justify-between items-center', { 'opacity-10': isDisabled })}>
            {index > 0 && <span className="sm:w-[60px] w-[40px] mx-[10px] block bg-black h-px"></span>}
            <button
              className="sm:w-[60px] sm:h-[60px] w-[50px] h-[50px] rounded-full bg-black text-white text-[30px] font-bold flex items-center justify-center"
              key={step}
              onClick={() => onStepChange(step)}
              disabled={step > currentStep}
            >
              {step}
            </button>
          </div>
        )
      })}
    </div>
  )
}

function transformFormDataForSubmission(formFields: FormField[], formValues: FieldValue[]) {
  return formFields.map(field => {
    const fieldValue = formValues.find(value => value.id == field.id)

    switch (field.type) {
      case 'EMAIL':
        return { id: field.id, emailValues: { value: fieldValue?.value } }
      case 'ADDRESS':
        return { id: field.id, addressValues: fieldValue?.value }
      case 'MULTISELECT':
        return { id: field.id, values: fieldValue?.value }
      case 'CHAIN_SELECT':
        return { id: field.id, chainedSelectValues: fieldValue?.value }
      case 'CHECKBOX':
        const conditionalField = (fieldValue as CheckboxFieldValue).conditionalField
        if (conditionalField) {
          const conditionalFieldValue = formValues.find(field => field.id === conditionalField.fieldId)
          if (conditionalFieldValue?.value === conditionalField.value) {
            const processedFieldValues = fieldValue?.value.map((choice: ChoiceFormData) => ({
              inputId: Number(choice.inputId),
              value: choice.value ? choice.choiceValue : null,
            }))

            // filter out array values of processedFieldValues where choice.value is null
            processedFieldValues?.filter((choice: ChoiceFormData) => choice.value !== null)
            return { id: field.id, checkboxValues: processedFieldValues || [] }
          } else {
            break
          }
        }
        return { id: field.id, checkboxValues: fieldValue?.value || [] }
      case 'LIST':
        return { id: field.id, listValues: fieldValue?.value }
      case 'NAME':
        return { id: field.id, nameValues: fieldValue?.value }
      case 'CONSENT':
        return { id: field.id, value: fieldValue?.value ? 'true' : '' }
      default:
        return { id: field.id, value: fieldValue?.value }
    }
  })
}

const ContactForm = ({ formId, className, form, contentRef }: Props) => {
  const formFieldsByPage = form.formFields.nodes.reduce<{ [key: number]: FormField[] }>((groupedFields, field) => {
    const pageNumber = field.pageNumber

    if (!groupedFields[pageNumber]) {
      groupedFields[pageNumber] = []
    }

    groupedFields[pageNumber].push(field)

    return groupedFields
  }, {})
  const [currentStep, setCurrentStep] = useState(1)
  const totalSteps = Object.keys(formFieldsByPage).length

  const router = useRouter()

  // if it's a checkbox field initialize the value to []
  const initialValues = form?.formFields.nodes.map(node => {
    if (node.__typename === 'CheckboxField') {
      // if checkbox field has a conditional field, initialize the value to have a value of:
      // node.id + '.' + conditionalField
      return {
        id: node.id,
        value: node.choices.map(
          (choice: Choice, i) =>
            ({
              inputId: `${node.id}.${i + 1}`,
              text: choice.text,
              choiceValue: choice.value,
              value: false,
            } as ChoiceFormData)
        ),
        conditionalField: node.conditionalLogic?.rules[0],
      } as CheckboxFieldValue
    } else {
      return {
        id: node.id,
        value: node?.defaultValue || '',
      } as FieldValue
    }
  })

  const [formData, setFormData] = useState(initialValues)
  const [errors, setErrors] = useState<{ id: string; message: string }[]>([])
  const [success, setSuccess] = useState(false)

  const errorsForCurrentStep = (response: { errors: ErrorType[] }) =>
    response.errors.filter(error => formFieldsByPage[currentStep].some(field => field.id === error.id))

  const handleStepChange = async (step: number) => {
    if (step > currentStep) {
      const formDataForPage = transformFormDataForSubmission(formFieldsByPage[currentStep], formData)

      const response = await submitGeneralInquiryForm(
        formDataForPage.filter(value => value) as FieldValue[],
        String(formId)
      )
      const responseErrorsForCurrentStep = errorsForCurrentStep(response)
      if (responseErrorsForCurrentStep.length > 0) {
        setErrors(response.errors)
        return
      } else {
        setErrors([])
      }
    }
    setCurrentStep(step)
    contentRef.current?.scrollIntoView({ behavior: 'smooth' })
  }

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault()

    const formattedFormData = transformFormDataForSubmission(form.formFields.nodes, formData)

    const response = await submitGeneralInquiryForm(
      formattedFormData.filter(value => value) as FieldValue[],
      String(formId)
    )

    if (currentStep === totalSteps) {
      if (response.errors) {
        setErrors(response.errors)
        setSuccess(false)
      } else {
        setErrors([])
        setFormData(initialValues)
        setSuccess(true)
        setTimeout(() => {
          router.push(response.confirmation.url)
        }, 0)
      }
    } else {
      handleStepChange(currentStep + 1)
    }
  }

  useEffect(() => {
    if (errors.length > 0) {
      setErrors([])
      setSuccess(false)
    }
  }, [formData])

  if (!form) return null

  return (
    <>
      {totalSteps > 1 && <Stepper totalSteps={totalSteps} currentStep={currentStep} onStepChange={handleStepChange} />}
      <form className={className}>
        {formFieldsByPage[currentStep].map(formField => {
          switch (formField.__typename) {
            case 'TextField':
            case 'EmailField':
            case 'PhoneField':
            case 'NumberField':
              return (
                <CustomTextField
                  key={formField.id}
                  setFormData={setFormData}
                  formField={formField}
                  formData={formData}
                  errors={errors}
                />
              )
            case 'PhoneField':
              return (
                <CustomPhoneField
                  key={formField.id}
                  setFormData={setFormData}
                  formField={formField}
                  formData={formData}
                  errors={errors}
                />
              )
            case 'TextAreaField':
              return (
                <CustomTextAreaField
                  key={formField.id}
                  setFormData={setFormData}
                  formField={formField}
                  formData={formData}
                  errors={errors}
                />
              )
            case 'ConsentField':
              return (
                <CustomConsentField
                  key={formField.id}
                  setFormData={setFormData}
                  formField={formField}
                  formData={formData}
                  errors={errors}
                />
              )
            case 'SelectField':
              return (
                <CustomSelectField
                  key={formField.id}
                  setFormData={setFormData}
                  formField={formField}
                  formData={formData}
                  errors={errors}
                />
              )
            case 'RadioField':
              return (
                <CustomRadioField
                  key={formField.id}
                  setFormData={setFormData}
                  formField={formField}
                  formFields={form.formFields.nodes}
                  formData={formData}
                  errors={errors}
                />
              )
            case 'CheckboxField':
              return (
                <>
                  {!formField.conditionalLogic && (
                    <>
                      {console.error('CheckboxField not supported')}
                      CheckboxField not supported
                      {/* <CustomCheckboxFieldsGroup
                        data={[]}
                        key={formField.id}
                        setFormData={setFormData}
                        formFields={[formField]}
                        formData={formData}
                        errors={errors}
                      /> */}
                    </>
                  )}
                </>
              )
            case 'HtmlField':
              return (
                <>
                  {!formField.conditionalLogic && (
                    <CustomHtmlField
                      key={formField.id}
                      formField={formField}
                      cssClass="text-subtitle [&>sub]:text-caption [&>sub]:text-gray-muted mb-[60px]"
                    />
                  )}
                </>
              )
            case 'PageField':
              return
            default:
              console.error(`Unknown form field type: ${formField.__typename}`)
          }
        })}

        {currentStep < totalSteps && (
          <button
            type="button"
            className="navbar-btn btn btn--arrow-block font-bold px-[40px] uppercase md:ml-0 ml-auto btn--arrow-block-dark"
            onClick={() => handleStepChange(currentStep + 1)}
          >
            Next
            <span aria-hidden className="arrow-block arrow-block-dark"></span>
          </button>
        )}

        {currentStep === totalSteps && (
          <button
            className="navbar-btn btn btn--arrow-block font-bold px-[40px] uppercase md:ml-0 ml-auto btn--arrow-block-dark"
            onClick={handleSubmit}
          >
            {form.submitButton.text}
            <span aria-hidden className="arrow-block arrow-block-dark"></span>
          </button>
        )}
        {success && <div className="text-white text-sm my-30px">{form.confirmations[0].page.node.slug}</div>}
      </form>
    </>
  )
}

export default ContactForm
