'use client'

import type { FormFieldBlock } from '@payloadcms/plugin-form-builder/types'

import { useRouter } from 'next/navigation'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
import { DefaultDocumentIDType } from 'payload'

import { RichText } from '@/components/RichText'
import { Button } from '@/components/ui/button'
import { getClientSideURL } from '@/utilities/getURL'

import { buildInitialFormState } from '../Form/buildInitialFormState'
import { fields } from '../Form/fields'

export type Value = unknown

export interface Property {
  [key: string]: Value
}

export interface Data {
  [key: string]: Property | Property[]
}

type RenderableForm = {
  id: DefaultDocumentIDType
  confirmationMessage?: SerializedEditorState | null
  confirmationType?: 'message' | 'redirect' | null
  fields?: FormFieldBlock[] | null
  redirect?: { url?: string | null } | null
  submitButtonLabel?: string | null
}

export type ContactFormBlockType = {
  blockName?: string | null
  blockType?: 'contactForm'
  enableIntro?: boolean | null
  footerNote?: null | string
  form?: null | RenderableForm
  introContent?: SerializedEditorState | null
}

export const ContactFormBlockClient: React.FC<
  ContactFormBlockType & {
    id?: DefaultDocumentIDType
  }
> = (props) => {
  const { enableIntro, footerNote, form: formFromProps, introContent } = props

  const initialFormState = useMemo(
    () => buildInitialFormState(formFromProps?.fields || []),
    [formFromProps?.fields],
  )

  const formMethods = useForm({
    defaultValues: initialFormState,
  })
  const {
    control,
    formState: { errors },
    handleSubmit,
    register,
  } = formMethods

  const [isLoading, setIsLoading] = useState(false)
  const [hasSubmitted, setHasSubmitted] = useState<boolean>()
  const [error, setError] = useState<{ message: string; status?: string } | undefined>()
  const [hasMounted, setHasMounted] = useState(false)
  const router = useRouter()

  const formID = formFromProps?.id
  const confirmationMessage = formFromProps?.confirmationMessage
  const confirmationType = formFromProps?.confirmationType
  const redirect = formFromProps?.redirect
  const submitButtonLabel = formFromProps?.submitButtonLabel || 'Kirim Pesan'
  const hasRenderableForm = Boolean(formID && formFromProps?.fields?.length)
  const hasAsideContent = Boolean(enableIntro && introContent) || Boolean(footerNote)

  useEffect(() => {
    setHasMounted(true)
  }, [])

  const onSubmit = useCallback(
    (data: Data) => {
      let loadingTimerID: ReturnType<typeof setTimeout>
      const submitForm = async () => {
        setError(undefined)

        const dataToSend = Object.entries(data).map(([name, value]) => ({
          field: name,
          value,
        }))

        loadingTimerID = setTimeout(() => {
          setIsLoading(true)
        }, 1000)

        try {
          const req = await fetch(`${getClientSideURL()}/api/form-submissions`, {
            body: JSON.stringify({
              form: formID,
              submissionData: dataToSend,
            }),
            headers: {
              'Content-Type': 'application/json',
            },
            method: 'POST',
          })

          const res = await req.json()

          clearTimeout(loadingTimerID)

          if (req.status >= 400) {
            setIsLoading(false)
            setError({
              message: res.errors?.[0]?.message || 'Internal Server Error',
              status: res.status,
            })
            return
          }

          setIsLoading(false)
          setHasSubmitted(true)

          if (confirmationType === 'redirect' && redirect?.url) {
            router.push(redirect.url)
          }
        } catch (_err) {
          setIsLoading(false)
          setError({
            message: 'Something went wrong.',
          })
        }
      }

      void submitForm()
    },
    [confirmationType, formID, redirect, router],
  )

  return (
    <div className="container">
      <div
        className={
          hasAsideContent
            ? 'mx-auto grid max-w-6xl gap-8 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:gap-12'
            : 'mx-auto max-w-3xl'
        }
      >
        {hasAsideContent ? (
          <div className="space-y-6">
            {enableIntro && introContent ? (
              <RichText className="mb-0" data={introContent} enableGutter={false} />
            ) : null}

            {footerNote ? (
              <div className="rounded-[0.8rem] border border-border/80 bg-muted/40 p-4 text-sm leading-6 text-muted-foreground">
                {footerNote}
              </div>
            ) : null}
          </div>
        ) : null}

        <div className="rounded-[0.8rem] border border-border bg-card p-5 shadow-sm lg:p-8">
          <FormProvider {...formMethods}>
            {!hasMounted ? (
              <p className="text-sm text-muted-foreground">Memuat formulir kontak...</p>
            ) : (
              <>
                {!isLoading &&
                hasSubmitted &&
                confirmationType === 'message' &&
                confirmationMessage ? (
                  <RichText data={confirmationMessage} enableGutter={false} />
                ) : null}

                {isLoading && !hasSubmitted ? (
                  <p className="text-sm text-muted-foreground">Mengirim pesan, mohon tunggu...</p>
                ) : null}

                {error ? (
                  <div className="rounded-md border border-destructive/30 bg-destructive/10 px-4 py-3 text-sm text-destructive">
                    {`${error.status || '500'}: ${error.message || ''}`}
                  </div>
                ) : null}

                {!hasSubmitted ? (
                  hasRenderableForm ? (
                    <form id={String(formID)} onSubmit={handleSubmit(onSubmit)}>
                      <div className="mb-6 last:mb-0">
                        {formFromProps?.fields?.map((field, index) => {
                          const Field: React.FC<any> | undefined =
                            fields[field.blockType as keyof typeof fields]

                          if (!Field) {
                            return null
                          }

                          const fieldKey =
                            ('name' in field && field.name) ||
                            field.blockName ||
                            `contact-field-${index}`

                          return (
                            <div className="mb-6 last:mb-0" key={fieldKey}>
                              <Field
                                form={formFromProps}
                                {...field}
                                {...formMethods}
                                control={control}
                                errors={errors}
                                register={register}
                              />
                            </div>
                          )
                        })}
                      </div>

                      <Button form={String(formID)} type="submit" variant="default">
                        {submitButtonLabel}
                      </Button>
                    </form>
                  ) : (
                    <p className="text-sm leading-6 text-muted-foreground">
                      Konfigurasi form belum tersedia. Silakan periksa kembali hubungan form pada
                      blok ini.
                    </p>
                  )
                ) : null}
              </>
            )}
          </FormProvider>
        </div>
      </div>
    </div>
  )
}
