import { Config } from '../conf/config';

export function openTaskSocket(taskId, onMessage) {
  try {
    const base = Config.API_URL || window.location.origin;
    const wsBase = base.replace(/^http/i, 'ws');
    const url = `${wsBase}/ws/tasks/${taskId}`;
    const ws = new WebSocket(url);
    ws.onmessage = (evt) => {
      try {
        onMessage && onMessage(JSON.parse(evt.data));
      } catch (error) {
        console.error('Ошибка подключения', error);
      }
    };
    return ws;
  } catch (error) {
    console.error(error);
    return null;
  }
}

export const connectToTable = (tableId, userId, options = {}) => {
  const { onError, onClose } = options;

  const baseURL = Config.API_URL.replace('http://', 'ws://').replace(
    'https://',
    'wss://',
  );
  const wsURL = `${baseURL}/api/v1/ws/${tableId}?user_id=${userId}`;

  const ws = new WebSocket(wsURL);

  const eventHandlers = {
    cell_edit_start: [],
    cell_edit_end: [],
    cell_updated: [],
    row_added: [],
    row_deleted: [],
    formula_updated: [],
    formula_manual: [],
    formula_recalculate: [],
  };

  ws.onerror = (error) => {
    console.error('Ошибка WebSocket:', error);
    if (onError) {
      onError(error);
    }
  };

  ws.onclose = (event) => {
    console.log(
      `Отключено от таблицы ${tableId}. Код: ${event.code}, причина: ${event.reason}`,
    );
    if (onClose) {
      onClose(event);
    }
  };

  ws.onmessage = (event) => {
    const raw = event.data;
    let message;

    try {
      message = JSON.parse(raw);
    } catch (_err) {
      try {
        let fixed = raw
          .replace(/'/g, '"')
          .replace(/\bNone\b/g, 'null')
          .replace(/\bTrue\b/g, 'true')
          .replace(/\bFalse\b/g, 'false');

        if (fixed.includes('BasicFormulaDependancy')) {
          fixed = fixed.replace(
            /"dependancies"\s*:\s*\[\[[\s\S]*?\]\]/,
            '"dependancies":[[]]',
          );
        }

        message = JSON.parse(fixed);
      } catch (error) {
        console.error('Ошибка парсинга сообщения WebSocket:', error, raw);
        return;
      }
    }

    const { event: eventName, data, error, result } = message;
    if (eventHandlers[eventName]) {
      const base = data || {};
      const payload = {
        ...base,
        ...(result !== undefined ? { result } : {}),
        ...(error !== undefined ? { error } : {}),
      };
      eventHandlers[eventName].forEach((handler) => handler(payload));
    }
  };

  return {
    ws,
    disconnect: () => {
      ws.close();
    },

    // Начало редактирования ячейки
    startEditCell: (cellKey) => {
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'cell_edit_start',
          data: {
            cell_key: cellKey,
            user_id: userId,
          },
        });
        ws.send(message);
      }
    },

    // Завершение редактирования ячейки
    endEditCell: (cellKey) => {
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'cell_edit_end',
          data: {
            cell_key: cellKey,
            user_id: userId,
          },
        });
        ws.send(message);
      }
    },

    // Подписка на событие начала редактирования ячейки другим пользователем
    onCellEditStart: (callback) => {
      eventHandlers.cell_edit_start.push(callback);
    },
    offCellEditStart: (callback) => {
      eventHandlers.cell_edit_start = eventHandlers.cell_edit_start.filter(
        (cb) => cb !== callback,
      );
    },

    // Подписка на событие завершения редактирования ячейки другим пользователем
    onCellEditEnd: (callback) => {
      eventHandlers.cell_edit_end.push(callback);
    },
    offCellEditEnd: (callback) => {
      eventHandlers.cell_edit_end = eventHandlers.cell_edit_end.filter(
        (cb) => cb !== callback,
      );
    },

    // Обновление значения ячейки (отправка нового значения другим пользователям)
    updateCellValue: (cellKey, newValue, cellType, cellColor) => {
      const [columnId, rowId] = cellKey.split('_');
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'cell_updated',
          data: {
            row: Number(rowId) + 1,
            header_id: Number(columnId),
            cell_key: cellKey,
            color: cellColor,
            value: newValue,
            type: cellType,
          },
        });
        ws.send(message);
      }
    },

    // Подписка на событие обновления значения ячейки другим пользователем
    onCellValueUpdated: (callback) => {
      eventHandlers.cell_updated.push(callback);
    },
    offCellValueUpdated: (callback) => {
      eventHandlers.cell_updated = eventHandlers.cell_updated.filter(
        (cb) => cb !== callback,
      );
    },

    // Добавление строки (отправка события другим пользователям)
    addRow: (rowIndex) => {
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'row_added',
          data: {
            row_index: rowIndex,
            user_id: userId,
          },
        });
        ws.send(message);
      }
    },

    // Подписка на событие добавления строки другим пользователем
    onRowAdded: (callback) => {
      eventHandlers.row_added.push(callback);
    },
    offRowAdded: (callback) => {
      eventHandlers.row_added = eventHandlers.row_added.filter(
        (cb) => cb !== callback,
      );
    },

    // Удаление строки (отправка события другим пользователям)
    deleteRow: (rowIndex) => {
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'row_deleted',
          data: {
            row_index: rowIndex,
            user_id: userId,
          },
        });
        ws.send(message);
      }
    },

    // Подписка на событие удаления строки другим пользователем
    onRowDeleted: (callback) => {
      eventHandlers.row_deleted.push(callback);
    },
    offRowDeleted: (callback) => {
      eventHandlers.row_deleted = eventHandlers.row_deleted.filter(
        (cb) => cb !== callback,
      );
    },

    // Обновление цвета ячейки
    updateCellColor: (cellKey, color, cellType, cellValue) => {
      const [columnId, rowId] = cellKey.split('_');
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'cell_updated',
          data: {
            row: Number(rowId) + 1,
            header_id: Number(columnId),
            cell_key: cellKey,
            color,
            type: cellType,
            value: cellValue,
          },
        });
        ws.send(message);
      }
    },

    // Добавление/обновление формулы (отправка события другим пользователям)
    updateFormula: (cellKey, type, value, formula) => {
      const [columnId, rowId] = cellKey.split('_');
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'formula_updated',
          data: {
            cell_key: cellKey,
            row: Number(rowId),
            header_id: Number(columnId),
            type,
            value,
            formula,
            user_id: userId,
          },
        });
        ws.send(message);
      }
    },

    // Подписка на событие добавления/обновления формулы другим пользователем
    onFormulaUpdated: (callback) => {
      eventHandlers.formula_updated.push(callback);
    },
    offFormulaUpdated: (callback) => {
      eventHandlers.formula_updated = eventHandlers.formula_updated.filter(
        (cb) => cb !== callback,
      );
    },

    // Ручное добавление формулы (отправка события другим пользователям)
    formulaManual: (formulaDatas) => {
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'formula_manual',
          data: {
            formula_datas: formulaDatas,
          },
        });
        ws.send(message);
      }
    },

    // Подписка на результат ручного добавления формулы
    onFormulaManual: (callback) => {
      eventHandlers.formula_manual.push(callback);
    },
    offFormulaManual: (callback) => {
      eventHandlers.formula_manual = eventHandlers.formula_manual.filter(
        (cb) => cb !== callback,
      );
    },

    // Пересчёт формул (отправка события другим пользователям / на бэкенд)
    formulaRecalculate: (formulaDatas, cells) => {
      if (ws.readyState === WebSocket.OPEN) {
        const message = JSON.stringify({
          event: 'formula_recalculate',
          data: {
            formula_datas: formulaDatas,
            cells,
          },
        });
        ws.send(message);
      }
    },

    // Подписка на результат пересчёта формул
    onFormulaRecalculate: (callback) => {
      eventHandlers.formula_recalculate.push(callback);
    },
    offFormulaRecalculate: (callback) => {
      eventHandlers.formula_recalculate =
        eventHandlers.formula_recalculate.filter((cb) => cb !== callback);
    },
  };
};
