"use client";

import React, { useCallback, useEffect, useMemo, useState } from "react";

import styles from "@/components/administrator/CategoryEditor/categoryeditor.module.css";
import Input from "@/components/administrator/form/Input/input";
import TextArea from "@/components/administrator/form/TextArea/text.area";
import {
  modifyByKeys,
  slugify,
  unmergingCategory,
} from "@/app/library/library";
import Button from "@/components/ui/Button/button";
import Uploadbox from "../form/UploadBox/upload.box";
import Dropdown from "../form/Dropdown/dropdown";
import { useTerm } from "@/hooks/useTerm";
import Loader from "@/components/web/Loader/loader";
import { useRouter } from "next/navigation";

/**
 *
 * @type {React.FC <{
 *    data: object;
 * }>}
 * @returns
 */
const CategoryEditor = (props) => {
  const router = useRouter();
  const [data, setData] = useState(props.data);
  const [slugLock, setSlugLock] = useState(true);
  const [media, setMedia] = useState(props.data?.media);
  // onsave data loading
  const [loading, setLoading] = useState({
    save: false,
    delete: false,
  });
  const { mergeCategoryPost, updateCategory, deleteCategory } = useTerm();

  const isChange = useMemo(() => {
    return JSON.stringify(data) !== JSON.stringify(props.data);
  }, [props.data, data]);

  const categoryUnmerge = useMemo(() => {
    const cat = unmergingCategory(props.categories);
    const filtered = cat.filter((category) => category._id !== data._id);
    return filtered;
  }, [props.categories, data]);

  // filter parent if exist
  const categoryMerge = useMemo(() => {
    return mergeCategoryPost(categoryUnmerge);
  }, [categoryUnmerge, mergeCategoryPost]);

  const hierarchy = useMemo(() => {
    if (data?.parents && data?.parents?.length > 0) {
      const dataParents = Array.from(data.parents);
      return dataParents
        .reverse()
        .map((id) => categoryUnmerge.find((cat) => cat._id === id));
    }

    return [];
  }, [categoryUnmerge, data]);

  const currentParent = useMemo(() => {
    return data?.parents && data.parents.length > 0
      ? categoryUnmerge.find((cat) => cat._id === data.parents?.[0])
      : null;
  }, [categoryUnmerge, data]);

  const setImage = useCallback((file, uid) => {
    const id = file?._id || file?.files?.[0]?._id;
    setMedia(file);
    setTimeout(() => {
      setData((prev) => ({ ...prev, image: id }));
    });
  }, []);

  const removeImage = useCallback(() => {
    setMedia(null);
    setTimeout(() => {
      setData((prev) => ({ ...prev, image: null }));
    });
  }, []);

  const handleSetParent = useCallback((item, e) => {
    const newparents = [item._id, ...(item?.parents ? item.parents : [])];
    setData((prev) => ({ ...prev, parents: newparents }));
  }, []);

  const handleSave = useCallback(() => {
    setLoading((prev) => ({ ...prev, save: true }));
    updateCategory(data, (result) => {
      setLoading((prev) => ({ ...prev, save: false }));
      if (result.media) setMedia(result.media);
      delete result.media;

      setData(
        modifyByKeys(result, ["parents"], (parents) =>
          parents.map((parent) => parent._id)
        )
      );
    });
  }, [data, updateCategory]);

  const handleDelete = useCallback(() => {
    setLoading((prev) => ({ ...prev, delete: true }));
    deleteCategory(
      data._id,
      (result) => {
        setLoading((prev) => ({ ...prev, delete: false }));
        router.push("/dashboard/categories");
      },
      () => {
        setLoading((prev) => ({ ...prev, delete: false }));
      }
    );
  }, [data, deleteCategory, router]);

  useEffect(() => {
    const handleKeyDown = (e) => {
      const keyDown = [
        {
          on: e.key === "s" && e.ctrlKey,
          call: async () => {
            e.preventDefault();
            handleSave();
          },
        },
        {
          on: e.key === "Delete" && e.shiftKey,
          call: async () => {
            e.preventDefault();
            handleDelete();
          },
        },
      ];

      return keyDown.find((key) => key.on)?.call();
    };

    document.addEventListener("keydown", handleKeyDown);
    return () => {
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [handleSave, handleDelete]);

  return (
    <>
      <h1 className={styles.post_title}>{data.name || "Unnamed Category"}</h1>
      <div className={styles.container}>
        <div className={styles.editor_header}>
          <div className={styles.editor_status}>
            <p>
              ID : <span>{props.data._id}</span>
            </p>
            <p>
              Term : <span>Categories</span>
            </p>
            <p>
              Status : <span>{isChange ? "Changed" : "Unchanged"}</span>
            </p>
          </div>
          <div className={styles.editor_status}>
            <Button
              className={styles.button}
              disabled={!isChange || loading.save}
              onClick={() => handleSave()}>
              {loading.save && (
                <>
                  <Loader
                    size={20}
                    color={"#fff"}
                  />
                </>
              )}
              Save
            </Button>
            <Button
              className={styles.button}
              disabled={loading.delete}
              onClick={() => handleDelete()}>
              {loading.delete && (
                <>
                  <Loader
                    size={20}
                    color={"#fff"}
                  />
                </>
              )}
              Delete
            </Button>
          </div>
        </div>
        <div className={styles.editor_content}>
          <div className={`${styles.editor_body}`}>
            <div className={styles.editor_post}>
              <Input
                label="Name"
                className={styles.input}
                value={data.name || ""}
                labelclassname={styles.label}
                onChange={(e) =>
                  setData((prev) => ({
                    ...prev,
                    name: e.target.value,
                    slug: slugify(e.target.value),
                  }))
                }
              />
              <TextArea
                label="Description"
                className={styles.input}
                labelclassname={styles.label}
                defaultValue={data.description || ""}
                onChange={(e) =>
                  setData((prev) => ({ ...prev, description: e.target.value }))
                }
              />
              <Dropdown
                label="Parent"
                labelclassname={styles.label}
                className={styles.input}
                data={categoryMerge}
                display="name"
                value={currentParent}
                format={{
                  label: "Set to Top Level",
                  action: (item, setItem) => {
                    setItem("");
                    setData((prev) => ({ ...prev, parents: [] }));
                  },
                  changeValue: true,
                }}
                onClick={handleSetParent}
              />
              {hierarchy.length > 0 && (
                <div className={styles.hierarchy_container}>
                  <div className={styles.hierarchy_title}>hierarchy</div>
                  {hierarchy.map((item, index) => (
                    <div
                      className={styles.hierarchy_item}
                      key={index}>
                      <span className={styles.hierarchy_name}>{item.name}</span>
                      <span className={styles.hierarchy_slug}>{item.slug}</span>
                      {item?.description && (
                        <span className={styles.hierarchy_description}>
                          {item.description}
                        </span>
                      )}
                    </div>
                  ))}
                </div>
              )}
            </div>
          </div>
          <div className={`${styles.editor_body} ${styles.aside}`}>
            <Uploadbox
              mode="vertical"
              label="Category Image"
              uid="category-image"
              currentImage={media}
              callback={setImage}
              onCancel={removeImage}
            />
            <Input
              label="Slug"
              className={styles.input}
              value={data.slug || ""}
              labelclassname={styles.label}
              disabled={slugLock}
              format={{
                label: slugLock ? "Unlock" : "Lock",
                action: (element) => {
                  setTimeout(() => element.focus(), 200);
                  setSlugLock((prev) => !prev);
                },
                changeInput: false,
              }}
              onChange={(e) =>
                setData((prev) => ({ ...prev, slug: e.target.value }))
              }
            />
          </div>
        </div>
      </div>
    </>
  );
};

export default CategoryEditor;
