// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
export class XCUQuantumMatrix {
	private transport: WebTransport | null = null;
	private stream: WebTransportBidirectionalStream | null = null;
	private streamWriter: WritableStreamDefaultWriter | null = null;
	private streamReader: ReadableStreamDefaultReader | null = null;
	private videoDecoders: Map<number, VideoDecoder> = new Map();
	private canvasCtxMap: Map<number, CanvasRenderingContext2D> = new Map();
	private videoEncoder: VideoEncoder | null = null;
	private isRunning: boolean = false;
	private mediaStream: MediaStream | null = null;
	public participantId: number = 0;
	public participantRole: "PANELIST" | "AUDIENCE" = "PANELIST";

	// Callbacks
	public onParticipantJoined: ((id: number) => void) | null = null;
	public onParticipantLeft: ((id: number) => void) | null = null;
	public onQuantumDataReceived:
		| ((senderId: number, payload: string) => void)
		| null = null;
	public onLocalStream: ((stream: MediaStream) => void) | null = null;
	public onActiveSpeakerChanged: ((speakerId: number) => void) | null = null;
	public onAudioLevel: ((level: number) => void) | null = null;

	private vadAudioCtx: AudioContext | null = null;

	public registerCanvas(participantId: number, canvasId: string) {
		const canvas = document.getElementById(canvasId) as HTMLCanvasElement;
		if (canvas) {
			const ctx = canvas.getContext("2d");
			if (ctx) this.canvasCtxMap.set(participantId, ctx);
			console.log(
				`[QUANTUM MATRIX] Canvas didaftarkan untuk Partisipan ${participantId}`,
			);
		}
	}

