import { DEFAULT_APP_PASSWORD, PBKDF2_ITERATIONS } from '../constants';

function bytesToB64(bytes: Uint8Array): string {
  let bin = '';
  for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]!);
  return btoa(bin);
}

function b64ToBytes(b64: string): Uint8Array {
  const bin = atob(b64);
  const out = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)!;
  return out;
}

/**
 * 生成存储格式: saltB64:iterations:hashB64
 */
export async function hashPassword(password: string): Promise<string> {
  const enc = new TextEncoder();
  const salt = crypto.getRandomValues(new Uint8Array(16));
  const keyMaterial = await crypto.subtle.importKey(
    'raw',
    enc.encode(password),
    'PBKDF2',
    false,
    ['deriveBits'],
  );
  const bits = await crypto.subtle.deriveBits(
    {
      name: 'PBKDF2',
      salt: salt as BufferSource,
      iterations: PBKDF2_ITERATIONS,
      hash: 'SHA-256',
    },
    keyMaterial,
    256,
  );
  const hash = new Uint8Array(bits);
  return `${bytesToB64(salt)}:${PBKDF2_ITERATIONS}:${bytesToB64(hash)}`;
}

export async function verifyPasswordHash(
  password: string,
  stored: string,
): Promise<boolean> {
  const parts = stored.split(':');
  if (parts.length !== 3) return false;
  const [saltB64, iterStr, hashB64] = parts;
  const iterations = Number(iterStr);
  if (!Number.isFinite(iterations) || iterations < 10000) return false;
  // 旧版曾用 120000，Worker 不支持；需清空 app_meta 中 password_hash 后重新登录
  if (iterations > 100_000) return false;
  const salt = b64ToBytes(saltB64!);
  const expected = b64ToBytes(hashB64!);
  const enc = new TextEncoder();
  const keyMaterial = await crypto.subtle.importKey(
    'raw',
    enc.encode(password),
    'PBKDF2',
    false,
    ['deriveBits'],
  );
  const bits = await crypto.subtle.deriveBits(
    {
      name: 'PBKDF2',
      salt: salt as BufferSource,
      iterations,
      hash: 'SHA-256',
    },
    keyMaterial,
    256,
  );
  const actual = new Uint8Array(bits);
  if (actual.length !== expected.length) return false;
  let ok = 0;
  for (let i = 0; i < actual.length; i++) ok |= actual[i]! ^ expected[i]!;
  return ok === 0;
}

/**
 * 读取数据库中的口令哈希；若无记录则仅当口令为默认口令时视为通过，并返回需写入的哈希。
 */
export async function checkAppPassword(
  password: string,
  storedRow: { value: string } | null,
): Promise<{ ok: boolean; newHashToStore?: string }> {
  if (!storedRow) {
    if (password !== DEFAULT_APP_PASSWORD) {
      return { ok: false };
    }
    const newHashToStore = await hashPassword(password);
    return { ok: true, newHashToStore };
  }
  const ok = await verifyPasswordHash(password, storedRow.value);
  return { ok };
}
