/* global faceapi, CAPSQ_DATA, jQuery */
( function ( $ ) {
	'use strict';

	let stream = null;
	let modelsLoaded = false;

	const $startBtn   = $( '#capsq-start-camera' );
	const $captureBtn = $( '#capsq-capture-face' );
	const $removeBtn  = $( '#capsq-remove-face' );
	const $cameraBox  = $( '#capsq-camera-box' );
	const $video       = document.getElementById( 'capsq-video' );
	const $status      = $( '#capsq-status' );

	async function loadModels() {
		if ( modelsLoaded ) return;
		const url = CAPSQ_DATA.modelsUrl;
		await Promise.all( [
			faceapi.nets.ssdMobilenetv1.loadFromUri( url ),
			faceapi.nets.faceLandmark68Net.loadFromUri( url ),
			faceapi.nets.faceRecognitionNet.loadFromUri( url ),
		] );
		modelsLoaded = true;
	}

	$startBtn.on( 'click', async function () {
		$startBtn.prop( 'disabled', true ).text( 'Loading…' );
		try {
			await loadModels();
			stream = await navigator.mediaDevices.getUserMedia( { video: { width: 640, height: 480 } } );
			$video.srcObject = stream;
			$cameraBox.show();
			$captureBtn.show();
			$startBtn.hide();
		} catch ( err ) {
			alert( 'Could not access camera: ' + err.message );
			$startBtn.prop( 'disabled', false ).text( 'Open Camera' );
		}
	} );

	$captureBtn.on( 'click', async function () {
		$captureBtn.prop( 'disabled', true );

		const SAMPLES_NEEDED = 3;
		const samples = [];
		let attempts = 0;
		const MAX_ATTEMPTS = 30; // safety cap so we never loop forever

		while ( samples.length < SAMPLES_NEEDED && attempts < MAX_ATTEMPTS ) {
			attempts++;
			$captureBtn.text( 'Capturing ' + ( samples.length + 1 ) + ' of ' + SAMPLES_NEEDED + '…' );

			const detection = await faceapi
				.detectSingleFace( $video, new faceapi.SsdMobilenetv1Options({minConfidence:0.5}) )
				.withFaceLandmarks()
				.withFaceDescriptor();

			if ( detection ) {
				samples.push( Array.from( detection.descriptor ) );
			}
			// Small pause between samples so they capture slightly different
			// micro-poses/lighting rather than 3 near-identical frames.
			await new Promise( ( r ) => setTimeout( r, 350 ) );
		}

		if ( samples.length < SAMPLES_NEEDED ) {
			alert( 'Could not capture enough clear samples. Make sure your face is well-lit and clearly visible, then try again.' );
			$captureBtn.prop( 'disabled', false ).text( 'Capture Face' );
			return;
		}

		// Average the samples element-wise into one more robust descriptor.
		const descriptor = new Array( 128 ).fill( 0 );
		samples.forEach( ( s ) => {
			for ( let i = 0; i < 128; i++ ) descriptor[ i ] += s[ i ] / SAMPLES_NEEDED;
		} );

		$.ajax( {
			url: CAPSQ_DATA.restUrl + '/enroll',
			method: 'POST',
			beforeSend: function ( xhr ) {
				xhr.setRequestHeader( 'X-WP-Nonce', CAPSQ_DATA.nonce );
			},
			contentType: 'application/json',
			data: JSON.stringify( { descriptor: descriptor } ),
		} )
			.done( function () {
				$status.html( '<span style="color:green;">&#10003; Face enrolled</span>' );
				$removeBtn.show();
				stopCamera();
			} )
			.fail( function ( xhr ) {
				alert( 'Failed to save face: ' + ( xhr.responseJSON && xhr.responseJSON.message ? xhr.responseJSON.message : 'unknown error' ) );
			} )
			.always( function () {
				$captureBtn.prop( 'disabled', false ).text( 'Capture Face' );
			} );
	} );

	$removeBtn.on( 'click', function () {
		if ( ! confirm( 'Remove your enrolled face data?' ) ) return;
		
		$.ajax( {
			url: CAPSQ_DATA.restUrl + '/remove-face',
			method: 'POST',
			beforeSend: function ( xhr ) {
				xhr.setRequestHeader( 'X-WP-Nonce', CAPSQ_DATA.nonce );
			},
			contentType: 'application/json',
			data: JSON.stringify( {} ),
		} ).done( function () {
			$status.html( '<span style="color:#a00;">No face enrolled yet</span>' );
			$removeBtn.hide();
		} );
	} );

	function stopCamera() {
		if ( stream ) {
			stream.getTracks().forEach( ( t ) => t.stop() );
			stream = null;
		}
		$cameraBox.hide();
		$captureBtn.hide();
		$startBtn.show().prop( 'disabled', false ).text( 'Open Camera' );
	}

	/* PIN setup */
	$( '#capsq-save-pin' ).on( 'click', function () {
		const pin     = $( '#capsq-pin' ).val();
		const confirm = $( '#capsq-pin-confirm' ).val();
		const $out    = $( '#capsq-pin-status' );

		if ( ! /^[0-9]{4,8}$/.test( pin ) ) {
			$out.css( 'color', '#a00' ).text( 'PIN must be 4-8 digits.' );
			return;
		}
		if ( pin !== confirm ) {
			$out.css( 'color', '#a00' ).text( 'PINs do not match.' );
			return;
		}

		var that = $(this);
		that.text("Please Wait..").prop("disabled", true);

		$.ajax( {
			url: CAPSQ_DATA.restUrl + '/save-pin',
			method: 'POST',
			beforeSend: function ( xhr ) {
				xhr.setRequestHeader( 'X-WP-Nonce', CAPSQ_DATA.nonce );
			},
			contentType: 'application/json',
			data: JSON.stringify( { pin: pin } ),
		} )
		.done( function () {
			$( '#capsq-pin, #capsq-pin-confirm' ).val( '' );
			$out.html('<span style="color:green;">&#10003; Pin set.</span>');
		} )
		.fail( function () {
			$out.css( 'color', '#a00' ).text( 'Could not save PIN.' );
		} )
		.always(function () {
        	that.text("Save PIN").prop("disabled", false);
    	});
	} );
} )( jQuery );
