<?php
if (session_status() === PHP_SESSION_NONE) session_start();
if (!isset($_SESSION['user_id'])) { header('Location: ../index.php'); exit; }
require_once '../config.php';
require_once '../includes/canteen_helpers.php';
canteen_require_active();
canteen_require_role(['admin', 'headteacher']);

$settings = canteen_get_settings();
if (empty($settings['facial_recognition_enabled'])) {
    header('Location: settings.php?tab=hardware&error=facial_disabled');
    exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Facial Enrollment — EduTrack</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
    <link rel="stylesheet" href="../css/style.css">
    <style>
        .student-card { border: 2px solid #e9ecef; border-radius: 12px; padding: 1rem; cursor: pointer; }
        .student-card:hover { border-color: #0d6efd; background: #f8f9ff; }
        .student-photo { width: 80px; height: 80px; border-radius: 50%; object-fit: cover; }
        #facePreviewWrap {
            position: relative; width: 100%; max-width: 400px; margin: 0 auto;
            border-radius: 12px; overflow: hidden; background: #000;
            aspect-ratio: 4/3;
        }
        #faceVideo { width: 100%; height: 100%; object-fit: cover; display: block; }
        #faceCanvas { position: absolute; inset: 0; width: 100%; height: 100%; }
        #faceOverlay {
            position: absolute; inset: 0; display: flex;
            align-items: center; justify-content: center;
            background: rgba(0,0,0,.6); color: #fff;
            font-size: .9rem; text-align: center; padding: 1rem;
        }
        #enrollStatus {
            border-radius: 12px; padding: 1.5rem; text-align: center; display: none;
        }
        #enrollStatus.success { background: #d1e7dd; color: #0a3622; }
        #enrollStatus.error   { background: #f8d7da; color: #58151c; }
        #lightingAlert { display: none; }
        .face-dot {
            position: absolute; width: 4px; height: 4px;
            background: rgba(76,175,80,.7); border-radius: 50%;
            transform: translate(-50%, -50%);
        }
    </style>
