import { EncryptedMindScopeBackup, MindScopeBackup } from '@/lib/assessment-types';

const ITERATIONS = 250_000;

function toBase64(bytes: Uint8Array) {
  let binary = '';
  bytes.forEach((byte) => { binary += String.fromCharCode(byte); });
  return btoa(binary);
}

function fromBase64(value: string) {
  const binary = atob(value);
  return Uint8Array.from(binary, (character) => character.charCodeAt(0));
}

function toArrayBuffer(bytes: Uint8Array): ArrayBuffer {
  const copy = new Uint8Array(bytes.byteLength);
  copy.set(bytes);
  return copy.buffer;
}

async function deriveKey(password: string, salt: Uint8Array, iterations: number) {
  const material = await crypto.subtle.importKey(
    'raw',
    new TextEncoder().encode(password),
    'PBKDF2',
    false,
    ['deriveKey'],
  );
  return crypto.subtle.deriveKey(
    { name: 'PBKDF2', hash: 'SHA-256', salt: toArrayBuffer(salt), iterations },
    material,
    { name: 'AES-GCM', length: 256 },
    false,
    ['encrypt', 'decrypt'],
  );
}

export async function encryptBackup(backup: MindScopeBackup, password: string): Promise<EncryptedMindScopeBackup> {
  if (password.length < 8) throw new Error('备份密码至少需要 8 个字符');
  const salt = crypto.getRandomValues(new Uint8Array(16));
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const key = await deriveKey(password, salt, ITERATIONS);
  const encrypted = await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv: toArrayBuffer(iv) },
    key,
    new TextEncoder().encode(JSON.stringify(backup)),
  );
  return {
    format: 'mindscope-encrypted-backup',
    version: 1,
    algorithm: 'AES-GCM',
    iterations: ITERATIONS,
    salt: toBase64(salt),
    iv: toBase64(iv),
    data: toBase64(new Uint8Array(encrypted)),
  };
}

export async function decryptBackup(backup: EncryptedMindScopeBackup, password: string): Promise<MindScopeBackup> {
  if (backup.format !== 'mindscope-encrypted-backup' || backup.version !== 1) {
    throw new Error('不支持的加密备份格式');
  }
  try {
    const salt = fromBase64(backup.salt);
    const iv = fromBase64(backup.iv);
    const key = await deriveKey(password, salt, backup.iterations);
    const decrypted = await crypto.subtle.decrypt(
      { name: 'AES-GCM', iv: toArrayBuffer(iv) },
      key,
      toArrayBuffer(fromBase64(backup.data)),
    );
    return JSON.parse(new TextDecoder().decode(decrypted)) as MindScopeBackup;
  } catch {
    throw new Error('密码错误或备份文件已损坏');
  }
}
