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

let enclave = null;
let lastDatabase = null;
let currentResource = 'accounts';
let currentAction = 'list';

const RESOURCE_ACTIONS = {
  accounts: ['list', 'get'],
  enclaves: ['list', 'get', 'rotate', 'archive', 'delete'],
  credentials: ['list', 'get'],
  sessions: ['list', 'revoke'],
  grants: ['list', 'revoke'],
  delegations: ['list', 'list_received', 'list_command', 'get', 'revoke', 'verify', 'cleanup'],
  ucans: ['list', 'get', 'revoke', 'verify', 'cleanup'],
  verification_methods: ['list', 'get', 'delete'],
  services: ['list', 'get', 'get_by_id'],
};

const ACTIONS_REQUIRING_SUBJECT = ['get', 'revoke', 'delete', 'verify', 'rotate', 'archive', 'list_received', 'list_command', 'get_by_id'];

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">${escapeHtml(json)}</span>`;
  }
  entry += '</div>';
  
  el.innerHTML += entry;
  el.classList.add('visible');
  el.scrollTop = el.scrollHeight;
  
  console.log(`[${time}] [${card}] ${message}`, data ?? '');
}

function escapeHtml(str) {
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

function setStatus(ready, message) {
  const dot = document.getElementById('status-dot');
  const text = document.getElementById('status-text');
  
  if (dot) {
    dot.className = 'status-dot' + (ready === true ? ' ready' : ready === false ? ' error' : '');
  }
  if (text) {
    text.textContent = message;
  }
}

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 options = {
    challenge,
    rp: {
      name: "Motr Enclave Demo",
      id: window.location.hostname,
    },
    user: {
      id: userId,
      name: `user-${Date.now()}@motr.local`,
      displayName: "Motr Demo 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: options });

  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 {
    setStatus(null, 'Loading...');
    enclave = await createEnclave('./enclave.wasm', { debug: true });
    setStatus(true, 'Ready');
    log('generate', 'ok', 'Plugin loaded successfully');
  } catch (err) {
    setStatus(false, 'Failed');
    log('generate', 'err', `Load failed: ${err?.message || String(err)}`);
  }
}

window.showSection = function(section) {
  document.querySelectorAll('.tab-content').forEach(el => el.classList.remove('active'));
  document.querySelectorAll('.nav-btn').forEach(el => el.classList.remove('active'));
  
  const sectionEl = document.getElementById(`section-${section}`);
  if (sectionEl) sectionEl.classList.add('active');
  
  event?.target?.classList.add('active');
};

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

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

window.testGenerateMock = async function() {
  if (!enclave) return log('generate', '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', 'info', 'Using mock credential...');
  
  try {
    const result = await enclave.generate(mockCredential);
    
    log('generate', 'ok', `DID created: ${result.did}`, {
      did: result.did,
      enclaveId: result.enclave_id,
      publicKey: result.public_key?.slice(0, 20) + '...',
      accounts: result.accounts?.length ?? 0,
      dbSize: result.database?.length ?? 0,
    });
    
    if (result.database) {
      lastDatabase = result.database;
    }
    return result;
  } catch (err) {
    log('generate', 'err', err?.message || String(err));
    throw err;
  }
};

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

window.downloadDatabase = function() {
  if (!lastDatabase) {
    alert('No database in memory. Run generate first.');
    return;
  }
  
  const blob = new Blob([new Uint8Array(lastDatabase)], { type: 'application/octet-stream' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `enclave-${Date.now()}.db`;
  a.click();
  URL.revokeObjectURL(url);
  
  log('load', 'ok', `Downloaded database (${lastDatabase.length} bytes)`);
};

window.uploadDatabase = async function(event) {
  const file = event.target.files?.[0];
  if (!file) return;
  
  const buffer = await file.arrayBuffer();
  lastDatabase = Array.from(new Uint8Array(buffer));
  
  log('load', 'info', `Uploaded ${file.name} (${lastDatabase.length} bytes)`);
  
  if (enclave) {
    await testLoadFromBytes();
  }
};

window.selectResource = function(resource) {
  currentResource = resource;
  currentAction = 'list';
  
  document.querySelectorAll('.resource-btn').forEach(el => el.classList.remove('active'));
  event?.target?.closest('.resource-btn')?.classList.add('active');
  
  document.getElementById('selected-resource').textContent = resource;
  
  const actions = RESOURCE_ACTIONS[resource] || ['list'];
  const pillsContainer = document.getElementById('action-pills');
  pillsContainer.innerHTML = actions.map((action, i) => 
    `<button class="action-pill${i === 0 ? ' active' : ''}" onclick="selectAction('${action}')">${action}</button>`
  ).join('');
  
  updateSubjectRow();
};

window.selectAction = function(action) {
  currentAction = action;
  
  document.querySelectorAll('.action-pill').forEach(el => el.classList.remove('active'));
  event?.target?.classList.add('active');
  
  updateSubjectRow();
};

function updateSubjectRow() {
  const subjectRow = document.getElementById('subject-row');
  const subjectInput = document.getElementById('subject-input');
  
  if (ACTIONS_REQUIRING_SUBJECT.includes(currentAction)) {
    subjectRow.style.display = 'block';
    
    const placeholders = {
      get: 'ID or address',
      revoke: 'ID to revoke',
      delete: 'ID to delete',
      verify: 'CID to verify',
      rotate: 'Enclave ID',
      archive: 'Enclave ID',
      list_received: 'Audience DID',
      list_command: 'Command (e.g., msg/send)',
      get_by_id: 'Service ID (number)',
    };
    
    subjectInput.placeholder = placeholders[currentAction] || 'Subject';
  } else {
    subjectRow.style.display = 'none';
    subjectInput.value = '';
  }
}

window.executeAction = async function() {
  if (!enclave) {
    showResult('Plugin not loaded', true);
    return;
  }
  
  const subject = document.getElementById('subject-input')?.value || '';
  
  if (ACTIONS_REQUIRING_SUBJECT.includes(currentAction) && !subject) {
    showResult(`Subject is required for action: ${currentAction}`, true);
    return;
  }
  
  let filter = `resource:${currentResource} action:${currentAction}`;
  if (subject) {
    filter += ` subject:${subject}`;
  }
  
  try {
    const result = await enclave.exec(filter);
    
    if (result.success) {
      showResult(JSON.stringify(result.result, null, 2), false);
    } else {
      showResult(result.error, true);
    }
  } catch (err) {
    showResult(err?.message || String(err), true);
  }
};

window.quickExec = async function(resource, action) {
  if (!enclave) {
    alert('Plugin not loaded');
    return;
  }
  
  showSection('explorer');
  selectResource(resource);
  selectAction(action);
  await executeAction();
};

function showResult(content, isError = false) {
  const resultEl = document.getElementById('exec-result');
  resultEl.textContent = content;
  resultEl.className = 'result-panel' + (isError ? ' error' : ' success');
}

window.clearResult = function() {
  const resultEl = document.getElementById('exec-result');
  resultEl.innerHTML = '<span class="empty-state">Execute an action to see results</span>';
  resultEl.className = 'result-panel';
};

window.testQuery = async function() {
  if (!enclave) {
    showQueryResult('Plugin not loaded', true);
    return;
  }
  
  const did = document.getElementById('did-input')?.value || '';
  
  try {
    const result = await enclave.query(did);
    showQueryResult(JSON.stringify(result, null, 2), false);
  } catch (err) {
    showQueryResult(err?.message || String(err), true);
  }
};

function showQueryResult(content, isError = false) {
  const resultEl = document.getElementById('query-result');
  resultEl.textContent = content;
  resultEl.className = 'result-panel' + (isError ? ' error' : ' success');
}

window.resetEnclave = async function() {
  if (!enclave) return;
  
  try {
    await enclave.reset();
    lastDatabase = null;
    log('generate', 'info', 'Enclave state reset');
    clearResult();
    document.getElementById('query-result').innerHTML = '<span class="empty-state">Query a DID to see the document</span>';
  } catch (err) {
    log('generate', 'err', `Reset failed: ${err?.message || String(err)}`);
  }
};

window.runAllTests = async function() {
  log('generate', 'info', '=== Running all tests ===');
  
  try {
    await testPing();
    await testGenerateMock();
    await testLoadFromBytes();
    
    showSection('explorer');
    await quickExec('accounts', 'list');
    await quickExec('enclaves', 'list');
    
    showSection('query');
    await testQuery();
    
    log('generate', 'ok', '=== All tests completed ===');
  } catch (err) {
    log('generate', 'err', `Tests failed: ${err?.message || String(err)}`);
  }
};

init();
