import { createEnclave } from '../dist/enclave.js';

let enclave = null;
let lastDatabase = null;

const LogLevel = { INFO: 'info', OK: 'ok', ERR: 'err', DATA: 'data' };

function log(card, level, message, data = null) {
  const el = document.getElementById(`log-${card}`);
  if (!el) return console.log(`[${card}] ${message}`, data ?? '');
  
  const time = new Date().toISOString().slice(11, 23);
  
  let entry = `<div class="log-entry"><span class="log-time">${time}</span> <span class="log-${level}">${message}</span>`;
  if (data !== null) {
    const json = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
    entry += `<span class="log-data">${json}</span>`;
  }
  entry += '</div>';
  
  el.innerHTML += entry;
  el.classList.add('has-content');
  el.scrollTop = el.scrollHeight;
  
  console.log(`[${time}] [${card}] ${message}`, data ?? '');
}

function setStatus(id, ok, message) {
  const el = document.getElementById(id);
  if (el) {
    el.textContent = message;
    el.className = `status ${ok ? 'ok' : ok === false ? 'err' : 'wait'}`;
  }
}

function arrayBufferToBase64(buffer) {
  const bytes = new Uint8Array(buffer);
  let binary = '';
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return btoa(binary);
}

async function createWebAuthnCredential() {
  const userId = crypto.getRandomValues(new Uint8Array(16));
  const challenge = crypto.getRandomValues(new Uint8Array(32));
  
  const publicKeyCredentialCreationOptions = {
    challenge,
    rp: {
      name: "Motr Enclave",
      id: window.location.hostname,
    },
    user: {
      id: userId,
      name: `user-${Date.now()}@motr.local`,
      displayName: "Motr User",
    },
    pubKeyCredParams: [
      { alg: -7, type: "public-key" },
      { alg: -257, type: "public-key" },
    ],
    authenticatorSelection: {
      authenticatorAttachment: "platform",
      userVerification: "preferred",
      residentKey: "preferred",
    },
    timeout: 60000,
    attestation: "none",
  };

  const credential = await navigator.credentials.create({
    publicKey: publicKeyCredentialCreationOptions,
  });

  return {
    id: credential.id,
    rawId: arrayBufferToBase64(credential.rawId),
    type: credential.type,
    response: {
      clientDataJSON: arrayBufferToBase64(credential.response.clientDataJSON),
      attestationObject: arrayBufferToBase64(credential.response.attestationObject),
    },
  };
}

async function init() {
  try {
    log('generate', LogLevel.INFO, 'Loading enclave.wasm...');
    
    enclave = await createEnclave('./enclave.wasm', { debug: true });
    
    setStatus('status', true, 'Ready');
    log('generate', LogLevel.OK, 'Plugin loaded');
  } catch (err) {
    setStatus('status', false, 'Failed');
    log('generate', LogLevel.ERR, `Load failed: ${err?.message || String(err)}`);
  }
}

window.testPing = async function() {
  if (!enclave) return log('ping', LogLevel.ERR, 'Plugin not loaded');
  
  const message = document.getElementById('ping-msg').value || 'hello';
  log('ping', LogLevel.INFO, `Sending: "${message}"`);
  
  try {
    const result = await enclave.ping(message);
    if (result.success) {
      log('ping', LogLevel.OK, `Response: "${result.echo}"`, result);
    } else {
      log('ping', LogLevel.ERR, result.message, result);
    }
    return result;
  } catch (err) {
    log('ping', LogLevel.ERR, err?.message || String(err));
    throw err;
  }
};

window.testGenerate = async function() {
  if (!enclave) return log('generate', LogLevel.ERR, 'Plugin not loaded');
  
  if (!window.PublicKeyCredential) {
    log('generate', LogLevel.ERR, 'WebAuthn not supported in this browser');
    return;
  }
  
  try {
    log('generate', LogLevel.INFO, 'Requesting WebAuthn credential...');
    
    const credential = await createWebAuthnCredential();
    log('generate', LogLevel.OK, `Credential created: ${credential.id.slice(0, 20)}...`);
    
    const credentialJson = JSON.stringify(credential);
    const credentialBase64 = btoa(credentialJson);
    
    log('generate', LogLevel.INFO, 'Calling enclave.generate()...');
    const result = await enclave.generate(credentialBase64);
    
    const logData = { did: result.did, dbSize: result.database?.length };
    log('generate', LogLevel.OK, `DID created: ${result.did}`, logData);
    
    if (result.database) {
      lastDatabase = result.database;
    }
    return result;
  } catch (err) {
    if (err.name === 'NotAllowedError') {
      log('generate', LogLevel.ERR, 'User cancelled or WebAuthn not allowed');
    } else {
      log('generate', LogLevel.ERR, err?.message || String(err));
    }
    throw err;
  }
};

