import crypto from 'crypto';
import { create, findOne, deleteWhere } from '@zen/core/database';
import { generateToken, generateId } from './password.js';

async function createEmailVerification(email) {
  const token = generateToken(32);
  const expiresAt = new Date();
  expiresAt.setHours(expiresAt.getHours() + 24);

  await deleteWhere('zen_auth_verifications', { identifier: 'email_verification', value: email });

  const verification = await create('zen_auth_verifications', {
    id: generateId(),
    identifier: 'email_verification',
    value: email,
    token,
    expires_at: expiresAt,
    updated_at: new Date()
  });

  return { ...verification, token };
}

async function verifyEmailToken(email, token) {
  const verification = await findOne('zen_auth_verifications', {
    identifier: 'email_verification',
    value: email
  });

  if (!verification) return false;

  // Timing-safe comparison — always operate on same-length buffers so that a
  // wrong-length guess yields no measurable timing difference from a wrong-value guess.
  const storedBuf   = Buffer.from(verification.token, 'utf8');
  const providedBuf = Buffer.from(
    token.length === verification.token.length ? token : verification.token,
    'utf8'
  );
  const tokensMatch = crypto.timingSafeEqual(storedBuf, providedBuf)
                      && token.length === verification.token.length;
  if (!tokensMatch) return false;

  if (new Date(verification.expires_at) < new Date()) {
    await deleteWhere('zen_auth_verifications', { id: verification.id });
    return false;
  }

  await deleteWhere('zen_auth_verifications', { id: verification.id });
  return true;
}

async function createPasswordReset(email) {
  const token = generateToken(32);
  const expiresAt = new Date();
  expiresAt.setHours(expiresAt.getHours() + 1);

  await deleteWhere('zen_auth_verifications', { identifier: 'password_reset', value: email });

  const reset = await create('zen_auth_verifications', {
    id: generateId(),
    identifier: 'password_reset',
    value: email,
    token,
    expires_at: expiresAt,
    updated_at: new Date()
  });

  return { ...reset, token };
}

async function verifyResetToken(email, token) {
  const reset = await findOne('zen_auth_verifications', {
    identifier: 'password_reset',
    value: email
  });

  if (!reset) return false;

  // Timing-safe comparison — same rationale as verifyEmailToken above.
  const storedBuf   = Buffer.from(reset.token, 'utf8');
  const providedBuf = Buffer.from(
    token.length === reset.token.length ? token : reset.token,
    'utf8'
  );
  const tokensMatch = crypto.timingSafeEqual(storedBuf, providedBuf)
                      && token.length === reset.token.length;
  if (!tokensMatch) return false;

  if (new Date(reset.expires_at) < new Date()) {
    await deleteWhere('zen_auth_verifications', { id: reset.id });
    return false;
  }

  return true;
}

function deleteResetToken(email) {
  return deleteWhere('zen_auth_verifications', { identifier: 'password_reset', value: email });
}

async function createAccountSetup(email) {
  const token = generateToken(32);
  const expiresAt = new Date();
  expiresAt.setHours(expiresAt.getHours() + 48);

  await deleteWhere('zen_auth_verifications', { identifier: 'account_setup', value: email });

  const setup = await create('zen_auth_verifications', {
    id: generateId(),
    identifier: 'account_setup',
    value: email,
    token,
    expires_at: expiresAt,
    updated_at: new Date()
  });

  return { ...setup, token };
}

async function verifyAccountSetupToken(email, token) {
  const setup = await findOne('zen_auth_verifications', {
    identifier: 'account_setup',
    value: email
  });

  if (!setup) return false;

  const storedBuf   = Buffer.from(setup.token, 'utf8');
  const providedBuf = Buffer.from(
    token.length === setup.token.length ? token : setup.token,
    'utf8'
  );
  const tokensMatch = crypto.timingSafeEqual(storedBuf, providedBuf)
                      && token.length === setup.token.length;
  if (!tokensMatch) return false;

  if (new Date(setup.expires_at) < new Date()) {
    await deleteWhere('zen_auth_verifications', { id: setup.id });
    return false;
  }

  return true;
}

function deleteAccountSetupToken(email) {
  return deleteWhere('zen_auth_verifications', { identifier: 'account_setup', value: email });
}

export { createEmailVerification, verifyEmailToken, createPasswordReset, verifyResetToken, deleteResetToken, createAccountSetup, verifyAccountSetupToken, deleteAccountSetupToken };
