import NProgress from "nprogress";
import { useAuthStore } from "@/stores/auth";
import { useAccountStore } from "@/stores/account";
import { jwtDecode, type JwtPayload } from "jwt-decode";
import { refreshToken } from "@/serverCom";
import type { PermissionObject } from "@/types/permissionTypes";
import { useAbilityStore } from "@/stores/ability";

export type Payload = JwtPayload & {
  userId: number;
  username: string;
  firstname: string;
  lastname: string;
  mail: string;
  isOwner: boolean;
  permissions: PermissionObject;
};

export async function isAuthenticated(to: any, from: any, next: any) {
  const auth = useAuthStore();
  NProgress.start();
  if (auth.authCheck && localStorage.getItem("access_token") && localStorage.getItem("refresh_token")) {
    NProgress.done();
    next();
    return;
  }
  await isAuthenticatedPromise()
    .then(async (result: Payload) => {
      NProgress.done();
      next();
    })
    .catch((err: string) => {
      NProgress.done();
      next({ name: err ?? "login" });
    });
}

export async function isAuthenticatedPromise(forceRefresh: boolean = false): Promise<Payload> {
  return new Promise<Payload>(async (resolve, reject) => {
    const auth = useAuthStore();
    const account = useAccountStore();
    const ability = useAbilityStore();
    let decoded: Payload | string = "";
    try {
      decoded = jwtDecode<Payload>(localStorage.getItem("accessToken") ?? "");
    } catch (error) {
      auth.setFailed();
      reject("login");
    }

    if (typeof decoded == "string" || !decoded) {
      auth.setFailed();
      reject("login");
    } else {
      // check jwt expiry
      const exp = decoded.exp ?? 0;
      const correctedLocalTime = new Date().getTime();
      if (exp < Math.floor(correctedLocalTime / 1000) || forceRefresh) {
        await refreshToken()
          .then(() => {
            console.log("fetched new token");
          })
          .catch((err: string) => {
            console.log("expired");
            auth.setFailed();
            reject(err);
          });
      }

      var { firstname, lastname, mail, username, permissions, isOwner } = decoded;

      if (Object.keys(permissions ?? {}).length === 0 && !isOwner) {
        auth.setFailed();
        reject("nopermissions");
      }

      auth.setSuccess();
      account.setAccountData(firstname, lastname, mail, username);
      ability.setAbility(permissions, isOwner);
      resolve(decoded);
    }
  });
}