window.testGenerateMock = async function() {
  if (!enclave) return log('generate', LogLevel.ERR, 'Plugin not loaded');
  
  const mockCredential = btoa(JSON.stringify({
    id: `mock-${Date.now()}`,
    rawId: arrayBufferToBase64(crypto.getRandomValues(new Uint8Array(32))),
    type: 'public-key',
    response: {
      clientDataJSON: arrayBufferToBase64(new TextEncoder().encode('{"mock":true}')),
      attestationObject: arrayBufferToBase64(crypto.getRandomValues(new Uint8Array(64))),
    },
  }));
  
  log('generate', LogLevel.INFO, 'Using mock credential...');
  
  try {
    const result = await enclave.generate(mockCredential);
    
    const logData = { did: result.did, dbSize: result.database?.length };
    log('generate', LogLevel.OK, `DID created: ${result.did}`, logData);
    
    if (result.database) {
      lastDatabase = result.database;
    }
    return result;
  } catch (err) {
    log('generate', LogLevel.ERR, err?.message || String(err));
    throw err;
  }
};

window.testLoadFromBytes = async function() {
  if (!enclave) return log('load', LogLevel.ERR, 'Plugin not loaded');
  
  if (!lastDatabase) {
    return log('load', LogLevel.ERR, 'No database in memory - run generate first');
  }
  
  log('load', LogLevel.INFO, `Loading from bytes (${lastDatabase.length} bytes)...`);
  
  try {
    const result = await enclave.load(new Uint8Array(lastDatabase));
    
    if (result.success) {
      log('load', LogLevel.OK, `Loaded DID: ${result.did}`, result);
    } else {
      log('load', LogLevel.ERR, result.error, result);
    }
    return result;
  } catch (err) {
    log('load', LogLevel.ERR, err?.message || String(err));
    throw err;
  }
};

window.testExec = async function() {
  if (!enclave) return log('exec', LogLevel.ERR, 'Plugin not loaded');
  
  const filter = document.getElementById('filter').value;
  if (!filter) return log('exec', LogLevel.ERR, 'Filter required');
  
  log('exec', LogLevel.INFO, `Executing: ${filter}`);
  
  try {
    const result = await enclave.exec(filter);
    
    if (result.success) {
      log('exec', LogLevel.OK, 'Success', result);
    } else {
      log('exec', LogLevel.ERR, result.error, result);
    }
    return result;
  } catch (err) {
    log('exec', LogLevel.ERR, err?.message || String(err));
    throw err;
  }
};

window.testQuery = async function() {
  if (!enclave) return log('query', LogLevel.ERR, 'Plugin not loaded');
  
  const did = document.getElementById('did').value;
  log('query', LogLevel.INFO, did ? `Querying: ${did}` : 'Querying current DID...');
  
  try {
    const result = await enclave.query(did);
    log('query', LogLevel.OK, `Resolved: ${result.did}`, result);
    return result;
  } catch (err) {
    log('query', LogLevel.ERR, err?.message || String(err));
    throw err;
  }
};

window.setFilter = function(filter) {
  document.getElementById('filter').value = filter;
};

window.clearCardLog = function(card) {
  const el = document.getElementById(`log-${card}`);
  if (el) {
    el.innerHTML = '';
    el.classList.remove('has-content');
  }
};

window.runAllTests = async function() {
  log('ping', LogLevel.INFO, '=== Running all tests ===');
  
  try {
    await testPing();
    await testGenerateMock();
    await testLoadFromBytes();
    await testExec();
    await testQuery();
    log('query', LogLevel.OK, '=== All tests passed ===');
  } catch (err) {
    log('query', LogLevel.ERR, `Tests failed: ${err?.message || String(err)}`);
  }
};

init();
