import bcrypt from "bcryptjs";
import { SignJWT, jwtVerify } from "jose";
import { ONE_YEAR_MS } from "@shared/const";
import { ENV } from "./env";

const BCRYPT_ROUNDS = 10;

export async function hashPassword(password: string): Promise<string> {
  return bcrypt.hash(password, BCRYPT_ROUNDS);
}

export async function verifyPassword(
  password: string,
  hash: string | null | undefined
): Promise<boolean> {
  if (!hash) return false;
  try {
    return await bcrypt.compare(password, hash);
  } catch {
    return false;
  }
}

function getSecretKey() {
  if (!ENV.cookieSecret) {
    throw new Error(
      "JWT_SECRET não está configurado. Defina a variável de ambiente JWT_SECRET."
    );
  }
  return new TextEncoder().encode(ENV.cookieSecret);
}

export type SessionPayload = {
  uid: number;
};

/**
 * Creates a signed JWT session token for a local user account.
 */
export async function createSessionToken(
  userId: number,
  expiresInMs: number = ONE_YEAR_MS
): Promise<string> {
  const issuedAt = Date.now();
  const expirationSeconds = Math.floor((issuedAt + expiresInMs) / 1000);

  return new SignJWT({ uid: userId })
    .setProtectedHeader({ alg: "HS256", typ: "JWT" })
    .setIssuedAt()
    .setExpirationTime(expirationSeconds)
    .sign(getSecretKey());
}

/**
 * Verifies a session token and returns the decoded payload, or null if
 * the token is missing, malformed, expired, or has an invalid signature.
 */
export async function verifySessionToken(
  token: string | undefined | null
): Promise<SessionPayload | null> {
  if (!token) return null;

  try {
    const { payload } = await jwtVerify(token, getSecretKey(), {
      algorithms: ["HS256"],
    });

    const uid = payload.uid;
    if (typeof uid !== "number") return null;

    return { uid };
  } catch {
    return null;
  }
}
