/**
 * Headless E2E: the REAL daemon device path against a REAL emulator.
 *   real DeviceHost (seal/throttle/route) → real AndroidBackend → real scrcpy
 *   → transport captures SEALED frames → client decrypts with the machine key
 *   → verify H.264 keyframe → seal a tap → handleInput → real injection.
 * The Socket.IO server relay is a proven blind passthrough (relay spec 10/10),
 * so this in-process transport faithfully covers the daemon-side integration.
 */
import { randomBytes } from 'node:crypto';
import { getCryptoEnv } from '@/agent/attachments/cryptoEnv';
import { DeviceHost } from '@/daemon/deviceHost';
import { AndroidBackend, TangoAdbScrcpyClient } from '@/daemon/deviceHost/androidBackend';
import {
    sealInputEnvelope,
    openFrameSealed,
    SECRETBOX_NONCE_BYTES,
    type SecretBox,
    type DeviceFrame,
    type DeviceInfo,
    type DeviceControlResult,
    type DeviceLifecycleEvent,
    type DeviceInputEvent,
} from '@consortium/device-protocol';

const log = (...a: unknown[]) => console.log('[e2e]', ...a);

const env = await getCryptoEnv();
const dek = new Uint8Array(randomBytes(32)); // shared machine key: daemon seals, client opens

const box: SecretBox = {
    seal: (m, n, k) => env.sodium.crypto_secretbox_easy(m, n, k),
    open: (c, n, k) => env.sodium.crypto_secretbox_open_easy(c, n, k),
    randomNonce: () => env.getRandomBytes(SECRETBOX_NONCE_BYTES),
    toBase64: (b) => Buffer.from(b).toString('base64'),
    fromBase64: (s) => new Uint8Array(Buffer.from(s, 'base64')),
};

let frames = 0, keyframes = 0, bytes = 0;
let firstLogged = false;
const results: DeviceControlResult[] = [];
const events: DeviceLifecycleEvent[] = [];
const transport = {
    emitFrame: (f: DeviceFrame) => {
        try {
            const raw = openFrameSealed(box, f, dek); // CLIENT decrypt with machine key
            frames++; bytes += raw.length; if (f.keyframe) keyframes++;
            if (!firstLogged) { firstLogged = true; log(`decoded frame#1 keyframe=${!!f.keyframe} codec=${f.codec} ${raw.length}B seq=${f.seq}`); }
        } catch (e) { log('DECRYPT FAILED ❌', String(e)); }
    },
    emitEvent: (e: DeviceLifecycleEvent) => { events.push(e); log('event:', e.event, e.deviceId); },
    emitControlResult: (r: DeviceControlResult) => { results.push(r); },
};

const host = new DeviceHost({
    env,
    backends: { android: new AndroidBackend(new TangoAdbScrcpyClient()) },
    transport,
    dek: () => dek,
    policy: { mobileToolsDisabled: () => false, ensureConsent: () => {} },
});

await host.handleControl({ type: 'control', id: 'c1', method: 'listDevices', params: { platform: 'android' } });
const r1 = results.find((r) => r.id === 'c1');
const devices = (r1 && 'result' in r1 ? (r1.result as DeviceInfo[]) : []) ?? [];
log('devices:', devices.map((d) => `${d.id} ${d.screen.w}x${d.screen.h}`));
const dev = devices.find((d) => d.id === 'emulator-5554') ?? devices[0];
if (!dev) { log('no device ❌'); process.exit(1); }
host.registerDevice(dev.id, 'android');

log('attaching (real scrcpy)...');
await host.handleControl({ type: 'control', id: 'c2', method: 'attach', params: { deviceId: dev.id, opts: { codec: 'h264', maxFps: 15, maxLongEdge: 1024, quality: 0.6 } } });
const r2 = results.find((r) => r.id === 'c2');
if (r2 && 'ok' in r2 && !r2.ok) { log('attach failed ❌', (r2 as { error: string }).error); process.exit(1); }

await new Promise((res) => setTimeout(res, 8000));
log(`FRAMES: ${frames} decoded & auth'd, ${keyframes} keyframes, ${bytes}B total`);

const tap = (phase: 'down' | 'up'): DeviceInputEvent => ({ kind: 'touch', phase, x: 0.5, y: 0.5 });
let nonce = 0;
await host.handleInput(sealInputEnvelope(box, dev.id, tap('down'), ++nonce, dek));
await host.handleInput(sealInputEnvelope(box, dev.id, tap('up'), ++nonce, dek));
log(`TAP sealed → handleInput → injected at center of ${dev.screen.w}x${dev.screen.h}`);

await host.close();
const pass = frames > 0 && keyframes > 0;
log(pass ? 'E2E PASS ✅' : 'E2E FAIL ❌');
process.exit(pass ? 0 : 1);
