import { useState } from 'react';
import {
  DragDropContext,
  Draggable,
  type DragUpdate,
  // biome-ignore lint/style/noRestrictedImports: legacy drag-and-drop, migration to SortableList pending
} from 'react-beautiful-dnd';
import { useFieldArray, useFormContext } from 'react-hook-form';

import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';

import Button from '@material-hu/components/design-system/Buttons/Button';

import useDragEnd, { type DragProps } from 'src/hooks/useDragEnd';
import PlusIcon from 'src/icons/Plus';
import { SIDEBAR_WIDTH } from 'src/pages/dashboard/Learning/Courses/New/constants';
import {
  DroppableType,
  type Module,
  type Selected,
} from 'src/pages/dashboard/Learning/Courses/types';
import { move } from 'src/utils/arrayUtils';
import { useLokaliseTranslation } from 'src/utils/i18n';

import StrictModeDroppable from 'src/components/StrictModeDroppable';

import ModuleListItem from './ModuleListItem';
import TaskListItem from './TaskListItem';

export type ContentSidebarProps = {
  name: string;
  onSelect?: (newSelected: Selected) => void;
  selected: Selected;
  onExpanded?: (moduleExpanded: number) => void;
  expanded?: number[];
  onCreateModule?: () => void;
  onDeleteModule?: (module: number) => void;
  onCreateTask?: (module: number) => void;
  onDeleteTask?: (module: number, task: number) => void;
  showValidation?: boolean;
};

type DroppableInfo = {
  moduleIndex: number;
  type: DroppableType;
};

function parseDroppableId(droppableId: string): DroppableInfo | null {
  const modulePattern = /^modules$/;
  const taskPattern = /^tasks-in-module-(\d+)$/;

  let match = droppableId.match(modulePattern);
  if (match) {
    return { moduleIndex: -1, type: DroppableType.MODULE };
  }

  match = droppableId.match(taskPattern);
  if (match) {
    return { moduleIndex: parseInt(match[1], 10), type: DroppableType.TASK };
  }

  return null;
}

