import { FG_Plugin } from '@flaschengeist/types';
import { fixSession, useSessionStore, useUserStore } from '.';
import { AxiosResponse } from 'axios';
import { api } from '../internal';
import { defineStore } from 'pinia';
import { PersistentStorage } from '../utils/persistent';

function loadToken() {
  return PersistentStorage.get<string>('fg_token');
}

function clearToken() {
  PersistentStorage.remove('fg_token');
}

export function saveToken(token?: string) {
  if (token === undefined) return clearToken();
  PersistentStorage.set('fg_token', token).catch(() =>
    console.error('Could not save token to storage')
  );
}

export const useMainStore = defineStore({
  id: 'main',

  state: () => ({
    session: undefined as FG.Session | undefined,
    user: undefined as FG.User | undefined,
    notifications: [] as Array<FG_Plugin.Notification>,
    shortcuts: [] as Array<FG_Plugin.MenuLink>,
  }),

  getters: {
    loggedIn(): boolean {
      return this.session !== undefined;
    },
    currentUser(): FG.User {
      if (this.user === undefined) throw 'Not logged in, this should not be called';
      return this.user;
    },
    permissions(): string[] {
      return this.user?.permissions || [];
    },
  },

  actions: {
    /** Ininitalize store from saved session
     *  Updates session and loads current user
     */
    async init() {
      const sessionStore = useSessionStore();
      const userStore = useUserStore();

      try {
        const token = await loadToken();
        if (token !== null) {
          this.session = await sessionStore.getSession(token);
          if (this.session !== undefined) this.user = await userStore.getUser(this.session.userid);
        }
      } catch (error) {
        console.warn('Could not load token from storage', error);
      }
    },

    async login(userid: string, password: string) {
      try {
        const { data } = await api.post<FG.Session>('/auth', { userid, password });
        this.session = fixSession(data);
        return true;
      } catch ({ response }) {
        return (<AxiosResponse | undefined>response)?.status || false;
      }
    },

    async logout() {
      if (!this.session || !this.session.token) return false;

      try {
        const token = this.session.token;
        await api.delete(`/auth/${token}`);
      } catch (error) {
        return false;
      } finally {
        this.handleLoggedOut();
      }
      return true;
    },

    async requestReset(userid: string) {
      return await api
        .post('/auth/reset', { userid })
        .then(() => true)
        .catch(() => false);
    },

    async resetPassword(token: string, password: string) {
      return await api
        .post('/auth/reset', { token, password })
        .then(() => true)
        .catch(({ response }) =>
          response && 'status' in response ? (<AxiosResponse>response).status : false
        );
    },

    async loadNotifications(flaschengeist: FG_Plugin.Flaschengeist) {
      const { data } = await api.get<FG.Notification[]>('/notifications', {
        params:
          this.notifications.length > 0
            ? { from: this.notifications[this.notifications.length - 1].time }
            : {},
      });

      const notes = [] as FG_Plugin.Notification[];
      data.forEach((n) => {
        n.time = new Date(n.time);
        const plugin = flaschengeist?.plugins.filter((p) => p.id === n.plugin)[0];
        if (!plugin) console.debug('Could not find a parser for this notification', n);
        else notes.push(plugin.notification(n));
      });
      this.notifications.push(...notes);
      return notes;
    },

    async removeNotification(id: number) {
      const idx = this.notifications.findIndex((n) => n.id === id);
      if (idx >= 0)
        try {
          this.notifications.splice(idx, 1);
          await api.delete(`/notifications/${id}`);
        } catch (error) {
          if (this.notifications.length > idx)
            this.notifications.splice(idx, this.notifications.length - idx - 1);
        }
    },

    async getShortcuts() {
      const { data } = await api.get<Array<FG_Plugin.MenuLink>>(
        `users/${this.currentUser.userid}/shortcuts`
      );
      this.shortcuts = data;
    },

    async setShortcuts() {
      await api.put(`users/${this.currentUser.userid}/shortcuts`, this.shortcuts);
    },

    handleLoggedOut() {
      this.$reset();
      void clearToken();
    },
  },
});

export default () => useMainStore;