import {
  SESSION_ID_TOKEN_DEFAULTS,
  SESSION_TOKEN_DEFAULTS,
  CONSOLE_USER_SESSION_ID_TOKEN_DEFAULTS,
  CONSOLE_USER_SESSION_TOKEN_DEFAULTS,
  CONSOLE_USER_ROLES_TOKEN_DEFAULTS,
} from "@/lib/cookie";
import { decode, sign, verify } from "hono/jwt";
import type { JWTPayload } from "hono/utils/jwt/types";
import { randomUUID } from "crypto";

async function signJWT(payload: JWTPayload): Promise<string> {
  const secret = process.env.JWT_SECRET!;
  const token = await sign(payload, secret);
  return token;
}

async function verifyJWT(token: string): Promise<boolean> {
  const secret = process.env.JWT_SECRET!;
  try {
    await verify(token, secret, "HS256");
    return true;
  } catch (error) {
    return false;
  }
}

export async function createSession(member_email: string) {
  const now = Math.floor(Date.now() / 1000);
  const sessionToken = await signJWT({
    iat: now,
    exp: now + SESSION_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    member_email,
  });

  const dbSessionToken = await signJWT({
    iat: now,
    exp: now + SESSION_ID_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    member_email,
  });

  return { sessionToken, dbSessionToken };
}

export async function verifySession(sessionToken: string) {
  return await verifyJWT(sessionToken);
}

export function decodeSession(sessionToken: string) {
  const { payload } = decode(sessionToken);

  return payload;
}

// TODO: Create blacklist storage using redis

// export async function blacklistSession(sessionToken: string){
//
// }

export async function createMemberSession(
  member_email: string,
  accountID: string,
  contactID: string,
  clubID: string,
) {
  const now = Math.floor(Date.now() / 1000);
  const memberSessionToken = await signJWT({
    iat: now,
    exp: now + SESSION_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    member_email,
    accountID,
    contactID,
    clubID,
  });

  const memberDBSessionToken = await signJWT({
    iat: now,
    exp: now + SESSION_ID_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    member_email,
  });

  return { memberSessionToken, memberDBSessionToken };
}

export const getMemberSessionPayload = (session_token: string) => {
  const payload = decodeSession(session_token);
  return {
    member_email: (payload.member_email as string) ?? null,
    accountID: (payload.accountID as string) ?? null,
    contactID: (payload.contactID as string) ?? null,
    clubID: (payload.clubID as string) ?? null,
  };
};

export async function createAdminSession(email: string, privileges: string[]) {
  const now = Math.floor(Date.now() / 1000);
  const sessionToken = await signJWT({
    iat: now,
    exp: now + SESSION_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    email,
    privileges,
  });

  const dbSessionToken = await signJWT({
    iat: now,
    exp: now + SESSION_ID_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    email,
  });

  return { sessionToken, dbSessionToken };
}

export async function createConsoleUserSession(email: string) {
  const now = Math.floor(Date.now() / 1000);
  const sessionToken = await signJWT({
    iat: now,
    exp: now + CONSOLE_USER_SESSION_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    email,
  });

  const dbSessionToken = await signJWT({
    iat: now,
    exp: now + CONSOLE_USER_SESSION_ID_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    email,
  });

  return { sessionToken, dbSessionToken };
}

export async function signMemberSessionHandOffToken(
  id: string,
  member_email: string,
) {
  const now = Math.floor(Date.now() / 1000);
  const token = await signJWT({
    iat: now,
    exp: now + 200 * 5,
    nbf: now,
    id,
    member_email,
  });

  return token;
}

export const getMemberSessionHandOffPayload = async (
  token: string,
): Promise<{
  id: string | null;
  member_email: string | null;
}> => {
  const isVerified = await verifyJWT(token);
  if (!isVerified) {
    return {
      id: null,
      member_email: null,
    };
  }
  const payload = decodeSession(token);
  return {
    id: payload.id as string,
    member_email: payload.member_email as string,
  };
};

export async function signKcgmSsoToken(email: string) {
  const now = Math.floor(Date.now() / 1000);
  const secret = process.env.KCGM_SSO_SECRET!;
  return await sign(
    {
      iat: now,
      nbf: now,
      exp: now + 90,
      email,
      jti: randomUUID(),
    },
    secret,
  );
}

export async function createConsoleUserRolesToken(
  scopes: any[],
  super_admin: boolean,
) {
  const now = Math.floor(Date.now() / 1000);
  const roleToken = await signJWT({
    iat: now,
    exp: now + CONSOLE_USER_ROLES_TOKEN_DEFAULTS.maxAge,
    nbf: now,
    scopes,
    super_admin,
  });

  return { roleToken };
}