export const ContentSidebar = ({
  name = '',
  onSelect = () => null,
  selected,
  expanded = [],
  onCreateModule = () => null,
  onDeleteModule = () => null,
  onCreateTask = () => null,
  onDeleteTask = () => null,
  showValidation = false,
}: ContentSidebarProps) => {
  const { t } = useLokaliseTranslation('learning');
  const theme = useTheme();

  const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);

  const { watch, control } = useFormContext();
  const modules = watch(name);
  const moduleFields = useFieldArray({ name, control });

  const dragPolicy = ({ destination, source }: DragProps) => {
    if (source.droppableId !== destination?.droppableId) return;

    const moduleSource = parseDroppableId(source.droppableId);

    if (!moduleSource) return;

    const sourceIdx = source.index;
    const destinationIdx = destination.index;
    const newModules: Module[] = [...modules];

    if (moduleSource.type === DroppableType.MODULE) {
      const selectedModule = newModules[selected.module];
      move(newModules, sourceIdx, destinationIdx);
      const newSelectedModuleIdx = newModules.findIndex(
        module => module.id === selectedModule.id,
      );
      onSelect({ module: newSelectedModuleIdx, task: selected.task });
    } else if (moduleSource.type === DroppableType.TASK) {
      const selectedTask = modules[selected.module].tasks[selected.task];
      move(
        newModules[moduleSource.moduleIndex].tasks,
        sourceIdx,
        destinationIdx,
      );
      if (selected.module === moduleSource.moduleIndex && selected.task >= 0) {
        const newSelectedTaskIdx = newModules[
          moduleSource.moduleIndex
        ].tasks.findIndex(task => task.id === selectedTask.id);
        onSelect({ module: selected.module, task: newSelectedTaskIdx });
      }
    }
    moduleFields.replace(newModules);
  };

  const { handleDragEnd } = useDragEnd(dragPolicy);

  const handleSelect =
    (module: number = -1, task: number = -1) =>
    () =>
      onSelect({ module, task });

  const handleDeleteModule = (module: number) => () => onDeleteModule(module);

  const handleCreateModule = () => onCreateModule();

  const handleDeleteTask = (module: number, task: number) => () =>
    onDeleteTask(module, task);

  const handleCreateTask = (module: number) => () => onCreateTask(module);

  const handleDragUpdate = (update: DragUpdate) => {
    if (update.destination && update.type === DroppableType.TASK.toString()) {
      setHoveredIndex(update.source.index);
    } else {
      setHoveredIndex(null);
    }
  };

  return (
    <Stack
      sx={{
        gap: 1,
        justifyContent: 'space-between',
        width: SIDEBAR_WIDTH,
        minWidth: SIDEBAR_WIDTH,
        py: 3,
        backgroundColor: theme.palette.background.paper,
      }}
    >
      <Stack
        sx={{
          gap: 1,
          width: '100%',
          alignItems: 'center',
          justifyContent: 'flex-start',
          overflow: 'auto',
          pl: 3,
          pr: { xs: 2, lg: 3 },
        }}
      >
        {modules.length <= 0 && (
          <Typography
            variant="body2"
            sx={{ color: theme.palette.text.disabled }}
          >
            {t('course.lesson.no_modules')}
          </Typography>
        )}
        <DragDropContext
          onDragEnd={handleDragEnd}
          onDragUpdate={handleDragUpdate}
        >
          {/* Modules Droppable */}
          <StrictModeDroppable
            droppableId="modules"
            direction="vertical"
            type="MODULE"
          >
            {droppableProvided => (
              <Stack
                {...droppableProvided.droppableProps}
                ref={droppableProvided.innerRef}
                sx={{
                  width: 1,
                  gap: 1,
                }}
              >
                {modules.map((module: Module, moduleIndex: number) => (
                  <Draggable
                    key={module.id}
                    draggableId={`module-${module.id}`}
                    index={moduleIndex}
                  >
                    {provided => (
                      <Stack
                        ref={provided.innerRef}
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                      >
                        <ModuleListItem
                          index={moduleIndex}
                          module={module}
                          selectedModule={
                            moduleIndex === selected.module && selected.task < 0
                          }
                          selectedInnerTask={
                            moduleIndex === selected.module &&
                            selected.task >= 0
                          }
                          expanded={expanded.some(id => module.id === id)}
                          onSelect={handleSelect(moduleIndex)}
                          onDelete={handleDeleteModule(moduleIndex)}
                          onCreateTask={handleCreateTask(moduleIndex)}
                          showValidation={showValidation}
                        >
                          {module?.tasks?.length <= 0 && (
                            <Typography
                              variant="body2"
                              sx={{
                                color: theme.palette.text.disabled,
                                px: 3,
                                pt: 2,
                                pb: 2,
                                width: 1,
                              }}
                            >
                              {t('course.lesson.no_lessons')}
                            </Typography>
                          )}
                          {/* Tasks Droppable */}
                          <StrictModeDroppable
                            droppableId={`tasks-in-module-${moduleIndex}`}
                            direction="vertical"
                            type="TASK"
                          >
                            {taskProvided => (
                              <Stack
                                {...taskProvided.droppableProps}
                                ref={taskProvided.innerRef}
                                sx={{ width: 1 }}
                              >
                                {module?.tasks?.map((task, taskIndex) => (
                                  <Draggable
                                    key={task.id}
                                    draggableId={`task-${module.id}-${task.id}`}
                                    index={taskIndex}
                                  >
                                    {(draggableProvided, draggableSnapshot) => (
                                      <TaskListItem
                                        moduleIndex={moduleIndex}
                                        taskIndex={taskIndex}
                                        task={task}
                                        selected={
                                          moduleIndex === selected.module &&
                                          taskIndex === selected.task
                                        }
                                        onSelect={handleSelect(
                                          moduleIndex,
                                          taskIndex,
                                        )}
                                        onDelete={handleDeleteTask(
                                          moduleIndex,
                                          taskIndex,
                                        )}
                                        draggableProvided={draggableProvided}
                                        draggingOver={
                                          draggableSnapshot.draggingOver || ''
                                        }
                                        hoveredOver={
                                          draggableSnapshot.isDragging &&
                                          hoveredIndex === taskIndex
                                        }
                                      />
                                    )}
                                  </Draggable>
                                ))}
                                {taskProvided.placeholder}
                              </Stack>
                            )}
                          </StrictModeDroppable>
                        </ModuleListItem>
                      </Stack>
                    )}
                  </Draggable>
                ))}
                {droppableProvided.placeholder}
              </Stack>
            )}
          </StrictModeDroppable>
        </DragDropContext>
      </Stack>
      <Button
        startIcon={<PlusIcon fontSize="small" />}
        variant="contained"
        color="secondary"
        onClick={handleCreateModule}
        sx={{ ml: 3, mr: { xs: 2, lg: 3 } }}
      >
        {t('course.lesson.new_module')}
      </Button>
    </Stack>
  );
};

export default ContentSidebar;
