import { useMemo, useState, useEffect } from "react";
import { ColumnContainerCard } from "./columnContainerWrapper";
import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
import { SortableContext, arrayMove } from "@dnd-kit/sortable";
import { createPortal } from "react-dom";
import { TaskCard } from "./taskCard";
import { axiosInstance } from "src/api/AxiosConfig";

export function KanbanBoard() {
  const [columns, setColumns] = useState([]);
  const columnsId = useMemo(() => columns.map((col) => col.id), [columns]);
  const [boardId, setBoardData] = useState();

  const [tasks, setTasks] = useState([]);

  const [activeColumn, setActiveColumn] = useState(null);

  const [activeTask, setActiveTask] = useState(null);

  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 10,
      },
    })
  );

  useEffect(() => {
    const fetchData = async () => {
      try {
        const tasksResponse = await axiosInstance.get("/todo");

        // Transform
        const transformedTasks = tasksResponse.data.map((task) => ({
          id: task.id,
          columnId: task.list_board,
          content: task.title,
          difficulty: task.difficulty,
          notes: task.notes,
          importance: task.importance,
          challenge: task.challenge,
          fromSystem: task.fromSystem,
          creation_date: task.creation_date,
          last_update: task.last_update,
          is_active: task.is_active,
          is_full_day_event: task.is_full_day_event,
          start_event: task.start_event,
          end_event: task.end_event,
          google_calendar_id: task.google_calendar_id,
          completed: task.completed,
          completion_date: task.completion_date,
          priority: task.priority,
          user: task.user,
          list_board: task.list_board,
          tags: task.tags,
        }));
        setTasks(transformedTasks);

        const columnsResponse = await axiosInstance.get("/lists");

        // Transform
        const transformedColumns = columnsResponse.data.map((column) => ({
          id: column.id,
          title: column.name,
        }));
        setColumns(transformedColumns);
      } catch (error) {
        console.error("Error fetching data from API:", error);
      }
    };
    fetchData();
  }, []);

  useEffect(() => {
    const fetchBoardData = async () => {
      try {
        const response = await axiosInstance.get("boards/");
        if (response.data && response.data.length > 0) {
          setBoardData(response.data[0]);
        }
      } catch (error) {
        console.error("Error fetching board data:", error);
      }
    };
    fetchBoardData();
  }, []);

  return (
    <div
      className="
      m-auto
      flex
      w-full
      items-center
      overflow-x-auto
      overflow-y-hidden
  ">
      <DndContext sensors={sensors} onDragStart={onDragStart} onDragEnd={onDragEnd} onDragOver={onDragOver}>
        <div className="ml-2 flex gap-4">
          <div className="flex gap-4">
            <SortableContext items={columnsId}>
              {columns.map((col) => (
                <ColumnContainerCard
                  key={col.id}
                  column={col}
                  deleteColumn={deleteColumn}
                  updateColumn={updateColumn}
                  createTask={createTask}
                  deleteTask={deleteTask}
                  updateTask={updateTask}
                  tasks={tasks.filter((task) => task.columnId === col.id)}
                />
              ))}
            </SortableContext>
          </div>
        </div>

        {createPortal(
          <DragOverlay className="bg-white" dropAnimation={null} zIndex={20}>
            {activeColumn && (
              <ColumnContainerCard
                column={activeColumn}
                deleteColumn={deleteColumn}
                updateColumn={updateColumn}
                createTask={createTask}
                deleteTask={deleteTask}
                updateTask={updateTask}
                tasks={tasks.filter((task) => task.columnId === activeColumn.id)}
              />
            )}
            {activeTask && <TaskCard task={activeTask} deleteTask={deleteTask} updateTask={updateTask} />}
          </DragOverlay>,
          document.body
        )}
      </DndContext>
    </div>
  );

  function createTask(columnId, setTasks) {
    const newTaskData = {
      title: `Task ${tasks.length + 1}`,
      importance: 1,
      difficulty: 1,
      challenge: false,
      fromSystem: false,
      is_active: false,
      is_full_day_event: false,
      completed: false,
      priority: 1,
      list_board: columnId,
    };

    axiosInstance
      .post("todo/", newTaskData)
      .then((response) => {
        const newTask = {
          id: response.data.id,
          columnId,
          content: response.data.title,
        };
      })
      .catch((error) => {
        console.error("Error creating task:", error);
      });
    setTasks((tasks) => [...tasks, newTask]);
  }

  function deleteTask(id) {
    const newTasks = tasks.filter((task) => task.id !== id);
    axiosInstance
      .delete(`todo/${id}/`)
      .then((response) => {
        setTasks(newTasks);
      })
      .catch((error) => {
        console.error("Error deleting Task:", error);
      });
    setTasks(newTasks);
  }

  function updateTask(id, content) {
    const newTasks = tasks.map((task) => {
      if (task.id !== id) return task;
      return { ...task, content };
    });
    if (content === "") return deleteTask(id);
    setTasks(newTasks);
  }

  function createNewColumn() {
    axiosInstance
      .post("lists/", { name: `Column ${columns.length + 1}`, position: 1, board: boardId.id })
      .then((response) => {
        const newColumn = {
          id: response.data.id,
          title: response.data.name,
        };

        setColumns((prevColumns) => [...prevColumns, newColumn]);
      })
      .catch((error) => {
        console.error("Error creating ListBoard:", error);
      });
  }

  function deleteColumn(id) {
    axiosInstance
      .delete(`lists/${id}/`)
      .then((response) => {
        setColumns((prevColumns) => prevColumns.filter((col) => col.id !== id));
      })
      .catch((error) => {
        console.error("Error deleting ListBoard:", error);
      });

    const tasksToDelete = tasks.filter((t) => t.columnId === id);

    tasksToDelete.forEach((task) => {
      axiosInstance
        .delete(`todo/${task.id}/`)
        .then((response) => {
          setTasks((prevTasks) => prevTasks.filter((t) => t.id !== task.id));
        })
        .catch((error) => {
          console.error("Error deleting Task:", error);
        });
    });
  }

  function updateColumn(id, title) {
    // Update the column
    axiosInstance
      .patch(`lists/${id}/`, { name: title }) // Adjust the payload based on your API requirements
      .then((response) => {
        setColumns((prevColumns) => prevColumns.map((col) => (col.id === id ? { ...col, title } : col)));
      })
      .catch((error) => {
        console.error("Error updating ListBoard:", error);
      });
  }

  function onDragStart(event) {
    if (event.active.data.current?.type === "Column") {
      setActiveColumn(event.active.data.current.column);
      return;
    }

    if (event.active.data.current?.type === "Task") {
      setActiveTask(event.active.data.current.task);
      return;
    }
  }

  function onDragEnd(event) {
    setActiveColumn(null);
    setActiveTask(null);

    const { active, over } = event;
    if (!over) return;

    const activeId = active.id;
    const overId = over.id;

    const isActiveAColumn = active.data.current?.type === "Column";
    const isActiveATask = active.data.current?.type === "Task";
    const isOverAColumn = over.data.current?.type === "Column";
    const isOverATask = over.data.current?.type === "Task";

    // Reorder columns if the dragged item is a column
    if (isActiveAColumn && isOverAColumn) {
      setColumns((columns) => {
        const activeColumnIndex = columns.findIndex((col) => col.id === activeId);
        const overColumnIndex = columns.findIndex((col) => col.id === overId);

        const reorderedColumns = arrayMove(columns, activeColumnIndex, overColumnIndex);

        return reorderedColumns;
      });
    }

    // Reorder tasks within the same column
    if (isActiveATask && isOverATask) {
      setTasks((tasks) => {
        const activeIndex = tasks.findIndex((t) => t.id === activeId);
        const overIndex = tasks.findIndex((t) => t.id === overId);

        const reorderedTasks = arrayMove(tasks, activeIndex, overIndex);

        return reorderedTasks;
      });
    }

    // Move tasks between columns and update columnId
    if (isActiveATask && isOverAColumn) {
      setTasks((tasks) => {
        const activeIndex = tasks.findIndex((t) => t.id === activeId);

        tasks[activeIndex].columnId = overId;

        axiosInstance
          .put(`todo/change_task_list_board/`, { todo_id: activeId, new_list_board_id: overId, new_index: 0 })
          .then((response) => {})
          .catch((error) => {
            console.error("Error updating task columnId:", error);
          });

        return arrayMove(tasks, activeIndex, activeIndex);
      });
    }
  }

  function onDragOver(event) {
    const { active, over } = event;
    if (!over) return;

    const activeId = active.id;
    const overId = over.id;

    if (activeId === overId) return;

    const isActiveATask = active.data.current?.type === "Task";
    const isOverATask = over.data.current?.type === "Task";

    if (!isActiveATask) return;

    if (isActiveATask && isOverATask) {
      setTasks((tasks) => {
        const activeIndex = tasks.findIndex((t) => t.id === activeId);
        const overIndex = tasks.findIndex((t) => t.id === overId);

        if (tasks[activeIndex].columnId !== tasks[overIndex].columnId) {
          tasks[activeIndex].columnId = tasks[overIndex].columnId;
          return arrayMove(tasks, activeIndex, overIndex - 1);
        }

        return arrayMove(tasks, activeIndex, overIndex);
      });
    }

    const isOverAColumn = over.data.current?.type === "Column";

    if (isActiveATask && isOverAColumn) {
      setTasks((tasks) => {
        const activeIndex = tasks.findIndex((t) => t.id === activeId);

        tasks[activeIndex].columnId = overId;
        return arrayMove(tasks, activeIndex, activeIndex);
      });
    }
  }
}