	public async ignite() {
		this.isRunning = true;
		console.log(
			"[QUANTUM MATRIX] Menginisialisasi Pipa WebTransport & WebCodecs...",
		);

		// 2. Setup WebTransport ke Rust Backend
		try {
			// Menggunakan port Standar Kuantum 4433 (UDP) dengan Sertifikat Valid Let's Encrypt
			this.transport = new WebTransport(
				typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.hostname}:8443` : "/xcu-engine",
			);
			await this.transport.ready;
			console.log("[QUANTUM MATRIX] Terhubung ke Server Zero-Copy QUIC!");

			// Setup awal dihapus, decoder akan dibuat per-partisipan
			this.startReceiver();
		} catch (e: unknown) {
			console.error("[QUANTUM MATRIX] Gagal menembus matriks QUIC:", e);
			throw e;
		}
	}

	public toggleMic(enabled: boolean) {
		if (this.mediaStream) {
			this.mediaStream.getAudioTracks().forEach((track) => {
				track.enabled = enabled;
			});
			console.log(`[QUANTUM UPLINK] Mikrofon ${enabled ? "Aktif" : "Mati"}`);
		}
	}

	public resumeAudioContext() {
		if (this.vadAudioCtx && this.vadAudioCtx.state === "suspended") {
			this.vadAudioCtx
				.resume()
				.catch((e) => console.error("Force resume failed", e));
		}
	}

	private createDecoderForParticipant(senderId: number) {
		const decoder = new VideoDecoder({
			output: (frame: unknown) => {
				const ctx = this.canvasCtxMap.get(senderId);
				if (ctx) {
					ctx.drawImage(
						frame as unknown as CanvasImageSource,
						0,
						0,
						ctx.canvas.width,
						ctx.canvas.height,
					);
				}
				(frame as { close(): void }).close();
			},
			error: (e: unknown) =>
				console.error(`Decoder Error untuk ${senderId}:`, e),
		});

		decoder.configure({
			codec: "avc1.42E01E", // H.264 Baseline
			codedWidth: 1280,
			codedHeight: 720,
		});

		this.videoDecoders.set(senderId, decoder);

		// Notifikasi React untuk merender tile
		if (this.onParticipantJoined) {
			this.onParticipantJoined(senderId);
		}
	}

	public async activateUplink(source: "camera" | "screen" = "camera") {
		if (this.mediaStream) {
			console.warn(
				"[QUANTUM UPLINK] Kamera/Layar sudah aktif! Mengabaikan perintah ganda untuk mencegah kebocoran memori.",
			);
			return;
		}
		console.log(
			`[QUANTUM UPLINK] Memulai Injeksi ${source === "screen" ? "Layar" : "Kamera"} ke WebCodecs...`,
		);
		try {
			if (source === "screen") {
				this.mediaStream = await navigator.mediaDevices.getDisplayMedia({
					video: { width: 1280, height: 720 },
					audio: false,
				});
			} else {
				this.mediaStream = await navigator.mediaDevices.getUserMedia({
					video: { width: 1280, height: 720 },
					audio: true,
				});
				this.startVadLoop(this.mediaStream); // Phase 37: Auto-Start VAD
			}

			if (this.onLocalStream) {
				this.onLocalStream(this.mediaStream);
			}

			// Jika Klien adalah AUDIENCE, abaikan penyalaan WebCodecs untuk menghemat RAM 100%
			if (this.participantRole === "AUDIENCE") {
				console.log(
					"[QUANTUM MATRIX] Tersambung sebagai AUDIENCE. Menutup jalur Uplink Video.",
				);
				await this.sendRoleSignal();
				return;
			}

			const videoTrack = this.mediaStream.getVideoTracks()[0];

			const processor = new MediaStreamTrackProcessor({
				track: videoTrack,
			});
			const reader = processor.readable.getReader();

			// Setup Hardware Encoder
			this.videoEncoder = new VideoEncoder({
				output: async (chunk: unknown) => {
					if (this.streamWriter && this.isRunning) {
						// Quantum Protocol v3: 8-Byte Header
						// Byte 0: Type (0=Delta, 1=Key, 2=Audio, 3=Control)
						// Byte 1: Quality (0=Low, 1=High, 2=VAD Active)
						// Byte 2-3: Participant ID (u16)
						// Byte 4-7: Length (4 bytes)
						const packet = new Uint8Array(
							8 + (chunk as { byteLength: number }).byteLength,
						);
						packet[0] = (chunk as { type: string }).type === "key" ? 1 : 0;
						packet[1] = 1; // High Quality

						const view = new DataView(packet.buffer);
						view.setUint16(2, this.participantId, true);
						view.setUint32(
							4,
							(chunk as { byteLength: number }).byteLength,
							true,
						); // Little-endian length

						(chunk as { copyTo(buf: ArrayBuffer): void }).copyTo(
							packet.buffer.slice(8),
						);

						// Tembakkan via QUIC Stream (Otomatis Fragmentasi MTU)
						await this.streamWriter.write(packet);
					}
				},
				error: (e: unknown) => console.error("Encoder Error:", e),
			});

			this.videoEncoder.configure({
				codec: "avc1.42E01E", // H.264
				width: 1280,
				height: 720,
				bitrate: 2_000_000, // 2 Mbps
				framerate: 30,
				latencyMode: "realtime",
			});

			// Loop pengiriman Frame ke GPU Encoder
			this.encodeLoop(reader);
		} catch (e: unknown) {
			console.error("[QUANTUM UPLINK] Gagal mengaktifkan kamera:", e);
		}
	}

	public async deactivateUplink() {
		console.log("[QUANTUM UPLINK] Mematikan Kamera (Downlink tetap aktif)...");
		if (this.mediaStream) {
			this.mediaStream.getTracks().forEach((t) => {
				t.stop();
			});
			this.mediaStream = null;
		}
		if (this.videoEncoder && this.videoEncoder.state !== "closed") {
			this.videoEncoder.close();
			this.videoEncoder = null;
		}
	}

	private async encodeLoop(reader: ReadableStreamDefaultReader) {
		while (this.isRunning) {
			try {
				const { done, value: frame } = await reader.read();
				if (done || !frame) break;

				if (this.videoEncoder && this.videoEncoder.state === "configured") {
					this.videoEncoder.encode(frame, { keyFrame: false });
				}
				if (frame) frame.close();
			} catch {
				// Stream terputus atau kamera dimatikan
				break;
			}
		}
	}

	private async startReceiver() {
		if (!this.transport) return;

		try {
			console.log("[QUANTUM MATRIX] Menciptakan QUIC Bidirectional Stream...");
			// Klien yang berinisiatif membuka Bi-Directional Stream pertama kali
			this.stream = await this.transport.createBidirectionalStream();
			this.streamWriter = this.stream.writable.getWriter();
			this.streamReader = this.stream.readable.getReader();

			let buffer = new Uint8Array(0);

			while (this.isRunning) {
				const { value, done } = await this.streamReader.read();
				if (done) {
					console.log("QUIC Stream Ditutup oleh Server.");
					break;
				}

				if (value) {
					// Gabungkan chunk yang baru datang ke dalam buffer
					const newBuffer = new Uint8Array(buffer.length + value.length);
					newBuffer.set(buffer);
					newBuffer.set(value, buffer.length);
					buffer = newBuffer;

					// Ekstrak Frame berdasarkan 8-byte header
					while (buffer.length >= 8) {
						const frameType = buffer[0];
						const quality = buffer[1];
						const view = new DataView(
							buffer.buffer,
							buffer.byteOffset,
							buffer.byteLength,
						);
						const senderId = view.getUint16(2, true);
						const frameLength = view.getUint32(4, true);

						if (buffer.length >= 8 + frameLength) {
							const payloadData = buffer.slice(8, 8 + frameLength);
							buffer = buffer.slice(8 + frameLength);

							// [FASE 40] Eksekusi Quantum Ledger (Telepati Data)
							if (frameType === 6) {
								if (this.onQuantumDataReceived) {
									const textDecoder = new TextDecoder();
									const payloadStr = textDecoder.decode(payloadData);
									this.onQuantumDataReceived(senderId, payloadStr);
								}
								continue; // Lanjut ke paket berikutnya, ini bukan Video
							}

							// [FASE 37] Tangkap Sinyal Active Speaker Broadcast dari Core
							if (frameType === 3 && quality === 2) {
								if (this.onActiveSpeakerChanged) {
									this.onActiveSpeakerChanged(senderId);
								}
								continue;
							}

							// Injeksi Frame Video langsung ke Hardware Decoder Klien
							if (frameType === 0 || frameType === 1) {
								if (!this.videoDecoders.has(senderId)) {
									this.createDecoderForParticipant(senderId);
								}

								const decoder = this.videoDecoders.get(senderId);
								if (decoder && decoder.state === "configured") {
									const chunk = new EncodedVideoChunk({
										type: frameType === 1 ? "key" : "delta",
										timestamp: performance.now() * 1000,
										data: payloadData,
									});
									decoder.decode(chunk);
								}
							}
						} else {
							// Butuh lebih banyak byte untuk membentuk frame utuh
							break;
						}
					}
				}
			}
		} catch (e: unknown) {
			console.error("[QUANTUM MATRIX] Kegagalan Aliran (Stream Failure):", e);
		}
	}

	// Fase 37: Voice Activity Detection (VAD) Loop
	private startVadLoop(stream: MediaStream) {
		try {
			this.vadAudioCtx = new (
				window.AudioContext ||
				(window as unknown as { webkitAudioContext: typeof AudioContext })
					.webkitAudioContext
			)();
			if (this.vadAudioCtx.state === "suspended") {
				this.vadAudioCtx
					.resume()
					.catch((e) => console.warn("[VAD] Cannot resume AudioContext", e));
			}
			const source = this.vadAudioCtx.createMediaStreamSource(stream);
			const analyser = this.vadAudioCtx.createAnalyser();
			analyser.fftSize = 512;

			// Trik khusus untuk browser modern agar benar-benar memproses FFT stream
			const dummyGain = this.vadAudioCtx.createGain();
			dummyGain.gain.value = 0; // Bisukan (Mute) agar tidak terjadi echo

			source.connect(analyser);
			analyser.connect(dummyGain);
			dummyGain.connect(this.vadAudioCtx.destination);

			const dataArray = new Uint8Array(analyser.frequencyBinCount);
			let speakingFrames = 0;

			setInterval(() => {
				analyser.getByteFrequencyData(dataArray);
				const sum = dataArray.reduce((a, b) => a + b, 0);
				const avg = sum / dataArray.length;

				if (this.onAudioLevel) {
					this.onAudioLevel(avg);
				}

				if (avg > 5) {
					// Ambang batas diturunkan drastis ke 5
					speakingFrames++;
					if (speakingFrames === 3) {
						// Hanya kirim jika uplink siap
						if (this.streamWriter && this.isRunning) {
							this.sendDirectorSignal(2);
						}
					}
				} else {
					speakingFrames = 0;
				}
			}, 100);
		} catch (e: unknown) {
			console.warn(
				"[VAD] Audio Context tidak didukung atau dicekal browser.",
				e,
			);
		}
	}

	private async sendDirectorSignal(actionQuality: number) {
		if (!this.streamWriter) return;
		const packet = new Uint8Array(8);
		packet[0] = 3; // Control
		packet[1] = actionQuality;
		const view = new DataView(packet.buffer);
		view.setUint16(2, this.participantId, true);
		view.setUint32(4, 0, true);
		await this.streamWriter.write(packet);
	}

	// Fase 34: Zero-CPU Omniscient Recording
	public async triggerQuantumRecording() {
		if (!this.streamWriter) return;
		const packet = new Uint8Array(8);
		packet[0] = 3; // Control
		packet[1] = 6; // Set Action: Record
		const view = new DataView(packet.buffer);
		view.setUint16(2, this.participantId, true);
		view.setUint32(4, 0, true);
		await this.streamWriter.write(packet);
		console.log(
			"[VAULT MATRIX] Sinyal Perekaman Kuantum Langsung Ke SSD Server Dikirim.",
		);
	}

	// Fase 35: SVC Downgrade (Anti-Lag Manual/Otomatis)
	public async activateAntiLagDowngrade() {
		if (this.streamWriter) {
			console.log("[SVC MATRIX] Mengirim sinyal Downgrade ke Server Rust...");
			const controlPacket = new Uint8Array(8);
			controlPacket[0] = 3; // Type: Control
			controlPacket[1] = 0; // Quality: Low (Drop paket 1080p)
			const view = new DataView(controlPacket.buffer);
			view.setUint16(2, this.participantId, true);
			view.setUint32(4, 0, true); // Payload Length: 0

			await this.streamWriter.write(controlPacket);
		}
	}

	// Fase 39: Webinar Asimetris (Audience)
	public async joinAsAudience() {
		this.participantRole = "AUDIENCE";
		await this.sendRoleSignal();
		console.log(
			"[WEBINAR MATRIX] Beralih ke Mode AUDIENCE (Uplink Dimatikan).",
		);
	}

	private async sendRoleSignal() {
		if (!this.streamWriter) return;
		const packet = new Uint8Array(8);
		packet[0] = 3; // Control
		packet[1] = 4; // Set Role
		const view = new DataView(packet.buffer);
		view.setUint16(2, this.participantId, true);
		packet[4] = this.participantRole === "AUDIENCE" ? 1 : 0; // 1=Audience, 0=Panelist
		await this.streamWriter.write(packet);
	}

	// Fase 39: Podcast Mode (Matikan Video di Routing Level)
	public async setPodcastMode(isPodcast: boolean) {
		if (!this.streamWriter) return;
		const packet = new Uint8Array(8);
		packet[0] = 3; // Control
		packet[1] = 5; // Set Mode
		const view = new DataView(packet.buffer);
		view.setUint16(2, this.participantId, true);
		packet[4] = isPodcast ? 1 : 0; // 1=Podcast, 0=Webinar
		await this.streamWriter.write(packet);
		console.log(
			`[PODCAST MATRIX] Sinyal ${isPodcast ? "PODCAST" : "WEBINAR"} dikirim ke Core.`,
		);
	}

	// Fase 40: The Quantum Ledger (Pengganti WebSocket Node.js)
	// Menembakkan Chat, JSON, Emoji, Koordinat langsung via QUIC
	public async sendQuantumData(payload: string) {
		if (!this.streamWriter) return;

		const textEncoder = new TextEncoder();
		const payloadBytes = textEncoder.encode(payload);

		const packet = new Uint8Array(8 + payloadBytes.byteLength);
		packet[0] = 6; // Type: Ledger Data
		packet[1] = 0; // Quality: N/A
		const view = new DataView(packet.buffer);
		view.setUint16(2, this.participantId, true);
		view.setUint32(4, payloadBytes.byteLength, true);

		packet.set(payloadBytes, 8);

		await this.streamWriter.write(packet);
	}

	public disconnect() {
		this.isRunning = false;
		if (this.transport) {
			this.transport.close();
		}
		this.videoDecoders.forEach((decoder) => {
			if (decoder.state !== "closed") decoder.close();
		});
		this.videoDecoders.clear();
		this.canvasCtxMap.clear();
		if (this.videoEncoder && this.videoEncoder.state !== "closed") {
			this.videoEncoder.close();
		}
		if (this.mediaStream) {
			this.mediaStream.getTracks().forEach((t) => {
				t.stop();
			});
		}
		console.log("[QUANTUM MATRIX] Sistem Terputus.");
	}

	public shutdown() {
		this.isRunning = false;
		if (this.transport) {
			this.transport.close();
		}
		this.videoDecoders.forEach((decoder) => {
			if (decoder.state !== "closed") decoder.close();
		});
		this.videoDecoders.clear();
		this.canvasCtxMap.clear();
		if (this.videoEncoder && this.videoEncoder.state !== "closed") {
			this.videoEncoder.close();
		}
		if (this.mediaStream) {
			this.mediaStream.getTracks().forEach((t) => {
				t.stop();
			});
		}
		console.log("[QUANTUM MATRIX] Sistem Terputus.");
	}
}
