import { defineStore } from 'pinia';
import { api } from 'src/boot/axios';
import { AxiosError, AxiosResponse } from 'axios';
import { useMainStore } from 'src/store';

export const useUserStore = defineStore({
  id: 'users',

  state: () => ({
    roles: [] as FG.Role[],
    users: [] as FG.User[],
    permissions: [] as FG.Permission[],
    _dirty_users: 0,
    _dirty_roles: 0,
  }),

  getters: {
    isDirty() {
      return new Date().getTime() - this._dirty_users > 60000;
    },
  },

  actions: {
    async getUser(userid: string, force = true) {
      const idx = this.users.findIndex((user) => user.userid === userid);
      if (force || idx == -1 || this.isDirty) {
        try {
          const { data } = await api.get<FG.User>(`/users/${userid}`);
          if (data.birthday) data.birthday = new Date(data.birthday);
          if (idx === -1) this.users.push(data);
          else this.users[idx] = data;
          return data;
        } catch (error) {
          if (!error || !('response' in error) || (<AxiosError>error).response?.status !== 404)
            throw error;
        }
      } else {
        return this.users[idx];
      }
    },

    async getUsers(force = true) {
      if (force || this.isDirty) {
        const { data } = await api.get<FG.User[]>('/users');
        data.forEach((user) => {
          if (user.birthday) user.birthday = new Date(user.birthday);
        });
        this.users = data;
        this._dirty_users = new Date().getTime();
      } else {
        return this.users;
      }
    },

    async updateUser(user: FG.User) {
      await api.put(`/users/${user.userid}`, user);

      const mainStore = useMainStore();
      if (user.userid === mainStore.user?.userid) mainStore.user = user;
      this._dirty_users = 0;
    },

    async createUser(user: FG.User) {
      const { data } = await api.post<FG.User>('/users', user);
      this.users.push(data);
      return data;
    },

    async uploadAvatar(user: FG.User, file: string) {
      const formData = new FormData();
      formData.append('file', file);
      await api.post(`/users/${user.userid}/avatar`, formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      });
    },

    async getPermissions(force = false) {
      if (force || this.permissions.length === 0) {
        const { data } = await api.get<FG.Permission[]>('/roles/permissions');
        this.permissions = data;
      }
      return this.permissions;
    },

    async getRoles(force = false) {
      if (force || new Date().getTime() - this._dirty_roles > 60000) {
        const { data } = await api.get<FG.Role[]>('/roles');
        this.roles = data;
        this._dirty_roles = new Date().getTime();
      }
      return this.roles;
    },

    async updateRole(role: FG.Role) {
      await api.put(`/roles/${role.id}`, role);
      const idx = this.roles.findIndex((r) => r.id === role.id);
      if (idx != -1) this.roles[idx] = role;
      this._dirty_roles = 0;
    },

    async newRole(role: FG.Role) {
      const { data } = await api.post<FG.Role>('/roles', role);
      this.roles.push(data);
      this._dirty_roles = 0;
      return data;
    },

    async deleteRole(role: FG.Role | number) {
      await api.delete(`/roles/${typeof role === 'number' ? role : role.id}`);
      this.roles = this.roles.filter((r) => r.id !== (typeof role == 'number' ? role : role.id));
      this._dirty_roles = 0;
    },
  },
});

export const useSessionStore = defineStore({
  id: 'sessions',

  state: () => ({}),

  getters: {},

  actions: {
    async getSession(token: string) {
      return await api
        .get(`/auth/${token}`)
        .then(({ data }: AxiosResponse<FG.Session>) => data)
        .catch(() => null);
    },

    async getSessions() {
      try {
        const { data } = await api.get<FG.Session[]>('/auth');
        data.forEach((session) => {
          session.expires = new Date(session.expires);
        });

        const mainStore = useMainStore();
        const currentSession = data.find((session) => {
          return session.token === mainStore.session?.token;
        });
        if (currentSession) {
          mainStore.session = currentSession;
        }
        return data;
      } catch (error) {
        return [] as FG.Session[];
      }
    },

    async deleteSession(token: string) {
      const mainStore = useMainStore();
      if (token === mainStore.session?.token) return mainStore.logout();

      try {
        await api.delete(`/auth/${token}`);
        return true;
      } catch (error) {
        if (!error || !('response' in error) || (<AxiosError>error).response?.status != 401)
          throw error;
      }
      return false;
    },

    async updateSession(lifetime: number, token: string) {
      try {
        const { data } = await api.put<FG.Session>(`auth/${token}`, { value: lifetime });
        data.expires = new Date(data.expires);

        const mainStore = useMainStore();
        if (mainStore.session?.token == data.token) mainStore.session = data;

        return true;
      } catch (error) {
        return false;
      }
    },
  },
});