// @ts-nocheck
"use client";

import { useRouter } from "next/navigation";
import React, { useCallback, useState } from "react";
import { useForm } from "react-hook-form";

import { Form } from "@/payload-types";
import { Button } from "./Button";
import RichText from "./RichText";
import { buildInitialFormState } from "./buildInitialFormState";
import { fields } from "./fields";
import { toast } from "react-toastify";

export type Value = unknown;

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

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

export type FormBlockType = {
  blockName?: string;
  blockType?: "formBlock";
  enableIntro?: boolean | null;
  form: number | Form;
  introContent?: {
    root: {
      type: string;
      children: {
        type: string;
        version: number;
        [k: string]: unknown;
      }[];
      direction: ("ltr" | "rtl") | null;
      format: "left" | "start" | "center" | "right" | "end" | "justify" | "";
      indent: number;
      version: number;
    };
    [k: string]: unknown;
  } | null;
};

export const FormBlock: React.FC<
  FormBlockType & {
    id?: string | null;
  }
> = (props) => {
  const {
    enableIntro,
    form: formFromProps,
    form: { id: formID, confirmationMessage, confirmationType, redirect, submitButtonLabel } = {},
    introContent,
  } = props;

  const formMethods = useForm({
    defaultValues: buildInitialFormState(formFromProps.fields),
  });
  const {
    control,
    formState: { errors },
    handleSubmit,
    register,
    reset,
    setValue,
  } = formMethods;

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

  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,
        }));

        const toastId = toast.loading("Sending...");

        // delay loading indicator by 1s
        loadingTimerID = setTimeout(() => {
          setIsLoading(true);
        }, 250);

        try {
          const req = await fetch(`/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);

            toast.error(res.errors?.[0]?.message || "Internal Server Error");
            toast.dismiss(toastId);
            setError({
              message: res.errors?.[0]?.message || "Internal Server Error",
              status: res.status,
            });

            return;
          }

          toast.success(<RichText content={confirmationMessage} />);
          toast.dismiss(toastId);
          setIsLoading(false);
          setHasSubmitted(true);
          reset();

          if (confirmationType === "redirect" && redirect) {
            const { url } = redirect;

            const redirectUrl = url;

            if (redirectUrl) router.push(redirectUrl);
          }
        } catch (err) {
          console.warn(err);

          toast.error("Something went wrong");
          toast.dismiss(toastId);
          setIsLoading(false);
          setError({
            message: "Something went wrong",
          });
        }
      };

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

  return (
    <div>
      {!!formFromProps?.title && <h2>{formFromProps.title}</h2>}
      <div className="mt-4">
        {!!enableIntro && introContent && !hasSubmitted && <RichText content={introContent} />}
        {isLoading && !hasSubmitted && <p>Loading, please wait...</p>}
        {error && <div className="text-red-500">{`${error.status || "500"}: ${error.message || ""}`}</div>}

        <form id={formID} onSubmit={handleSubmit(onSubmit)} className="rd-form">
          <div className="row space-y-4">
            {formFromProps &&
              formFromProps.fields &&
              formFromProps.fields.map((field, index) => {
                const Field: React.FC<any> = fields?.[field.blockType];
                if (Field) {
                  return (
                    <React.Fragment key={index}>
                      <Field
                        form={formFromProps}
                        {...field}
                        {...formMethods}
                        control={control}
                        errors={errors}
                        register={register}
                      />
                    </React.Fragment>
                  );
                }
                return null;
              })}
          </div>
          <Button appearance="primary" el="button" form={formID} label={submitButtonLabel} isLoading={isLoading} />
        </form>
      </div>
    </div>
  );
};
