import { ShadeSessionManager } from '../../packages/shade-core/src/index.js';
import { SubtleCryptoProvider, MemoryStorage } from '../../packages/shade-crypto-web/src/index.js';
import { createPrekeyServer, MemoryPrekeyStore } from '../../packages/shade-server/src/index.js';
import { ShadeFetchTransport } from '../../packages/shade-transport/src/index.js';

const crypto = new SubtleCryptoProvider();

async function main() {
  console.log('=== Shade Prekey Server Demo ===\n');

  // Start the prekey server
  const store = new MemoryPrekeyStore();
  const server = createPrekeyServer({ crypto, store });
  const port = 19850;
  const handle = Bun.serve({ port, fetch: server.fetch });
  console.log(`Prekey server listening on http://localhost:${port}\n`);

  try {
    // ─── Bob registers ────────────────────────────────────
    const bobMgr = new ShadeSessionManager(crypto, new MemoryStorage());
    await bobMgr.initialize();

    const bobIdentity = await new MemoryStorage().getIdentityKeyPair();
    // Note: in real usage, get the storage instance you passed in. Simplified here:
    const bobStorageRef = new MemoryStorage();
    const bobMgr2 = new ShadeSessionManager(crypto, bobStorageRef);
    await bobMgr2.initialize();
    const bobKp = await bobStorageRef.getIdentityKeyPair();

    const bobTransport = new ShadeFetchTransport({
      baseUrl: `http://localhost:${port}`,
      crypto,
      signingPrivateKey: bobKp!.signingPrivateKey,
    });

    const bobOTPKs = await bobMgr2.generateOneTimePreKeys(10);
    const bobBundle = await bobMgr2.createPreKeyBundle();
    await bobTransport.register('bob', bobMgr2.getPublicIdentity(), bobBundle.signedPreKey, bobOTPKs);
    console.log('Bob registered with prekey server (10 one-time prekeys uploaded)');
    console.log('Bob fingerprint:', await bobMgr2.getIdentityFingerprint());
    console.log();

    // ─── Alice fetches Bob's bundle anonymously ───────────
    const aliceMgr = new ShadeSessionManager(crypto, new MemoryStorage());
    await aliceMgr.initialize();
    console.log('Alice fingerprint:', await aliceMgr.getIdentityFingerprint());

    // Alice doesn't need a signing key to fetch
    const aliceTransport = new ShadeFetchTransport({
      baseUrl: `http://localhost:${port}`,
      crypto,
    });

    const fetchedBundle = await aliceTransport.fetchBundle('bob');
    console.log('\nAlice fetched Bob\'s bundle');
    console.log('Remaining one-time prekeys:', await aliceTransport.getKeyCount('bob'));

    await aliceMgr.initSessionFromBundle('bob', fetchedBundle);

    // ─── Encrypted conversation ───────────────────────────
    console.log('\n=== Encrypted conversation ===');
    const env1 = await aliceMgr.encrypt('bob', 'Hello via prekey server!');
    console.log('→ Alice sends encrypted message');
    const plain1 = await bobMgr2.decrypt('alice', env1);
    console.log(`← Bob decrypts: "${plain1}"`);

    const env2 = await bobMgr2.encrypt('alice', 'Got your message!');
    console.log('\n→ Bob replies (DH ratchet step)');
    const plain2 = await aliceMgr.decrypt('bob', env2);
    console.log(`← Alice decrypts: "${plain2}"`);

    console.log('\n=== Done ===');
  } finally {
    handle.stop();
  }
}

main().catch(console.error);
