import { defineStore } from 'pinia';
import { ID, account, functions, teams } from 'boot/appwrite';
import { ExecutionMethod, OAuthProvider, type Models } from 'appwrite';
import { computed, ref } from 'vue';
import { useBoatStore } from './boat';
import { useReservationStore } from './reservation';

export const useAuthStore = defineStore('auth', () => {
  const currentUser = ref<Models.User<Models.Preferences> | null>(null);
  const currentUserTeams = ref<Models.TeamList<Models.Preferences> | null>(
    null
  );
  const userNames = ref<Record<string, string>>({});

  async function init() {
    try {
      currentUser.value = await account.get();
      currentUserTeams.value = await teams.list();
      await useBoatStore().fetchBoats();
      await useReservationStore().fetchUserReservations();
    } catch {
      currentUser.value = null;
      currentUserTeams.value = null;
    }
  }

  const currentUserTeamNames = computed(() =>
    currentUserTeams.value
      ? currentUserTeams.value.teams.map((team) => team.name)
      : []
  );

  const hasRequiredRole = (requiredRoles: string[]): boolean => {
    return requiredRoles.some((role) =>
      currentUserTeamNames.value.includes(role)
    );
  };

  async function register(email: string, password: string) {
    await account.create(ID.unique(), email, password);
    return await login(email, password);
  }
  async function login(email: string, password: string) {
    await account.createEmailPasswordSession(email, password);
    await init();
  }

  async function createTokenSession(email: string) {
    return await account.createEmailToken(ID.unique(), email);
  }

  async function googleLogin() {
    await account.createOAuth2Session(
      OAuthProvider.Google,
      'https://oys.undock.ca',
      'https://oys.undock.ca/login'
    );
    await init();
  }

  async function discordLogin() {
    await account.createOAuth2Session(
      OAuthProvider.Discord,
      'https://oys.undock.ca',
      'https://oys.undock.ca/login'
    );
    await init();
  }

  async function tokenLogin(userId: string, token: string) {
    await account.createSession(userId, token);
    await init();
  }

  function getUserNameById(id: string | undefined | null): string {
    if (!id) return 'No User';
    try {
      if (!userNames.value[id]) {
        userNames.value[id] = 'Loading...';
        functions
          .createExecution(
            'userinfo',
            '',
            false,
            '/userinfo/' + id,
            ExecutionMethod.GET
          )
          .then((res) => {
            if (res.responseBody) {
              userNames.value[id] = JSON.parse(res.responseBody).name;
            } else {
              console.error(res, id);
            }
          });
      }
    } catch (e) {
      console.error('Failed to get username. Error: ' + e);
    }
    return userNames.value[id];
  }

  function logout() {
    return account.deleteSession('current').then(() => { currentUser.value = null; });
  }

  async function updateName(name: string) {
    await account.updateName(name);
    currentUser.value = await account.get();
  }

  return {
    currentUser,
    getUserNameById,
    hasRequiredRole,
    register,
    updateName,
    login,
    googleLogin,
    discordLogin,
    createTokenSession,
    tokenLogin,
    logout,
    init,
  };
});