</head>
<body>
<div class="wrapper">
    <nav id="sidebar" class="sidebar">
        <?php echo buildSidebar('canteen/enroll_facial.php'); ?>
    </nav>
    <div class="main-content">
        <header class="header">
            <button class="btn-toggle" id="sidebarToggle"><i class="fas fa-bars"></i></button>
            <div class="header-right">
                <div class="dropdown">
                    <button class="btn btn-link dropdown-toggle" type="button" data-bs-toggle="dropdown">
                        <i class="fas fa-user-circle me-2"></i><?php echo htmlspecialchars((string)($_SESSION['full_name'] ?? '')); ?>
                    </button>
                    <ul class="dropdown-menu dropdown-menu-end">
                        <li><a class="dropdown-item" href="../dashboard.php"><i class="fas fa-home me-2"></i>Dashboard</a></li>
                    </ul>
                </div>
            </div>
        </header>
        <main class="content">
            <div class="content-header">
                <h2><i class="fas fa-user-circle me-2"></i>Facial Recognition Enrollment</h2>
                <p class="text-muted">Capture a student's facial landmarks using MediaPipe. All processing is local — no images sent to any server.</p>
            </div>

            <div class="row justify-content-center">
                <div class="col-lg-8">

                    <!-- Data Protection Notice -->
                    <div class="alert alert-warning border-warning mb-4">
                        <h6 class="alert-heading fw-bold"><i class="fas fa-shield-alt me-2"></i>Data Protection Notice</h6>
                        <p class="small mb-2">Facial recognition data is stored <strong>only in your school's secure database</strong>. No student images or facial data are transmitted to ORIC Network or any external service at any time, including during verification. All face matching is performed locally in your school's browser.</p>
                        <ul class="small mb-0">
                            <li>Your school must inform all students and parents/guardians before enrollment.</li>
                            <li>Obtain <strong>consent</strong> from parents/guardians for students under 18.</li>
                            <li>Comply with Ghana's <strong>Data Protection Act 2012 (Act 843)</strong>.</li>
                            <li>Students may decline — QR code is their permanent alternative.</li>
                        </ul>
                    </div>

                    <!-- Step 1: Search student -->
                    <div class="card mb-3" id="stepSearch">
                        <div class="card-header fw-semibold">Step 1 — Find Student</div>
                        <div class="card-body">
                            <div class="input-group">
                                <input type="text" id="studentSearch" class="form-control"
                                       placeholder="Name or student ID…" autocomplete="off">
                                <button class="btn btn-primary" id="btnSearch">
                                    <i class="fas fa-search"></i>
                                </button>
                            </div>
                            <div id="searchResults" class="mt-3"></div>
                        </div>
                    </div>

                    <!-- Step 2: Consent + method choice -->
                    <div class="card mb-3 d-none" id="stepConsent">
                        <div class="card-header fw-semibold">Step 2 — Consent &amp; Method</div>
                        <div class="card-body">
                            <div class="d-flex align-items-center gap-3 mb-3 p-3 border rounded">
                                <img id="selPhoto" src="" alt="" class="student-photo">
                                <div>
                                    <div class="fw-bold fs-5" id="selName"></div>
                                    <div class="text-muted" id="selClass"></div>
                                    <div class="text-muted small" id="selCode"></div>
                                    <span id="facialAlreadyEnrolled" class="badge bg-success d-none mt-1">
                                        <i class="fas fa-check me-1"></i>Facial already enrolled — will be updated
                                    </span>
                                </div>
                            </div>

                            <div class="form-check mb-3">
                                <input class="form-check-input" type="checkbox" id="consentCheck">
                                <label class="form-check-label small" for="consentCheck">
                                    I confirm that parent/guardian consent has been obtained for facial biometric enrollment in accordance with Ghana's Data Protection Act 2012.
                                </label>
                            </div>

                            <!-- Source selection -->
                            <div class="row g-2 mb-3" id="sourceSelect">
                                <div class="col-6">
                                    <button class="btn btn-outline-primary w-100" id="btnUsePhoto" disabled>
                                        <i class="fas fa-image d-block mb-1"></i>Use Profile Photo
                                    </button>
                                </div>
                                <div class="col-6">
                                    <button class="btn btn-outline-success w-100" id="btnUseWebcam" disabled>
                                        <i class="fas fa-video d-block mb-1"></i>Capture via Webcam
                                    </button>
                                </div>
                            </div>

                            <button class="btn btn-outline-secondary btn-sm" id="btnReselect">
                                <i class="fas fa-times me-1"></i>Choose Different Student
                            </button>
                        </div>
                    </div>

                    <!-- Step 3a: Profile photo -->
                    <div class="card mb-3 d-none" id="stepPhoto">
                        <div class="card-header fw-semibold">Step 3 — Confirm Face from Profile Photo</div>
                        <div class="card-body text-center">
                            <div id="facePreviewWrap" class="mb-3">
                                <img id="staticPhoto" src="" alt="" style="width:100%;height:100%;object-fit:cover;display:block">
                                <canvas id="faceCanvas"></canvas>
                                <div id="faceOverlay">
                                    <span><i class="fas fa-circle-notch fa-spin me-2"></i>Loading MediaPipe…</span>
                                </div>
                            </div>
                            <div id="lightingAlert" class="alert alert-warning alert-sm py-1 mb-2">
                                <i class="fas fa-exclamation-triangle me-1"></i>Low lighting detected. Accuracy may be reduced.
                            </div>
                            <p id="faceStatusMsg" class="text-muted small mb-3">Initialising face detection…</p>
                            <button class="btn btn-success d-none" id="btnConfirmDescriptor">
                                <i class="fas fa-check me-2"></i>Confirm &amp; Save Face Data
                            </button>
                            <button class="btn btn-outline-secondary ms-2" id="btnBackFromPhoto">Back</button>
                        </div>
                    </div>

                    <!-- Step 3b: Webcam capture -->
                    <div class="card mb-3 d-none" id="stepWebcam">
                        <div class="card-header fw-semibold">Step 3 — Capture via Webcam</div>
                        <div class="card-body text-center">
                            <div id="facePreviewWrap2" class="mb-3" style="position:relative;width:100%;max-width:400px;margin:0 auto;border-radius:12px;overflow:hidden;background:#000;aspect-ratio:4/3">
                                <video id="faceVideo" autoplay playsinline muted style="width:100%;height:100%;object-fit:cover;display:block"></video>
                                <canvas id="faceLandmarks" style="position:absolute;inset:0;width:100%;height:100%"></canvas>
                                <div id="faceOverlay2" style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.6);color:#fff;font-size:.9rem;text-align:center;padding:1rem">
                                    <span><i class="fas fa-circle-notch fa-spin me-2"></i>Starting camera…</span>
                                </div>
                            </div>
                            <div id="lightingAlertWebcam" class="alert alert-warning py-1 mb-2 d-none">
                                <i class="fas fa-exclamation-triangle me-1"></i>Low lighting — please improve lighting and retry.
                            </div>
                            <p id="webcamStatusMsg" class="text-muted small mb-2">Position face clearly in frame.</p>
                            <button class="btn btn-success d-none" id="btnCaptureFace">
                                <i class="fas fa-camera me-2"></i>Capture &amp; Save
                            </button>
                            <button class="btn btn-outline-secondary ms-2" id="btnBackFromWebcam">Back</button>
                        </div>
                    </div>

                    <!-- Status -->
                    <div id="enrollStatus" class="mb-3">
                        <i id="statusIcon" class="fa-4x mb-3"></i>
                        <h5 id="statusTitle"></h5>
                        <p id="statusMsg" class="mb-3"></p>
                        <button class="btn btn-primary d-none" id="btnEnrollAnother">
                            <i class="fas fa-plus me-1"></i>Enroll Another Student
                        </button>
                    </div>

                </div>
            </div>
        </main>
    </div>
