import React, { useState, useRef } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
import {
  DragDropContext,
  Draggable,
  DraggableProvided,
  DraggableStateSnapshot,
  DropResult,
  Droppable,
} from "@hello-pangea/dnd";
import { useTheme } from "next-themes";
// hooks
import { useLabel, useUser } from "hooks/store";
import useDraggableInPortal from "hooks/use-draggable-portal";
// components
import {
  CreateUpdateLabelInline,
  DeleteLabelModal,
  ProjectSettingLabelGroup,
  ProjectSettingLabelItem,
} from "components/labels";
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
// ui
import { Button, Loader } from "@plane/ui";
// types
import { IIssueLabel } from "@plane/types";
// constants
import { PROJECT_SETTINGS_EMPTY_STATE_DETAILS } from "constants/empty-state";

const LABELS_ROOT = "labels.root";

export const ProjectSettingsLabelList: React.FC = observer(() => {
  // states
  const [showLabelForm, setLabelForm] = useState(false);
  const [isUpdating, setIsUpdating] = useState(false);
  const [selectDeleteLabel, setSelectDeleteLabel] = useState<IIssueLabel | null>(null);
  const [isDraggingGroup, setIsDraggingGroup] = useState(false);
  // refs
  const scrollToRef = useRef<HTMLFormElement>(null);
  // router
  const router = useRouter();
  const { workspaceSlug, projectId } = router.query;
  // theme
  const { resolvedTheme } = useTheme();
  // store hooks
  const { currentUser } = useUser();
  const { projectLabels, updateLabelPosition, projectLabelsTree } = useLabel();
  // portal
  const renderDraggable = useDraggableInPortal();

  const newLabel = () => {
    setIsUpdating(false);
    setLabelForm(true);
  };

  const emptyStateDetail = PROJECT_SETTINGS_EMPTY_STATE_DETAILS["labels"];
  const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light";
  const emptyStateImage = getEmptyStateImagePath("project-settings", "labels", isLightMode);

  const onDragEnd = (result: DropResult) => {
    const { combine, draggableId, destination, source } = result;

    // return if dropped outside the DragDropContext
    if (!combine && !destination) return;

    const childLabel = draggableId.split(".")[2];
    let parentLabel: string | undefined | null = destination?.droppableId?.split(".")[3];
    const index = destination?.index || 0;

    const prevParentLabel: string | undefined | null = source?.droppableId?.split(".")[3];
    const prevIndex = source?.index;

    if (combine && combine.draggableId) parentLabel = combine?.draggableId?.split(".")[2];

    if (destination?.droppableId === LABELS_ROOT) parentLabel = null;

    if (result.reason == "DROP" && childLabel != parentLabel) {
      updateLabelPosition(
        workspaceSlug?.toString()!,
        projectId?.toString()!,
        childLabel,
        parentLabel,
        index,
        prevParentLabel == parentLabel,
        prevIndex
      );
      return;
    }
  };

  return (
    <>
      <DeleteLabelModal
        isOpen={!!selectDeleteLabel}
        data={selectDeleteLabel ?? null}
        onClose={() => setSelectDeleteLabel(null)}
      />
      <div className="flex items-center justify-between border-b border-custom-border-100 py-3.5">
        <h3 className="text-xl font-medium">Labels</h3>
        <Button variant="primary" onClick={newLabel} size="sm">
          Add label
        </Button>
      </div>
      <div className="h-full w-full py-8">
        {showLabelForm && (
          <div className="w-full rounded border border-custom-border-200 px-3.5 py-2 my-2">
            <CreateUpdateLabelInline
              labelForm={showLabelForm}
              setLabelForm={setLabelForm}
              isUpdating={isUpdating}
              ref={scrollToRef}
              onClose={() => {
                setLabelForm(false);
                setIsUpdating(false);
              }}
            />
          </div>
        )}
        {projectLabels ? (
          projectLabels.length === 0 && !showLabelForm ? (
            <div className="flex items-center justify-center h-full w-full">
              <EmptyState
                title={emptyStateDetail.title}
                description={emptyStateDetail.description}
                image={emptyStateImage}
                size="lg"
              />
            </div>
          ) : (
            projectLabelsTree && (
              <DragDropContext
                onDragEnd={onDragEnd}
                autoScrollerOptions={{
                  startFromPercentage: 1,
                  disabled: false,
                  maxScrollAtPercentage: 0,
                  maxPixelScroll: 2,
                }}
              >
                <Droppable
                  droppableId={LABELS_ROOT}
                  isCombineEnabled={!isDraggingGroup}
                  ignoreContainerClipping
                  isDropDisabled={isUpdating}
                >
                  {(droppableProvided, droppableSnapshot) => (
                    <div className="mt-3" ref={droppableProvided.innerRef} {...droppableProvided.droppableProps}>
                      {projectLabelsTree.map((label, index) => {
                        if (label.children && label.children.length) {
                          return (
                            <Draggable
                              key={`label.draggable.${label.id}`}
                              draggableId={`label.draggable.${label.id}.group`}
                              index={index}
                              isDragDisabled={isUpdating}
                            >
                              {(provided: DraggableProvided, snapshot: DraggableStateSnapshot) => {
                                const isGroup = droppableSnapshot.draggingFromThisWith?.split(".")[3] === "group";
                                setIsDraggingGroup(isGroup);

                                return (
                                  <div ref={provided.innerRef} {...provided.draggableProps} className="mt-3">
                                    <ProjectSettingLabelGroup
                                      key={label.id}
                                      label={label}
                                      labelChildren={label.children || []}
                                      isDropDisabled={isGroup}
                                      dragHandleProps={provided.dragHandleProps!}
                                      handleLabelDelete={(label: IIssueLabel) => setSelectDeleteLabel(label)}
                                      draggableSnapshot={snapshot}
                                      isUpdating={isUpdating}
                                      setIsUpdating={setIsUpdating}
                                    />
                                  </div>
                                );
                              }}
                            </Draggable>
                          );
                        }
                        return (
                          <Draggable
                            key={`label.draggable.${label.id}`}
                            draggableId={`label.draggable.${label.id}`}
                            index={index}
                            isDragDisabled={isUpdating}
                          >
                            {renderDraggable((provided: DraggableProvided, snapshot: DraggableStateSnapshot) => (
                              <div ref={provided.innerRef} {...provided.draggableProps} className="mt-3">
                                <ProjectSettingLabelItem
                                  dragHandleProps={provided.dragHandleProps!}
                                  draggableSnapshot={snapshot}
                                  label={label}
                                  setIsUpdating={setIsUpdating}
                                  handleLabelDelete={(label) => setSelectDeleteLabel(label)}
                                  isChild={false}
                                />
                              </div>
                            ))}
                          </Draggable>
                        );
                      })}
                      {droppableProvided.placeholder}
                    </div>
                  )}
                </Droppable>
              </DragDropContext>
            )
          )
        ) : (
          !showLabelForm && (
            <Loader className="space-y-5">
              <Loader.Item height="42px" />
              <Loader.Item height="42px" />
              <Loader.Item height="42px" />
              <Loader.Item height="42px" />
            </Loader>
          )
        )}
      </div>
    </>
  );
});