'use node';

import {
  createCipheriv,
  createDecipheriv,
  createHash,
  randomBytes,
} from 'node:crypto';
import { ConvexError } from 'convex/values';

const getSecret = () => {
  const secret =
    process.env.SPOON_ENCRYPTION_KEY?.trim() ??
    process.env.INSTANCE_SECRET?.trim();
  if (!secret) {
    throw new ConvexError(
      'SPOON_ENCRYPTION_KEY is not configured. Add it before storing user API keys.',
    );
  }
  return secret;
};

const getKey = () => createHash('sha256').update(getSecret()).digest();

export const encryptSecret = (plaintext: string) => {
  const iv = randomBytes(12);
  const cipher = createCipheriv('aes-256-gcm', getKey(), iv);
  const ciphertext = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();
  return [
    iv.toString('base64url'),
    tag.toString('base64url'),
    ciphertext.toString('base64url'),
  ].join('.');
};

export const decryptSecret = (encrypted: string) => {
  const [ivRaw, tagRaw, ciphertextRaw] = encrypted.split('.');
  if (!ivRaw || !tagRaw || !ciphertextRaw) {
    throw new ConvexError('Stored secret has an invalid format.');
  }
  const decipher = createDecipheriv(
    'aes-256-gcm',
    getKey(),
    Buffer.from(ivRaw, 'base64url'),
  );
  decipher.setAuthTag(Buffer.from(tagRaw, 'base64url'));
  const plaintext = Buffer.concat([
    decipher.update(Buffer.from(ciphertextRaw, 'base64url')),
    decipher.final(),
  ]);
  return plaintext.toString('utf8');
};
