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,
} from 'src/types/stores/kanvaso';
import { KanvasoEventoj } from 'src/queries/subscriptions.js';

class ObjectWrapper {
  private _wrappingObject: any;
  constructor(wrappingObject: TreeNode) {
    this._wrappingObject = wrappingObject;
    this._wrappingObject.childrens = [];
  }

  get name(): string {
    return this._wrappingObject.nomo?.enhavo || 'Без имени';
  }
  get isPublished(): boolean {
    return this._wrappingObject.publikigo || true;
  }
  get isDeleted(): boolean {
    return this._wrappingObject.forigo || false;
  }
  get description(): string {
    return this._wrappingObject.priskribo?.enhavo || 'Нет описания';
  }
  get id(): number {
    return this._wrappingObject.objId || 0;
  }
  get uuid(): string {
    return this._wrappingObject.uuid || null;
  }
  get type(): string {
    return this._wrappingObject.tipo?.nomo?.enhavo || 'Без типа';
  }
  get typeId(): number {
    return this._wrappingObject.tipo?.objId || 0;
  }
  get parentUuid(): string {
    return (
      this._wrappingObject.kanvasojKanvasoobjektoligiloLigilo?.posedanto
        ?.uuid || ''
    );
  }
  get childrens(): ObjectWrapper[] {
    return this._wrappingObject.childrens || [];
  }
  setChildrens(childrens: ObjectWrapper | ObjectWrapper[]) {
    this._wrappingObject.childrens.push(childrens);
  }
  removeChildrens() {
    this._wrappingObject.childrens.length = 0;
  }
  get hasParent() {
    return !!this._wrappingObject.kanvasojKanvasoobjektoligiloLigilo;
  }
}

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(nodes: ObjectWrapper[]): ObjectWrapper[] {
        // Создаем объект для быстрого доступа к каждому узлу по его UUID.
        const nodeMap: Record<string, ObjectWrapper> = {};
        // Инициализируем nodeMap и добавляем каждому узлу пустой массив children и геттеры для получения свойств
        nodes.forEach((node) => {
          nodeMap[node.uuid] = node;
          node.removeChildrens();
        });
        // Фильтруем узлы, чтобы сохранить только корневые узлы в результирующем массиве.
        const tree: ObjectWrapper[] = nodes.filter((node) => {
          // Если у узла есть uuid родителя, добавляем его в children его родителя.
          if (node.hasParent) {
            const parent = nodeMap[node.parentUuid];
            if (parent) {
              parent.setChildrens(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) {
            const obj = new ObjectWrapper(
              JSON.parse(JSON.stringify(item.node)),
            );
            this.kanvasoObjektoMap.set(obj.uuid, obj);
          }
        });
        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 {
                    const obj = new ObjectWrapper(
                      JSON.parse(JSON.stringify(objekto)),
                    );
                    _this.kanvasoObjektoMap.set(obj.uuid, obj);
                  }
                }
              }
            },
          });
        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));
}