</div>

<!-- MediaPipe -->
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/face_mesh.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js"></script>
<script>
'use strict';
(function () {

let selectedStudent  = null;
let capturedDescriptor = null;
let faceMeshInstance   = null;
let cameraInstance     = null;

// ── Student search ─────────────────────────────────────────────────────────
document.getElementById('btnSearch').addEventListener('click', doSearch);
document.getElementById('studentSearch').addEventListener('keydown', e => {
    if (e.key === 'Enter') doSearch();
});

function doSearch() {
    const q = document.getElementById('studentSearch').value.trim();
    if (!q) return;
    const resultsEl = document.getElementById('searchResults');
    resultsEl.innerHTML = '<div class="text-muted small"><i class="fas fa-circle-notch fa-spin me-1"></i>Searching…</div>';

    const fd = new FormData();
    fd.append('q', q);
    fd.append('limit', '8');

    fetch('../ajax/canteen_student_search.php', { method: 'POST', body: fd })
        .then(r => r.json())
        .then(data => {
            if (!data.success || !data.students.length) {
                resultsEl.innerHTML = '<p class="text-muted small">No students found.</p>';
                return;
            }
            resultsEl.innerHTML = data.students.map(s => `
                <div class="student-card d-flex align-items-center gap-3 mb-2"
                     data-id="${s.id}" data-name="${escHtml(s.name)}" data-class="${escHtml(s.class_name)}"
                     data-code="${escHtml(s.student_code)}" data-photo="${escHtml(s.photo_url)}"
                     data-facial="${s.has_facial ? '1' : '0'}">
                    <img src="${s.photo_url || '../assets/img/no-photo.png'}" class="student-photo" alt="">
                    <div>
                        <div class="fw-semibold">${escHtml(s.name)}</div>
                        <div class="text-muted small">${escHtml(s.class_name)} · ID: ${escHtml(s.student_code)}</div>
                        ${s.has_facial ? '<span class="badge bg-info">Facial enrolled</span>' : ''}
                    </div>
                </div>
            `).join('');
            resultsEl.querySelectorAll('.student-card').forEach(card => {
                card.addEventListener('click', () => selectStudent(card.dataset));
            });
        })
        .catch(() => { resultsEl.innerHTML = '<p class="text-danger small">Search failed.</p>'; });
}

function selectStudent(data) {
    selectedStudent = { id: parseInt(data.id), name: data.name, class_name: data.class, code: data.code, photo: data.photo };
    capturedDescriptor = null;

    document.getElementById('selPhoto').src = data.photo || '../assets/img/no-photo.png';
    document.getElementById('selName').textContent  = data.name;
    document.getElementById('selClass').textContent = data.class;
    document.getElementById('selCode').textContent  = 'ID: ' + data.code;
    document.getElementById('facialAlreadyEnrolled').classList.toggle('d-none', data.facial !== '1');

    document.getElementById('consentCheck').checked = false;
    document.getElementById('btnUsePhoto').disabled  = true;
    document.getElementById('btnUseWebcam').disabled = true;

    document.getElementById('stepSearch').querySelector('.card-body').style.display = 'none';
    document.getElementById('stepConsent').classList.remove('d-none');
    [document.getElementById('stepPhoto'), document.getElementById('stepWebcam')].forEach(e => e.classList.add('d-none'));
}

document.getElementById('consentCheck').addEventListener('change', function () {
    document.getElementById('btnUsePhoto').disabled  = !this.checked || !selectedStudent?.photo;
    document.getElementById('btnUseWebcam').disabled = !this.checked;
});

document.getElementById('btnReselect').addEventListener('click', resetToSearch);

// ── Option A: Profile photo ────────────────────────────────────────────────
document.getElementById('btnUsePhoto').addEventListener('click', function () {
    if (!selectedStudent?.photo) return;
    document.getElementById('stepConsent').classList.add('d-none');
    document.getElementById('stepPhoto').classList.remove('d-none');
    document.getElementById('staticPhoto').src = selectedStudent.photo;
    runFaceMeshOnImage(selectedStudent.photo);
});

document.getElementById('btnBackFromPhoto').addEventListener('click', function () {
    capturedDescriptor = null;
    document.getElementById('stepPhoto').classList.add('d-none');
    document.getElementById('stepConsent').classList.remove('d-none');
    document.getElementById('btnConfirmDescriptor').classList.add('d-none');
    document.getElementById('faceStatusMsg').textContent = 'Initialising face detection…';
});

document.getElementById('btnConfirmDescriptor').addEventListener('click', async function () {
    if (!capturedDescriptor || !selectedStudent) return;
    await saveDescriptor(capturedDescriptor);
});

// ── Option B: Webcam ───────────────────────────────────────────────────────
document.getElementById('btnUseWebcam').addEventListener('click', function () {
    document.getElementById('stepConsent').classList.add('d-none');
    document.getElementById('stepWebcam').classList.remove('d-none');
    startWebcamCapture();
});

document.getElementById('btnBackFromWebcam').addEventListener('click', function () {
    stopWebcam();
    capturedDescriptor = null;
    document.getElementById('stepWebcam').classList.add('d-none');
    document.getElementById('stepConsent').classList.remove('d-none');
});

document.getElementById('btnCaptureFace').addEventListener('click', async function () {
    if (!capturedDescriptor || !selectedStudent) return;
    stopWebcam();
    await saveDescriptor(capturedDescriptor);
});

// ── MediaPipe on static image ──────────────────────────────────────────────
function runFaceMeshOnImage(imgSrc) {
    const overlay  = document.getElementById('faceOverlay');
    const statusEl = document.getElementById('faceStatusMsg');
    const confirmBtn = document.getElementById('btnConfirmDescriptor');
    overlay.style.display = 'flex';
    overlay.innerHTML = '<span><i class="fas fa-circle-notch fa-spin me-2"></i>Detecting face…</span>';

    const faceMesh = new FaceMesh({
        locateFile: file => `https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${file}`
    });
    faceMesh.setOptions({
        maxNumFaces: 1,
        refineLandmarks: false,
        minDetectionConfidence: 0.5,
        minTrackingConfidence: 0.5,
    });

    faceMesh.onResults(results => {
        if (!results.multiFaceLandmarks || results.multiFaceLandmarks.length === 0) {
            overlay.innerHTML = '<span class="text-warning"><i class="fas fa-exclamation-triangle me-2"></i>No face detected. Please use the webcam option.</span>';
            statusEl.textContent = 'No face found in profile photo.';
            return;
        }

        const landmarks = results.multiFaceLandmarks[0];
        capturedDescriptor = landmarks.map(lm => ({ x: lm.x, y: lm.y, z: lm.z }));

        // Draw dots on canvas
        drawLandmarks(document.getElementById('faceCanvas'), landmarks,
            document.getElementById('staticPhoto').naturalWidth || 400,
            document.getElementById('staticPhoto').naturalHeight || 300);

        overlay.style.display = 'none';
        statusEl.textContent = '✓ Face detected — ' + capturedDescriptor.length + ' landmarks. Confirm to save.';
        confirmBtn.classList.remove('d-none');
    });

    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => faceMesh.send({ image: img });
    img.onerror = () => {
        overlay.innerHTML = '<span class="text-danger">Could not load photo. Use webcam instead.</span>';
    };
    img.src = imgSrc;
}

// ── MediaPipe on webcam stream ─────────────────────────────────────────────
function startWebcamCapture() {
    const video   = document.getElementById('faceVideo');
    const canvas  = document.getElementById('faceLandmarks');
    const overlay = document.getElementById('faceOverlay2');
    const statusEl = document.getElementById('webcamStatusMsg');
    const captureBtn = document.getElementById('btnCaptureFace');

    overlay.style.display = 'flex';
    overlay.innerHTML = '<span><i class="fas fa-circle-notch fa-spin me-2"></i>Starting camera…</span>';

    faceMeshInstance = new FaceMesh({
        locateFile: file => `https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/${file}`
    });
    faceMeshInstance.setOptions({
        maxNumFaces: 1,
        refineLandmarks: false,
        minDetectionConfidence: 0.5,
        minTrackingConfidence: 0.5,
    });

    let frameCount = 0;
    faceMeshInstance.onResults(results => {
        frameCount++;

        // Lighting check every 30 frames
        if (frameCount % 30 === 0) checkLighting(video);

        if (!results.multiFaceLandmarks || results.multiFaceLandmarks.length === 0) {
            overlay.style.display = 'flex';
            overlay.innerHTML = '<span>Position your face clearly in the frame</span>';
            captureBtn.classList.add('d-none');
            capturedDescriptor = null;
            return;
        }

        const landmarks = results.multiFaceLandmarks[0];
        capturedDescriptor = landmarks.map(lm => ({ x: lm.x, y: lm.y, z: lm.z }));

        drawLandmarks(canvas, landmarks, video.videoWidth, video.videoHeight);
        overlay.style.display = 'none';
        statusEl.textContent = '✓ Face detected — tap Capture to save.';
        captureBtn.classList.remove('d-none');
    });

    cameraInstance = new Camera(video, {
        onFrame: async () => {
            if (video.readyState >= 2) {
                await faceMeshInstance.send({ image: video });
            }
        },
        width: 640, height: 480,
    });
    cameraInstance.start().then(() => {
        overlay.style.display = 'none';
    }).catch(() => {
        overlay.innerHTML = '<span class="text-danger">Camera failed to start.</span>';
    });
}

function stopWebcam() {
    if (cameraInstance) { cameraInstance.stop(); cameraInstance = null; }
    if (faceMeshInstance) { faceMeshInstance.close(); faceMeshInstance = null; }
    const video = document.getElementById('faceVideo');
    if (video.srcObject) { video.srcObject.getTracks().forEach(t => t.stop()); video.srcObject = null; }
}

// ── Lighting check ─────────────────────────────────────────────────────────
function checkLighting(video) {
    const cvs = document.createElement('canvas');
    cvs.width  = Math.floor(video.videoWidth  / 4);
    cvs.height = Math.floor(video.videoHeight / 4);
    const ctx  = cvs.getContext('2d');
    ctx.drawImage(video, 0, 0, cvs.width, cvs.height);
    const data = ctx.getImageData(0, 0, cvs.width, cvs.height).data;
    let sum = 0;
    for (let i = 0; i < data.length; i += 4) {
        sum += 0.299 * data[i] + 0.587 * data[i+1] + 0.114 * data[i+2];
    }
    const avg = sum / (data.length / 4);
    document.getElementById('lightingAlertWebcam').classList.toggle('d-none', avg >= 60);
}

// ── Draw MediaPipe dots ────────────────────────────────────────────────────
function drawLandmarks(canvas, landmarks, w, h) {
    canvas.width  = w;
    canvas.height = h;
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, w, h);
    ctx.fillStyle = 'rgba(76,175,80,0.7)';
    landmarks.forEach(lm => {
        ctx.beginPath();
        ctx.arc(lm.x * w, lm.y * h, 1.5, 0, Math.PI * 2);
        ctx.fill();
    });
}

// ── Save descriptor to server ──────────────────────────────────────────────
async function saveDescriptor(descriptor) {
    if (!descriptor || !selectedStudent) return;
    showStatus('working', 'fas fa-circle-notch fa-spin text-warning', 'Saving…', 'Sending facial data to server…');

    const fd = new FormData();
    fd.append('student_id',  selectedStudent.id);
    fd.append('descriptor',  JSON.stringify(descriptor));

    try {
        const resp = await fetch('../ajax/canteen_facial_enroll.php', {
            method: 'POST', credentials: 'same-origin', body: fd
        });
        const data = await resp.json();
        if (data.success) {
            showStatus('success', 'fas fa-check-circle text-success', 'Facial Data Saved!', data.message, true);
        } else {
            showStatus('error', 'fas fa-times-circle text-danger', 'Enrollment failed', data.message);
        }
    } catch {
        showStatus('error', 'fas fa-times-circle text-danger', 'Network error', 'Please try again.');
    }
}

function showStatus(type, iconClass, title, msg, showAnother = false) {
    const el = document.getElementById('enrollStatus');
    el.className = type;
    el.style.display = 'block';
    document.getElementById('statusIcon').className = iconClass + ' fa-4x mb-3';
    document.getElementById('statusTitle').textContent = title;
    document.getElementById('statusMsg').textContent   = msg;
    document.getElementById('btnEnrollAnother').classList.toggle('d-none', !showAnother);
    ['stepPhoto', 'stepWebcam', 'stepConsent', 'stepSearch'].forEach(id => {
        document.getElementById(id).classList.add('d-none');
    });
}

document.getElementById('btnEnrollAnother').addEventListener('click', resetToSearch);

function resetToSearch() {
    selectedStudent = null;
    capturedDescriptor = null;
    stopWebcam();
    document.getElementById('enrollStatus').style.display = 'none';
    document.getElementById('stepConsent').classList.add('d-none');
    document.getElementById('stepPhoto').classList.add('d-none');
    document.getElementById('stepWebcam').classList.add('d-none');
    document.getElementById('stepSearch').querySelector('.card-body').style.removeProperty('display');
    document.getElementById('stepSearch').classList.remove('d-none');
    document.getElementById('searchResults').innerHTML = '';
    document.getElementById('studentSearch').value = '';
    document.getElementById('studentSearch').focus();
}

function escHtml(s) {
    return String(s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[c]);
}

})();
</script>
</body>
</html>
