import { defineStore, acceptHMRUpdate } from 'pinia';
import { apollo } from 'src/boot/apollo';
import { debugLog, copy } from 'src/utils';
import {
  kanvaso,
  kanvasojKanvasoFull,
  kanvasoObjekto,
} from '../queries/queries.js';
import {
  kanvasoEdit,
  kanvasoObjektoLigilo,
  redaktuKanvasojKanvasoObjekto,
} from 'src/queries/mutations.js';
import {
  TreeNode,
  KanvasoEventoj as KanvasoEvento,
  Objekto,
} from 'src/types/stores/kanvaso';
import { KanvasoEventoj } from 'src/queries/subscriptions.js';

//@ts-nocheck
export const useKanvasoStore = defineStore('Kanvaso', {
  state: () => ({
    kanvaso: null,
    kanvasoObjektoMap: new Map(),
  }),
  getters: {
    getMap: (state) => {
      return Array.from(state.kanvasoObjektoMap.values()) || [];
    },
    getTree: (state) => {
      //преобразуем Map в массив из значений
      const kanvasoObjektoArrFromMap = Array.from(
        state.kanvasoObjektoMap.values(),
      );

      /**
       * Преобразует плоский массив в древовидную структуру.
       * @param flatArray Плоский массив объектов.
       * @returns Древовидная структура.
       */
      function convertToTree(flatArray: TreeNode[]): TreeNode[] {
        // Создаем копию исходного массива, чтобы не изменять его. Глубокая копия, так как в некоторых браузерах проблемы с добавлением children
        const nodes = JSON.parse(JSON.stringify(flatArray));
        // const nodes = copy(flatArray);

        // Создаем объект для быстрого доступа к каждому узлу по его UUID.
        const nodeMap: Record<string, TreeNode> = {};

        // Инициализируем nodeMap и добавляем каждому узлу пустой массив children и геттеры для получения свойств
        nodes.forEach((node) => {
          node.children = [];
          node.getChildrens = () => node.children || [];
          node.getName = () => node.nomo?.enhavo || 'Без имени';
          node.getPublished = () => node.publikigo || true;
          node.getDeleted = () => node.forigo || false;
          node.getDescription = () => node.priskribo?.enhavo || 'Нет описания';
          node.getId = () => node.objId || 0;
          node.getUuid = () => node.uuid || null;
          node.getType = () => node.tipo?.nomo?.enhavo || 'Без типа';
          node.getTypeId = () => node.tipo?.objId || 0;
          node.getParentUuid = () =>
            node.kanvasojKanvasoobjektoligiloLigilo.posedanto?.uuid || null;
          nodeMap[node.uuid] = node;
        });

        // Фильтруем узлы, чтобы сохранить только корневые узлы в результирующем массиве.
        const tree: TreeNode[] = nodes.filter((node) => {
          // Если у узла есть posedantoUuid, добавляем его в children его родителя.
          if (node.kanvasojKanvasoobjektoligiloLigilo) {
            const parent =
              nodeMap[node.kanvasojKanvasoobjektoligiloLigilo.posedanto.uuid];
            if (parent) {
              parent.children!.push(node);
            }

            // Узел не является корневым, поэтому исключаем его из результирующего массива.
            return false;
          }
          // Узел является корневым.
          return true;
        });
        return tree;
      }

      return convertToTree(kanvasoObjektoArrFromMap);
    },
    getKanvaso: (state) => {
      return state.kanvaso;
    },
    getKanvasoLength: (state) => {
      return state.kanvaso ? state.kanvaso.length : 0;
    },
  },
  actions: {
    async onGetKanvaso(payload) {
      debugLog('on get kanvaso');
      try {
        const response = await apollo.default.query({
          query: kanvaso,
          variables: payload,
          errorPolicy: 'all',
          fetchPolicy: 'network-only',
        });
        debugLog('get kanvaso response: ', response);
        this.kanvaso = response.data.kanvasojKanvaso.edges;
        return Promise.resolve(response);
      } catch (err) {
        return Promise.reject(err);
      }
    },
    async onGetKanvasoFull(payload) {
      debugLog('on get kanvaso full');
      try {
        const response = await apollo.default.query({
          query: kanvasojKanvasoFull,
          variables: payload,
          errorPolicy: 'all',
          fetchPolicy: 'network-only',
        });
        debugLog('get kanvaso full response: ', response);
        this.kanvaso = response.data.kanvasojKanvaso.edges;
        return Promise.resolve(response);
      } catch (err) {
        return Promise.reject(err);
      }
    },
    async onGetKanvasoObjekto(payload) {
      debugLog('on get kanvaso objekto');
      try {
        const response = await apollo.default.query({
          query: kanvasoObjekto,
          variables: payload,
          errorPolicy: 'all',
          fetchPolicy: 'network-only',
        });
        debugLog('get kanvaso objekto response: ', response);
        const kanvasoObjektoArr =
          response.data.kanvasojKanvasoObjekto?.edges || [];
        this.kanvasoObjektoMap.clear();
        kanvasoObjektoArr.forEach((item) => {
          if (item.node?.uuid) {
            this.kanvasoObjektoMap.set(item.node.uuid, item.node);
          }
        });
        return Promise.resolve(response);
      } catch (err) {
        return Promise.reject(err);
      }
    },

    async onEditKanvaso(payload) {
      debugLog('on edit kanvaso');
      try {
        const response = await apollo.default.mutate({
          mutation: kanvasoEdit,
          variables: payload,
          errorPolicy: 'all',
          fetchPolicy: 'network-only',
        });
        debugLog('edit kanvaso response: ', response);
        if (response.data?.redaktuKanvasojKanvaso?.status) {
          return Promise.resolve(true);
        } else {
          return Promise.reject(response);
        }
      } catch (err) {
        return Promise.reject(err);
      }
    },
    async onEditKanvasoObjekto(payload) {
      debugLog('on edit kanvaso objekto');
      try {
        const response = await apollo.default.mutate({
          mutation: redaktuKanvasojKanvasoObjekto,
          variables: payload,
          errorPolicy: 'all',
          fetchPolicy: 'network-only',
        });
        debugLog('edit kanvaso objekto response: ', response);
        if (response.data?.redaktuKanvasojKanvasoObjekto?.status) {
          return Promise.resolve(true);
        } else {
          return Promise.reject(response);
        }
      } catch (err) {
        return Promise.reject(err);
      }
    },
    async onEditKanvasoLigilo(payload) {
      debugLog('on edit kanvaso ligilo');
      try {
        const response = await apollo.default.mutate({
          mutation: kanvasoObjektoLigilo,
          variables: payload,
          errorPolicy: 'all',
          fetchPolicy: 'network-only',
        });
        debugLog('edit kanvaso ligilo response: ', response);
        // this.kanvaso = response.data.kanvasojKanvaso.edges;
        return Promise.resolve(response);
      } catch (err) {
        return Promise.reject(err);
      }
    },
    async onKanvasoSubscribe(payload) {
      debugLog('on kanvaso subscribe');
      try {
        const _this = this;
        const response = await apollo.default
          .subscribe({
            query: KanvasoEventoj,
            variables: payload,
          })
          .subscribe({
            next(data) {
              const evento: KanvasoEvento = data.data.KanvasoEventoj;
              if (evento) {
                const { objekto } = evento;
                if (objekto) {
                  if (objekto.forigo === true) {
                    _this.kanvasoObjektoMap.delete(objekto.uuid);
                  } else _this.kanvasoObjektoMap.set(objekto.uuid, objekto);
                }
              }
            },
          });
        return response;
      } catch {
        console.log('KanvasoEventoj subscribe error');
      }
    },
  },
});
//@ts-ignore
if (import.meta.hot) {
  //@ts-ignore
  import.meta.hot.accept(acceptHMRUpdate(useKanvasoStore, import.meta.hot));
}
