class NextCrypto {
  constructor(secret) {
    this.secret = secret;
  }

  async encrypt(plain) {
    if (!crypto) {
      throw new Error(
        'No WebAPI crypto module found. Do you call me in the right place?',
      );
    }

    const iv = crypto.getRandomValues(new Uint8Array(12));

    const alg = { name: 'AES-GCM', iv };
    const keyHash = await crypto.subtle.digest(
      'SHA-256',
      new TextEncoder().encode(this.secret),
    );

    const encodedPlaintext = new TextEncoder().encode(plain);

    const secretKey = await crypto.subtle.importKey(
      'raw',
      keyHash,
      alg,
      false,
      ['encrypt'],
    );

    const ciphertext = await crypto.subtle.encrypt(
      {
        name: 'AES-GCM',
        iv,
      },
      secretKey,
      encodedPlaintext,
    );

    return `${Buffer.from(ciphertext).toString('base64')};${Buffer.from(
      iv,
    ).toString('base64')}`;
  }

  async decrypt(encrypted) {
    if (!crypto) {
      throw new Error(
        'No WebAPI crypto module found. Do you call me in the right place?',
      );
    }

    const ciphertext = encrypted.split(';')[0];
    const iv = encrypted.split(';')[1];

    if (!ciphertext || !iv) {
      return null;
    }

    const alg = { name: 'AES-GCM', iv };
    const keyHash = await crypto.subtle.digest(
      'SHA-256',
      new TextEncoder().encode(this.secret),
    );

    const secretKey = await crypto.subtle.importKey(
      'raw',
      keyHash,
      alg,
      false,
      ['decrypt'],
    );

    try {
      const cleartext = await crypto.subtle.decrypt(
        {
          name: 'AES-GCM',
          iv: Buffer.from(iv, 'base64'),
        },
        secretKey,
        Buffer.from(ciphertext, 'base64'),
      );

      return new TextDecoder().decode(cleartext);
    } catch (e) {
      return null;
    }
  }
}

module.exports = NextCrypto;
