export async function deriveKeyFromSecret(secret, salt = 'toolbox_salt_v1') {
  if (!secret || typeof secret !== 'string') {
    throw new Error('Invalid secret: must be a non-empty string');
  }
  
  const enc = new TextEncoder();
  const secretKey = await crypto.subtle.importKey(
    'raw',
    enc.encode(secret),
    { name: 'PBKDF2' },
    false,
    ['deriveKey']
  );

  const key = await crypto.subtle.deriveKey(
    {
      name: 'PBKDF2',
      salt: enc.encode(salt),
      iterations: 100000,
      hash: 'SHA-256'
    },
    secretKey,
    { name: 'AES-GCM', length: 256 },
    true,
    ['encrypt', 'decrypt']
  );

  return key;
}

function _randBytes(len = 12) {
  const b = new Uint8Array(len);
  crypto.getRandomValues(b);
  return b;
}

export async function encryptJSON(key, obj) {
  if (!key || !(key instanceof CryptoKey)) {
    throw new Error('Valid CryptoKey is required');
  }
  
  const enc = new TextEncoder();
  const iv = _randBytes(12);
  const plain = enc.encode(JSON.stringify(obj));
  
  const cipher = await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv: iv },
    key,
    plain
  );

  const combined = new Uint8Array(iv.byteLength + cipher.byteLength);
  combined.set(iv, 0);
  combined.set(new Uint8Array(cipher), iv.byteLength);

  // Безопасное преобразование в base64
  const binaryString = Array.from(combined, byte => 
    String.fromCharCode(byte)).join('');
  return btoa(binaryString);
}

export async function decryptToJSON(key, b64) {
  if (!key || !(key instanceof CryptoKey)) {
    throw new Error('Valid CryptoKey is required');
  }
  
  if (!b64 || typeof b64 !== 'string') {
    throw new Error('Invalid base64 string');
  }

  try {
    // Безопасное преобразование из base64
    const binaryString = atob(b64);
    const raw = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
      raw[i] = binaryString.charCodeAt(i);
    }
    
    const iv = raw.slice(0, 12);
    const cipher = raw.slice(12);
    
    const plainBuf = await crypto.subtle.decrypt(
      { name: 'AES-GCM', iv: iv },
      key,
      cipher
    );
    
    const dec = new TextDecoder();
    return JSON.parse(dec.decode(plainBuf));
  } catch (error) {
    console.error('Decryption error:', error);
    throw new Error('Failed to decrypt data: ' + error.message);
  }
}