import React, {
  useState,
  ChangeEvent,
  FormEvent,
  Fragment,
  useEffect,
  useMemo,
  useCallback,
} from "react";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import Chip from "@mui/material/Chip";
import { DynamicFormProps } from "@/types/form";
import MyAlert from "@/components/Alert";
import useFetchMetadata from "@/utils/hooks/useFetchMetadata";
import Loader from "../common/Loader";

const DynamicForm: React.FC<DynamicFormProps> = React.memo(
  ({ elements, submitUrl, data, method, modelName }) => {
    const memoizedElements = useMemo(() => elements, [elements]);
    const [formData, setFormData] = useState<{ [key: string]: string }>({});
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState<{ [key: string]: string }>({});
    const [selectedTags, setSelectedTags] = useState<string[]>([]);
    const [alertOpen, setAlertOpen] = useState(false);
    const [alertType, setAlertType] = useState("");
    const [alertMessage, setAlertMessage] = useState("");

    const handleClose = () => {
      setAlertOpen(false);
    };

    useEffect(() => {
      data ? setFormData(data) : setFormData({});
    }, [data]);

    useEffect(() => {
      // Check if the 'enabled' property is truthy (1) or falsy (0)
      const initialValue = parseInt(data.enabled) === 1 ? "1" : "0";
      // Set the initial state of the checkbox
      setFormData((prevFormData) => ({
        ...prevFormData,
        enabled: initialValue,
      }));
    }, [data.enabled]);

    const handleChange = useCallback(
      (
        e: ChangeEvent<
          HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
        >,
        key: string
      ) => {
        const { value } = e.target;
        const element = memoizedElements.find((el) => el.key === key);

        if (element) {
          const { validation } = element;
          // Perform validation based on the validation rules
          if (validation) {
            let errorMessage = "";
            if (validation.required && String(value).trim() === "") {
              errorMessage = `${element.label} is required`;
            } else if (
              validation.minLength &&
              String(value).length < validation.minLength
            ) {
              errorMessage = `${element.label} must be at least ${validation.minLength} characters`;
            }
            setError((prevError) => ({ ...prevError, [key]: errorMessage }));
          }
        }

        // Update formData with the new value using a function to ensure it's synchronous
        setFormData((prevFormData) => ({ ...prevFormData, [key]: value }));
      },
      [memoizedElements]
    );

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

      const formErrors: { [key: string]: string } = {};
      let hasErr = false;
      elements.forEach((element) => {
        const { key, validation } = element;
        const value = formData[key];
        if (validation) {
          let errorMessage = "";
          if (value != undefined) {
            if (validation.required && String(value).trim() === "") {
              errorMessage = `${element.label} is required`;
            } else if (
              validation.minLength &&
              String(value).length < validation.minLength
            ) {
              errorMessage = `${element.label} must be at least ${validation.minLength} characters`;
            }
            if (errorMessage) {
              formErrors[key] = errorMessage;
              hasErr = true;
            }
          } else {
            if (validation.required) {
              errorMessage = `${element.label} is required`;
            } else if (validation.minLength) {
              errorMessage = `${element.label} must be at least ${validation.minLength} characters`;
            }
            if (errorMessage) {
              formErrors[key] = errorMessage;
              hasErr = true;
            }
          }
        }
      });

      if (hasErr) {
        setError(formErrors);
        setAlertType("error");
        setAlertMessage("Please fix the errors before submitting the form.");
        setAlertOpen(true);
        return;
      }

      // Proceed with form submission if there are no validation errors
      const token = localStorage.getItem("jobAdminJwtToken");
      setIsLoading(true);
      setError({}); // Clear previous errors

      try {
        const response = await fetch(submitUrl, {
          method: method,
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`,
          },
          body: JSON.stringify(formData),
        });

        if (!response.ok) {
          throw new Error("Failed to submit form");
        }

        setAlertType("success");
        setAlertMessage(
          `Successfully ${method == "POST" ? "added" : "updated"} ${modelName.slice(
            0,
            -1
          )}`
        );
        setAlertOpen(true);
        method == "POST" ? setFormData({}) : "";
        setIsLoading(true);
        await useFetchMetadata(token!);
        setIsLoading(false);
        
      } catch (error: any) {
        if (
          error.response &&
          error.response.data &&
          error.response.data.errors
        ) {
          // Server-side validation errors
          setError(error.response.data.errors);
        } else {
          setError({ general: "Failed to submit form" });
        }
        setAlertType("error");
        setAlertMessage(
          `Failed to ${method == "POST" ? "add" : "update"} ${modelName.slice(
            0,
            -1
          )}`
        );
        setAlertOpen(true);
      } finally {
        setIsLoading(false);
      }
    };

    return (
      <Fragment>
        {isLoading && <Loader/>}
        <div className="grid grid-cols-1 gap-9 sm:grid-cols-1">
          <div className="flex flex-col gap-9">
            <MyAlert
              message={alertMessage}
              type={alertType}
              open={alertOpen}
              onClose={handleClose}
            />
            <form onSubmit={handleSubmit}>
              <div className="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
                <div className="flex flex-col gap-3.5 p-6.5">
                  {elements.map((element, index) => {
                    const { type, label, key, validation } = element;
                    const errorMessage = error[key] || "";

                    return (
                      <div key={index}>
                        <label className="mb-3 block text-black dark:text-white">
                          {label}
                        </label>
                        {type === "text" ||
                        type === "password" ||
                        type === "number" ||
                        type === "email" ? (
                          <input
                            type={type}
                            value={formData[key] || ""}
                            onChange={(e) => handleChange(e, key)}
                            className={`w-full rounded-lg border-[1.5px] border-stroke bg-transparent py-3 px-5 font-medium outline-none transition focus:border-primary active:border-primary ${
                              errorMessage && "" // Add red border for error
                            }`}
                          />
                        ) : type === "multiselect" ? (
                          <Autocomplete
                            multiple
                            id={key}
                            value={selectedTags}
                            onChange={(event: any, newValue: any) => {
                              setSelectedTags(newValue);
                              setFormData({ ...formData, [key]: newValue });
                            }}
                            options={
                              element.options?.map(
                                (option) => option.display
                              ) || []
                            }
                            renderTags={(value: string[], getTagProps: any) =>
                              value.map((option: string, index: number) => (
                                <Chip
                                  key={index}
                                  label={option}
                                  {...getTagProps({ index })}
                                />
                              ))
                            }
                            renderInput={(params: any) => (
                              <TextField
                                {...params}
                                variant="outlined"
                                label={label}
                                placeholder={label}
                              />
                            )}
                          />
                        ) : type === "date" ? (
                          <input
                            type="date"
                            value={formData[key] || ""}
                            onChange={(e) => handleChange(e, key)}
                            className={`custom-input-date custom-input-date-1 w-full rounded border-[1.5px] border-stroke bg-transparent py-3 px-5 font-medium outline-none transition focus:border-primary active:border-primary ${
                              errorMessage && "border-red-500" // Add red border for error
                            }`}
                          />
                        ) : type === "file" ? (
                          <input
                            type="file"
                            value={formData[key] || ""}
                            onChange={(e) => handleChange(e, key)}
                            className={`custom-input-date custom-input-date-1 w-full rounded border-[1.5px] border-stroke bg-transparent py-3 px-5 font-medium outline-none transition focus:border-primary active:border-primary ${
                              errorMessage && "border-red-500" // Add red border for error
                            }`}
                          />
                        ) : type === "textarea" ? (
                          <textarea
                            rows={6}
                            value={formData[key] || ""}
                            onChange={(e) => handleChange(e, key)}
                            className={`w-full rounded-lg border-[1.5px] border-stroke bg-transparent py-3 px-5 font-medium outline-none transition focus:border-primary active:border-primary ${
                              errorMessage && "border-red-500" // Add red border for error
                            }`}
                          ></textarea>
                        ) : type === "checkbox" ? (
                          <div className="flex">
                            <div>
                              <input
                                className="mr-1"
                                type="radio"
                                id={`${key}-yes`}
                                name={key}
                                value="1"
                                checked={formData[key] === "1"}
                                onChange={(e) => handleChange(e, key)}
                              />
                              <label htmlFor={`${key}-yes`}>Yes</label>
                            </div>
                            <div className="mx-4">
                              <input
                                className="mr-1"
                                type="radio"
                                id={`${key}-no`}
                                name={key}
                                value="0"
                                checked={formData[key] === "0"}
                                onChange={(e) => handleChange(e, key)}
                              />
                              <label htmlFor={`${key}-no`}>No</label>
                            </div>
                          </div>
                        ) : type === "radio" ? (
                          <div className="flex">
                            {element.options?.map((option, idx) => {
                              const radioValue = formData[key] || "";
                              const isChecked = radioValue == option.value;

                              return (
                                <div
                                  key={idx}
                                  className="flex items-center pr-2"
                                >
                                  <input
                                    type="radio"
                                    id={`${key}-${idx}`}
                                    name={key}
                                    value={option.value}
                                    checked={isChecked}
                                    onChange={(e) => handleChange(e, key)}
                                    className="mr-2"
                                  />
                                  <label htmlFor={`${name}-${idx}`}>
                                    {option.display}
                                  </label>
                                </div>
                              );
                            })}
                          </div>
                        ) : type === "select" ? (
                          <div className="relative z-20 bg-transparent dark:bg-form-input">
                            <select
                              value={formData[key] || ""}
                              onChange={(e) => handleChange(e, key)}
                              className={`relative z-20 w-full appearance-none rounded border border-stroke bg-transparent py-3 px-5 outline-none transition focus:border-primary active:border-primary ${
                                errorMessage && "border-red-500" // Add red border for error
                              }`}
                            >
                              <option value="0">-- Select --</option>
                              {element.options?.map((option, idx) => (
                                <option key={idx} value={option.value}>
                                  {option.display}
                                </option>
                              ))}
                            </select>
                            <span className="absolute top-1/2 right-4 z-30 -translate-y-1/2">
                              <svg
                                className="fill-current"
                                width="24"
                                height="24"
                                viewBox="0 0 24 24"
                                fill="none"
                                xmlns="http://www.w3.org/2000/svg"
                              >
                                <g opacity="0.8">
                                  <path
                                    fillRule="evenodd"
                                    clipRule="evenodd"
                                    d="M5.29289 8.29289C5.68342 7.90237 6.31658 7.90237 6.70711 8.29289L12 13.5858L17.2929 8.29289C17.6834 7.90237 18.3166 7.90237 18.7071 8.29289C19.0976 8.68342 19.0976 9.31658 18.7071 9.70711L12.7071 15.7071C12.3166 16.0976 11.6834 16.0976 11.2929 15.7071L5.29289 9.70711C4.90237 9.31658 4.90237 8.68342 5.29289 8.29289Z"
                                    fill=""
                                  ></path>
                                </g>
                              </svg>
                            </span>
                          </div>
                        ) : null}
                        {errorMessage && (
                          <span
                            className="text-red-500"
                            style={{ color: "rgb(220 38 38)" }}
                          >
                            {errorMessage}
                          </span>
                        )}
                      </div>
                    );
                  })}

                  <button
                    type="submit"
                    className="inline-flex items-center w-30 justify-center my-3 gap-2.5 border border-primary py-3 px-30 text-center font-medium text-primary hover:bg-opacity-90 lg:px-8 xl:px-10"
                  >
                    {isLoading ? "Saving..." : "Submit"}
                  </button>
                </div>
              </div>
            </form>
          </div>
        </div>
      </Fragment>
    );
  }
);

export default DynamicForm;
