import { useState, useEffect, useCallback, useRef } from "react";
import { FormsSheetApi } from "../../../api/form_sheet";
import { useRealtime } from "../contexts/RealtimeContext";
import {
  addRootRow,
  deleteRow,
  insertCell,
  insertProjectRow,
  updateCells,
} from "../utils/cellUtils";
import { toast } from "react-toastify";
import { getParentId, isVspNewRow, isVspRow } from "../utils/rowUtils";
import { ProjectsApi } from "../../../api/projects";

const useRealtimeData = (formId, sheetName, direction, formType, year) => {
  const [data, setData] = useState([]);
  const [isConnected, setIsConnected] = useState(false);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [editingCells, setEditingCells] = useState({});
  const dataRef = useRef(data);

  const {
    isConnected: wsConnected,
    error: wsError,
    subscribeToCellUpdates,
    subscribeToRowAdds,
    subscribeToProgramAdds,
    subscribeToProjectAdds,
    subscribeToRowDeletes,
    subscribeToErrors,
    subscribeToCellEditStart,
    subscribeToCellEditEnd,
    setLockedCells,
  } = useRealtime();

  const formatedToSubRows = useCallback((depth, oldData) => {
    if (depth === 0) return oldData;

    const dataFiltered = oldData.filter((d) => d.depth < depth);

    for (let i = 0; i < dataFiltered.length; i++) {
      const curRow = dataFiltered[i];

      // Находим следующий элемент на том же или более высоком уровне
      let nextRow = null;
      for (let j = i + 1; j < dataFiltered.length; j++) {
        if (dataFiltered[j].depth <= curRow.depth) {
          nextRow = dataFiltered[j];
          break;
        }
      }

      // Находим всех потомков для текущей строки
      const subRows = oldData.filter((d) => {
        // Потомок должен иметь глубину больше чем у родителя
        if (d.depth <= curRow.depth) return false;

        // Потомок должен идти после родителя по sort_order
        if (d.sort_order <= curRow.sort_order) return false;

        // Если есть следующий элемент на том же уровне - потомок должен быть до него
        if (nextRow && d.sort_order >= nextRow.sort_order) return false;

        return true;
      });

      if (subRows.length > 0) {
        curRow.subRows = subRows;
      }
    }

    // Рекурсивно обрабатываем следующий уровень
    // Находим максимальную глубину в текущем dataFiltered
    const maxDepth = Math.max(...dataFiltered.map((d) => d.depth));
    if (maxDepth > 0) {
      return formatedToSubRows(maxDepth, dataFiltered);
    }

    return dataFiltered;
  }, []);

  // Загрузка начальных данных
  useEffect(() => {
    const loadInitialData = async () => {
      try {
        setIsLoading(true);
        let res;

        if (formType == "PROJECT") {
          res = await ProjectsApi.getTableData(formId, sheetName, year);
        } else if (direction !== null) {
          res = await FormsSheetApi.get(formId, sheetName, {
            params: { direction: direction },
          });
        } else {
          res = await FormsSheetApi.get(formId, sheetName);
        }
        const data = res.result;

        if (!data || data.length === 0) {
          setData([]);
          return;
        }

        const hierarchicalData = buildHierarchy(data);
        setData(hierarchicalData);
      } catch (err) {
        console.error("Failed to load initial data:", err);
        setError(err.message);
      } finally {
        setIsLoading(false);
      }
    };

    loadInitialData();
  }, [formId, sheetName]);

  const buildHierarchy = (items) => {
    const result = [];
    const stack = [];

    const getTypeLevel = (type) => {
      const levels = {
        ROOT: 0,
        GROUP: 1,
        ITEM: 2,
        SUB_ITEM: 3,
        INPUT: 4,
      };
      return levels[type] ?? 999;
    };

    for (const item of items) {
      const currentLevel = getTypeLevel(item.row_type);

      while (
        stack.length > 0 &&
        getTypeLevel(stack[stack.length - 1].row_type) >= currentLevel
      ) {
        stack.pop();
      }

      const parent = stack.length > 0 ? stack[stack.length - 1] : null;

      const newNode = { ...item, subRows: [] };

      if (parent) {
        if (!parent.subRows) {
          parent.subRows = [];
        }
        parent.subRows.push(newNode);
      } else {
        result.push(newNode);
      }

      // Добавляем текущий узел в стек, если он может иметь детей
      if (item.row_type !== "INPUT") {
        stack.push(newNode);
      }
    }

    return result;
  };

  useEffect(() => {
    setIsConnected(wsConnected);
  }, [wsConnected]);

  useEffect(() => {
    setError(wsError);
  }, [wsError]);

  useEffect(() => {
    dataRef.current = data;
  }, [data]);

  // Подписка на обновления WebSocket
  useEffect(() => {
    if (!wsConnected) return;

    const unsubscribeCellUpdates = subscribeToCellUpdates((updatedCells) => {
      if (!updatedCells || updatedCells.length === 0) return;

      setData((prevData) => {
        const newData = updateCells(prevData, updatedCells);
        return newData;
      });
    });

    const unsubscribeRowAdds = subscribeToRowAdds((data) => {
      const updates = data.result.data;
      const parent_id = getParentId(data.data);
      const newLineId = data.result.new_line_id;
      const [updatedCells, newRow] = updates.reduce(
        (res, row) => {
          if (row[3]?.line_id === newLineId || isVspNewRow(row)) {
            res[1] = row;
          } else {
            res[0].push(row);
          }
          return res;
        },
        [[], null],
      );
      if (newRow === null) {
        toast.error("Ошибка получения данных");
        return;
      }
      setData((prevData) => {
        let data = structuredClone(prevData);
        if (prevData[0]?.row_type !== "ROOT") {
          const newRowRoot = updates[0];
          data = addRootRow(data, newRowRoot);
        }
        const updatedData = updateCells(data, updatedCells);
        const newData = insertCell(updatedData, newRow, parent_id);
        return newData;
      });
    });

    const unsubscribeProjectAdds = subscribeToProjectAdds((data) => {
      const updates = data.result[1];
      const program_id = data.data.program_id;
      const [updatedCells, newRow] = updates.reduce(
        (res, row) => {
          if (row[0] === "ITEM") {
            res[1] = row;
          } else {
            res[0].push(row);
          }
          return res;
        },
        [[], null],
      );
      if (newRow === null) {
        toast.error("Ошибка получения данных");
        return;
      }
      setData((prevData) => {
        const updateData = updateCells(prevData, updatedCells);
        const newData = insertProjectRow(updateData, newRow, program_id);
        return newData;
      });
    });

    const unsubscribeProgramAdds = subscribeToProgramAdds((msg) => {
      let newRow = msg.result[1][0];
      setData((prevData) => {
        const hasRoot = prevData.length > 0 && prevData[0].row_type === "ROOT";
        if (hasRoot) {
          newRow = msg.result[1][1];
        }
        const updateData = structuredClone(prevData);
        const [row_type, depth, sort_order, dataRow] = newRow;
        const newRowObject = {
          row_type: row_type,
          depth: depth,
          sort_order: sort_order,
          subRows: [],
          data: dataRow,
        };
        if (hasRoot) {
          updateData[0].subRows.push(newRowObject);
          return updateData;
        }
        return [...updateData, newRowObject];
      });
    });

    const unsubscribeRowDeletes = subscribeToRowDeletes((data) => {
      const updatedCells = data.result;
      const lineIdForDelete = data.data.row_id;
      setData((prevData) => {
        const updateData = updateCells(prevData, updatedCells);
        const newData = deleteRow(updateData, lineIdForDelete);
        console.log(newData);
        return newData;
      });
    });

    // Обработчик начала редактирования ячейки
    const unsubscribeCellEditStart = subscribeToCellEditStart((data) => {
      const dataCell = data.data;
      dataCell.column = "data." + dataCell.column;
      if (data.is_self) {
        setEditingCells(dataCell);
        return;
      }

      const { line_id, column } = dataCell;
      const cellKey = `${line_id}_${column}`;

      // Сохраняем информацию о том, кто начал редактирование
      setLockedCells((prev) => [...prev, cellKey]);
    });

    // Обработчик завершения редактирования ячейки
    const unsubscribeCellEditEnd = subscribeToCellEditEnd((data) => {
      if (data.is_self) {
        setEditingCells(null);
        return;
      }
      const dataCell = data.data;
      dataCell.column = "data." + dataCell.column;
      const { line_id, column } = dataCell;
      const cellKey = `${line_id}_${column}`;
      setLockedCells((prev) => prev.filter((c) => c !== cellKey));
    });

    const unsubscribeErrors = subscribeToErrors((err) => {
      console.error("WebSocket error:", err);
      setError(err);
      setTimeout(() => setError(null), 5000);
    });

    return () => {
      unsubscribeCellUpdates();
      unsubscribeRowAdds();
      unsubscribeProgramAdds();
      unsubscribeProjectAdds();
      unsubscribeRowDeletes();
      unsubscribeErrors();
      unsubscribeCellEditStart();
      unsubscribeCellEditEnd();
    };
  }, [
    wsConnected,
    subscribeToCellUpdates,
    subscribeToRowAdds,
    subscribeToRowDeletes,
    subscribeToErrors,
    subscribeToCellEditStart,
    subscribeToCellEditEnd,
    subscribeToProgramAdds,
    subscribeToProjectAdds,
    formatedToSubRows,
  ]);

  const updateData = useCallback(
    (newData) => {
      if (Array.isArray(newData) && !newData[0]?.subRows) {
        const maxDepth = newData.reduce(
          (prev, current) => {
            return (prev.depth || 0) > (current.depth || 0) ? prev : current;
          },
          { depth: 0 },
        ).depth;

        const formattedData = formatedToSubRows(maxDepth, newData);
        setData(formattedData);
      } else {
        setData(newData);
      }
    },
    [formatedToSubRows],
  );

  return {
    data,
    setData,
    isConnected,
    isLoading,
    error,
    editingCells,
  };
};

export default useRealtimeData;
