import {defineStore} from "pinia";
import type {Article} from "~/types/article";
import {NotificationMessage} from "~/types/notificationMessage";
import type {RuntimeConfig} from "nuxt/schema";
import {Origin} from "~/types/origin";
import type {Variant} from "~/types/variant";
import {Unit} from "~/types/unit";
import type {Label} from "~/types/label";
import type {Settings} from "~/types/settings";
import type {Supplier} from "~/types/supplier";

interface State {
  config: RuntimeConfig,

  // UI
  descriptionMaxChars: number,
  ingredientsMaxChars: number,

  // Notification
  notifications: NotificationMessage[],
  notificationQueue: NotificationMessage[],

  // Article
  article: Article | null,
  articleEdit: Article | null,

  labels: Array<Label>,

  settings: Settings | null,

  origins: Array<Origin>,
  units: Array<Unit>,

  suppliers: Array<Supplier>,
}

export const useLabelEditorStore = defineStore('label_editor_store', {
  state: (): State => ({
    config: useRuntimeConfig(),

    // UI
    descriptionMaxChars: 256,
    ingredientsMaxChars: 256,

    // Notification
    notifications: [],
    notificationQueue: [],

    // Article
    article: null,
    articleEdit: null,

    labels: [],

    settings: null,

    origins: [
        Origin.EU,
        Origin.NonEU,
        Origin.EUnonEU,
    ],

    units: [
        Unit.G,
        Unit.Kg,
        Unit.Ml,
        Unit.L,
        Unit.Stk,
    ],

    suppliers: [],
  }),
  actions: {
    // Notification
    addNotification(error: boolean, message: string) {
      const notification: NotificationMessage = new NotificationMessage(error, message);

      if (import.meta.client) {
        const localStoreNotification = localStorage.getItem("label_editor_notifications");

        if (localStoreNotification != null) {
          this.notifications = JSON.parse(localStoreNotification);
        }
      }

      this.notificationQueue.push(notification);
      this.notifications.push(notification);

      if (import.meta.client) {
        localStorage.setItem('label_editor_notifications', JSON.stringify(this.notifications));
      }

      if (notification.error) {
        setTimeout(() => this.removeNotification(notification.id), 5000);
      } else {
        setTimeout(() => this.removeNotification(notification.id), 2000);
      }
    },

    removeNotification(id: string) {
      const index = this.notificationQueue.findIndex(notification => notification.id == id);

      if (index > -1) {
        this.notificationQueue.splice(index, 1);
      }
    },

    getNotifications(): NotificationMessage[] {
      let oldNotifications: NotificationMessage[] = [];

      if (import.meta.client) {
        const localStoreNotification = localStorage.getItem("label_editor_notifications");

        if (localStoreNotification != null) {
          oldNotifications = JSON.parse(localStoreNotification);

          oldNotifications.reverse();
          return oldNotifications;
        }
      }

      return [];
    },

    clearNotifications() {
      this.notifications = [];

      if (import.meta.client) {
        localStorage.setItem('label_editor_notifications', JSON.stringify(this.notifications));
      }

      this.addNotification(false, "Benachrichtigungen gelöscht")
    },


    // Settings
    async loadSettings() {
      try {
        this.settings = await $fetch<Settings>(this.config.public.url + '/settings', {
          method: 'GET',
        });

        this.addNotification(false, 'Einstellungen geladen');
      } catch {
        this.addNotification(true, 'Fehler beim laden der Einstellungen');
      }
    },

    async updateSettings(settings: Settings) {
      try {
        this.settings = await $fetch<Settings>(this.config.public.url + '/settings', {
          method: 'POST',
          body: JSON.stringify(settings),
        });

        this.addNotification(false, 'Einstellungen aktualisiert.');
      } catch {
        this.addNotification(true, 'Fehler beim aktualisieren der Einstellungen.');
      }
    },


    // Labels:
    async loadLabels() {
      try {
        const labels: Array<Label> = await $fetch<Array<Label>>(this.config.public.url + '/label', {
          method: 'GET',
        });

        this.labels = labels;

        this.addNotification(false, 'Etiketten Typen geladen');
      } catch {
        this.addNotification(true, 'Fehler beim laden der Etiketten Typen');
      }
    },

    async createLabel(label: Label) {
      try {
        let createdLabel = await $fetch<Label>(this.config.public.url + '/label', {
          method: 'POST',
          body: JSON.stringify(label),
        });

        this.labels.push(createdLabel);

        this.addNotification(false, 'Etiketten Typ "' + createdLabel.name + '" erstellt');
      } catch {
        this.addNotification(true, 'Fehler beim erstellen des Etiketten Typ: ' + label.name);
      }
    },

    async updateLabel(label: Label) {
      let labelIndex = this.labels.findIndex(i => i.id === label.id);

      try {
        let updatedLabel = await $fetch<Label>(this.config.public.url + '/label/' + label.id, {
          method: 'POST',
          body: JSON.stringify(label),
        });

        this.labels[labelIndex] = updatedLabel;

        this.addNotification(false, 'Etiketten Typ aktualisiert.');
      } catch {
        this.addNotification(true, 'Fehler beim aktualisieren des Etiketten Typen.');
      }
    },

    async deleteLabel(labelID: number) {
      let labelIndex = this.labels.findIndex(i => i.id === labelID);

      try {
        await $fetch(this.config.public.url + '/label/' + labelID, {
          method: 'DELETE',
        });

        this.labels.splice(labelIndex, 1);

        this.addNotification(false, 'Etiketten Typ aktualisiert.');
      } catch {
        this.addNotification(true, 'Fehler beim aktualisieren des Etiketten Typen.');
      }
    },


    // Article
    async loadArticle(articleID: number) {
      await this.loadLabels();

      try {
        const article: Article = await $fetch<Article>(this.config.public.url + '/article/' + articleID, {
          method: 'GET',
        });

        this.article = JSON.parse(JSON.stringify(article));
        this.articleEdit = JSON.parse(JSON.stringify(article));

        this.addNotification(false, 'Artikel geladen: ' + this.article!.name);
      } catch {
        this.article = null;
        this.articleEdit = null;
        this.addNotification(true, 'Fehler beim laden des Artikel. ID:' + articleID);
      }
    },

    // TODO: Check if function from view can be replaced with store method
    async loadArticles(): Promise<Array<Article>> {
      console.log("Test");
      try {
        const articles: Array<Article> = await $fetch<Array<Article>>(this.config.public.url + '/articles', {
          method: 'GET',
        });

        this.addNotification(false, 'Artikelliste geladen');
        return articles;
      } catch {
        this.addNotification(true, 'Fehler beim laden der Artikeliste');
        return [];
      }
    },

    async createArticle(article: Article) {
      try {
        let createdArticle = await $fetch<Article>(this.config.public.url + '/article', {
          method: 'POST',
          body: JSON.stringify(article),
        });

        this.article = JSON.parse(JSON.stringify(createdArticle));
        this.articleEdit = JSON.parse(JSON.stringify(createdArticle));

        this.addNotification(false, 'Artikel "' + createdArticle.name + '" erstellt');
      } catch {
        this.addNotification(true, 'Fehler beim erstellen des Artikel: ' + article.name);
      }
    },

    async updateArticle(article: Article) {
      if (this.article != null) {
        try {
          if (article.ingredients != null) {
            article.ingredients = article.ingredients.replace(/style="[^"]*"/g, '');
            article.ingredients = article.ingredients.replace(/<\/?p[^>]*>/g, '');
          }

          let updatedArticle = await $fetch<Article>(this.config.public.url + '/article/' + article.id, {
            method: 'POST',
            body: JSON.stringify(article),
          });

          this.article.name = updatedArticle.name;
          this.article.bio = updatedArticle.bio;
          this.article.origin = updatedArticle.origin;
          this.article.description = updatedArticle.description;
          this.article.ingredients = updatedArticle.ingredients;
          this.article.mhd = updatedArticle.mhd;
          this.article.bio_origin = updatedArticle.bio_origin;
          this.article.bio_info = updatedArticle.bio_info;
          this.article.allergens_text = updatedArticle.allergens_text;
          this.article.topm_id = updatedArticle.topm_id;
          this.article.additional_name = updatedArticle.additional_name;

          this.addNotification(false, 'Artikel "' + article.name + '" aktualisiert');
        } catch {
          this.addNotification(true, 'Fehler beim aktualisieren des Artikel: ' + article.name);
        }
      } else {
        this.addNotification(true, 'Es ist kein Artikel ausgewählt');
      }
    },

    async deleteCurrentArticle() {
      if(this.article != null) {
        try {
          await $fetch(this.config.public.url + '/article/' + this.article.id, {
            method: 'DELETE',
          });

          this.article = null;

          this.addNotification(false, 'Variante gelöscht.');
        } catch {
          this.addNotification(true, 'Fehler beim löschen der Variante.');
        }
      } else {
        this.addNotification(true, 'Kann Variante nicht gelöscht werden. Es ist kein Artikel ausgewählt.');
      }
    },



    // Variant
    async addVariant(variant: Variant) {
      if(this.article != null) {
        try {
          let createdVariant = await $fetch<Variant>(this.config.public.url + '/article/' + this.article.id + '/variant', {
            method: 'POST',
            body: JSON.stringify(variant),
          });

          this.article.variants.push(createdVariant);

          this.addNotification(false, 'Variante erstellt.');
        } catch {
          this.addNotification(true, 'Fehler beim erstellen der Variante.');
        }
      } else {
        this.addNotification(true, 'Kann Variante nicht erstellen. Es ist kein Artikel ausgewählt.');
      }
    },

    async updateVariant(variant: Variant) {
      if(this.article != null) {
        let variantIndex = this.article.variants.findIndex(i => i.id === variant.id);

        try {
          let updatedVariant = await $fetch<Variant>(this.config.public.url + '/variant/' + variant.id, {
            method: 'POST',
            body: JSON.stringify(variant),
          });

          this.article.variants[variantIndex] = updatedVariant;

          this.addNotification(false, 'Variante aktualisiert.');
        } catch {
          this.addNotification(true, 'Fehler beim aktualisieren der Variante.');
        }
      } else {
        this.addNotification(true, 'Kann Variante nicht aktualisiert werden. Es ist kein Artikel ausgewählt.');
      }
    },

    async deleteVariant(variantID: number) {
      if(this.article != null) {
        let variantIndex = this.article.variants.findIndex(i => i.id === variantID);

        try {
          await $fetch(this.config.public.url + '/variant/' + variantID, {
            method: 'DELETE',
          });

          this.article.variants.splice(variantIndex, 1);

          this.addNotification(false, 'Variante gelöscht.');
        } catch {
          this.addNotification(true, 'Fehler beim löschen der Variante.');
        }
      } else {
        this.addNotification(true, 'Kann Variante nicht gelöscht werden. Es ist kein Artikel ausgewählt.');
      }
    },



    // Supplier:
    async loadSuppliers() {
      try {
        const suppliers: Array<Supplier> = await $fetch<Array<Supplier>>(this.config.public.url + '/supplier', {
          method: 'GET',
        });

        this.suppliers = suppliers;

        this.addNotification(false, 'Lieferanten geladen');
      } catch {
        this.addNotification(true, 'Fehler beim laden der Lieferanten');
      }
    },

    async createSupplier(supplier: Supplier) {
      try {
        let createdSupplier = await $fetch<Supplier>(this.config.public.url + '/supplier', {
          method: 'POST',
          body: JSON.stringify(supplier),
        });

        this.suppliers.push(createdSupplier);

        this.addNotification(false, 'Lieferant "' + createdSupplier.name + '" erstellt');
      } catch {
        this.addNotification(true, 'Fehler beim erstellen des Lieferant: ' + supplier.name);
      }
    },

    async updateSupplier(supplier: Supplier) {
      let labelIndex = this.labels.findIndex(i => i.id === supplier.id);

      try {
        let updatedSupplier = await $fetch<Supplier>(this.config.public.url + '/supplier/' + supplier.id, {
          method: 'POST',
          body: JSON.stringify(supplier),
        });

        this.labels[labelIndex] = updatedSupplier;

        this.addNotification(false, 'Lieferant aktualisiert.');
      } catch {
        this.addNotification(true, 'Fehler beim aktualisieren des Lieferanten.');
      }
    },

    async deleteSupplier(supplierID: number) {
      let supplierIndex = this.suppliers.findIndex(i => i.id === supplierID);

      try {
        await $fetch(this.config.public.url + '/supplier/' + supplierID, {
          method: 'DELETE',
        });

        this.suppliers.splice(supplierIndex, 1);

        this.addNotification(false, 'Lieferant gelöscht.');
      } catch {
        this.addNotification(true, 'Fehler beim löschen des Lieferanten.');
      }
    },
  },
});
