import {
  deleteTokenCookies, getAccessTokenCookie, getRefreshTokenCookie, setAccessTokenCookie, setRefreshTokenCookie,
} from "@utils/auth";
import { APIPath, postBackendAPI } from "./backend";

export type AuthTokenRequest = {
  username: string;
  password: string;
};

export type AuthToken = {
  access: string;
  refresh: string;
};

export type AuthRefreshRequest = {
  refresh: AuthToken["refresh"]
};

export type RefreshedAuthToken = {
  access: string;
};

async function generateToken(username: string, password: string): Promise<AuthToken> {
  const resp = await postBackendAPI<AuthTokenRequest, AuthToken>({ path: APIPath.AUTH_TOKEN_GENERATE }, { username, password });
  return {
    access: resp.access,
    refresh: resp.refresh,
  };
}

async function refreshToken(): Promise<boolean> {
  // Get refresh token if exists
  const refresh = getRefreshTokenCookie();
  if (!refresh) {
    deleteTokenCookies();
    return false;
  }

  try {
    // Renew access token
    const { access } = await postBackendAPI<AuthRefreshRequest, RefreshedAuthToken>({ path: APIPath.AUTH_TOKEN_REFRESH }, { refresh });
    setAccessTokenCookie(access);
  } catch (err) {
    // If we get HTTP500 or something form backend, do not clear cookies
    return false;
  }
  return true;
}

export const login = async (username: string, password: string): Promise<void> => {
  const { access, refresh } = await generateToken(username, password);
  setAccessTokenCookie(access);
  setRefreshTokenCookie(refresh);
};

export const authenticate = async (): Promise<boolean> => {
  // Find access token
  const token = getAccessTokenCookie();
  if (!token) {
    // Unnecessary, but might be good idea to clear old refresh tokens etc.
    deleteTokenCookies();
    return false;
  }

  try {
    await postBackendAPI({ path: APIPath.AUTH_TOKEN_VERIFY }, { token });
    return true;
  } catch (err) {
    // Handle refresh automatically
    return refreshToken();
  }
};
