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

export async function createEmailChangeToken(userId, newEmail) {
  const token = generateToken(32);
  const expiresAt = new Date();
  expiresAt.setHours(expiresAt.getHours() + 24);

  await deleteWhere('zen_auth_verifications', { identifier: 'email_change:' + userId });

  await create('zen_auth_verifications', {
    id: generateId(),
    identifier: 'email_change:' + userId,
    value: newEmail,
    token,
    expires_at: expiresAt,
    updated_at: new Date(),
  });

  return token;
}

export async function verifyEmailChangeToken(token) {
  const result = await query(
    "SELECT * FROM zen_auth_verifications WHERE identifier LIKE 'email_change:%' AND token = $1",
    [token]
  );

  if (result.rows.length === 0) return null;

  const record = result.rows[0];

  // Timing-safe comparison — same-length buffer padding prevents length-based timing leaks.
  const storedBuf = Buffer.from(record.token, 'utf8');
  const providedBuf = Buffer.from(
    token.length === record.token.length ? token : record.token,
    'utf8'
  );
  const tokensMatch = crypto.timingSafeEqual(storedBuf, providedBuf) && token.length === record.token.length;
  if (!tokensMatch) return null;

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

  const userId = record.identifier.slice('email_change:'.length);
  const newEmail = record.value;

  await deleteWhere('zen_auth_verifications', { id: record.id });

  return { userId, newEmail };
}

export async function applyEmailChange(userId, newEmail) {
  await updateById('zen_auth_users', userId, { email: newEmail, updated_at: new Date() });
  await query(
    'UPDATE zen_auth_accounts SET account_id = $1, updated_at = $2 WHERE user_id = $3 AND provider_id = $4',
    [newEmail, new Date(), userId, 'credential']
  );
}
