import { TVerificationTokenRepository } from "./verification-tokens.repository";

type TVerificationTokenServiceDeps = {
  VerificationTokenRepository: TVerificationTokenRepository;
};

/**
 * Kind used by the one-time console sign-in links that go out in emails.
 *
 * Shares the `verification_tokens` table with invitations and password resets:
 * same shape (single-use, expiring, tied to one console user), and the `kind`
 * column already keeps them from being interchangeable — a reset token cannot be
 * redeemed as a sign-in and vice versa.
 */
export const CONSOLE_SSO_TOKEN_KIND = "console_user_sso";

/*
 * Short by design. The link lands in an inbox, so its lifetime is the window in
 * which a forwarded or leaked mail is still a working session. An hour is enough
 * for someone to act on a notification they read late.
 */
export const CONSOLE_SSO_TTL_MINUTES = 60;

export const VerificationTokenServices = ({
  VerificationTokenRepository,
}: TVerificationTokenServiceDeps) => {
  const CreateInvitationToken = async (userId: string) => {
    return VerificationTokenRepository.CreateToken({
      userId,
      kind: "console_user_invitation",
      expiresInDays: 7,
    });
  };

  const CreateResetPasswordToken = async (userId: string) => {
    return VerificationTokenRepository.CreateToken({
      userId,
      kind: "console_user_reset_password",
      expiresInDays: 1,
    });
  };

  const CreateConsoleSsoToken = async (userId: string) => {
    return VerificationTokenRepository.CreateToken({
      userId,
      kind: CONSOLE_SSO_TOKEN_KIND,
      expiresInMinutes: CONSOLE_SSO_TTL_MINUTES,
    });
  };

  /**
   * Redeems a single-use token: the row is gone whether or not it had expired,
   * so a link can never be replayed.
   */
  const ConsumeToken = async (token: string, kind: string) => {
    const record = await VerificationTokenRepository.ConsumeToken(token, kind);
    if (!record) return null;
    if (new Date(record.expires) < new Date()) return null;
    return record;
  };

  const VerifyToken = async (token: string, kind: string) => {
    const record = await VerificationTokenRepository.FindToken(token, kind);
    if (!record) return null;

    if (new Date(record.expires) < new Date()) {
      await VerificationTokenRepository.DeleteToken(record.id.toString());
      return null;
    }

    return record;
  };

  const DeleteToken = async (id: string) => {
    return VerificationTokenRepository.DeleteToken(id);
  };

  return {
    CreateInvitationToken,
    CreateResetPasswordToken,
    CreateConsoleSsoToken,
    ConsumeToken,
    VerifyToken,
    DeleteToken,
  };
};

export type TVerificationTokenServices = ReturnType<typeof VerificationTokenServices>;
