/**
 * Collects entropy from user interactions (mouse, keyboard, touch)
 * Runs in background to enhance any entropy generation method
 */
export class InteractionEntropy {
    private samples: number[] = [];
    private lastEvent = 0;
    private startTime = performance.now();
    private sources = { mouse: 0, keyboard: 0, touch: 0 };

    constructor() {
        this.initListeners();
    }

    private initListeners() {
        const handleEvent = (e: MouseEvent | KeyboardEvent | TouchEvent) => {
            const now = performance.now();
            const delta = now - this.lastEvent;

            if (delta > 0 && delta < 10000) { // Ignore huge gaps
                this.samples.push(delta);

                if (e instanceof MouseEvent) {
                    this.samples.push(e.clientX ^ e.clientY);
                    this.sources.mouse++;
                } else if (e instanceof KeyboardEvent) {
                    this.samples.push(e.key.codePointAt(0) ?? 0);
                    this.sources.keyboard++;
                } else if (e instanceof TouchEvent && e.touches[0]) {
                    this.samples.push(e.touches[0].clientX ^ e.touches[0].clientY);
                    this.sources.touch++;
                }
            }
            this.lastEvent = now;

            // Keep last 256 samples (128 pairs)
            if (this.samples.length > 256) {
                this.samples.splice(0, this.samples.length - 256);
            }
        };

        document.addEventListener('mousemove', handleEvent);
        document.addEventListener('keydown', handleEvent);
        document.addEventListener('touchmove', handleEvent);
    }

    async getEntropyBytes(): Promise<Uint8Array> {
        // Convert samples to entropy via SHA-256
        const data = new TextEncoder().encode(
            this.samples.join(',') + performance.now()
        );
        const hash = await crypto.subtle.digest('SHA-256', data);
        return new Uint8Array(hash);
    }

    getSampleCount(): { mouse: number; keyboard: number; touch: number; total: number } {
        return {
            ...this.sources,
            total: this.sources.mouse + this.sources.keyboard + this.sources.touch
        };
    }

    getCollectionTime(): number {
        return performance.now() - this.startTime;
    }

    clear() {
        this.samples = [];
        this.lastEvent = 0;
        this.startTime = performance.now();
        this.sources = { mouse: 0, keyboard: 0, touch: 0 };
    }
}