<?php
/** Biometric attendance — management AJAX. */
if (session_status() === PHP_SESSION_NONE) session_start();
header('Content-Type: application/json');

require_once __DIR__ . '/../../config.php';
if (!isset($_SESSION['user_id'])) { http_response_code(401); echo json_encode(['success' => false, 'message' => 'Not signed in.']); exit; }
requireModule('biometric_attendance', true);
require_once __DIR__ . '/../../includes/biometric_lib.php';

$role = $_SESSION['role'] ?? '';
if (!biometric_can_manage($role)) { http_response_code(403); echo json_encode(['success' => false, 'message' => 'Not permitted.']); exit; }

$conn = getDBConnection();
biometric_ensure_tables($conn);
$uid = (int) $_SESSION['user_id'];
$action = $_POST['action'] ?? $_GET['action'] ?? '';
function b_out($p){ echo json_encode($p); exit; }

switch ($action) {

    case 'devices_list': {
        $rows = [];
        $res = $conn->query("SELECT * FROM biometric_devices ORDER BY name");
        while ($res && $r = $res->fetch_assoc()) $rows[] = $r;
        b_out(['success' => true, 'data' => $rows, 'recommended' => biometric_recommended_devices()]);
    }

    case 'save_device': {
        $id     = (int) ($_POST['id'] ?? 0);
        $name   = trim($_POST['name'] ?? '');
        $serial = trim($_POST['serial_number'] ?? '');
        $type   = $_POST['device_type'] ?? 'fingerprint';
        $conn2  = $_POST['connection'] ?? 'wired';
        $ip     = trim($_POST['ip_address'] ?? '') ?: null;
        $loc    = trim($_POST['location'] ?? '') ?: null;
        $dir    = $_POST['direction'] ?? 'auto';
        $active = !empty($_POST['active']) ? 1 : 0;
        if ($name === '' || $serial === '') b_out(['success' => false, 'message' => 'Name and serial number are required.']);
        if (!in_array($type, ['fingerprint', 'face', 'hybrid'], true)) $type = 'fingerprint';
        if (!in_array($conn2, ['wired', 'wireless'], true)) $conn2 = 'wired';
        if (!in_array($dir, ['in', 'out', 'auto'], true)) $dir = 'auto';

        if ($id > 0) {
            $stmt = $conn->prepare("UPDATE biometric_devices SET name=?, serial_number=?, device_type=?, connection=?, ip_address=?, location=?, direction=?, active=? WHERE id=?");
            $stmt->bind_param('sssssssii', $name, $serial, $type, $conn2, $ip, $loc, $dir, $active, $id);
        } else {
            $stmt = $conn->prepare("INSERT INTO biometric_devices (name, serial_number, device_type, connection, ip_address, location, direction, active) VALUES (?,?,?,?,?,?,?,?)");
            $stmt->bind_param('sssssssi', $name, $serial, $type, $conn2, $ip, $loc, $dir, $active);
        }
        if (!$stmt->execute()) { $e = $stmt->error; $stmt->close(); b_out(['success' => false, 'message' => 'Save failed (serial may already exist): ' . $e]); }
        $stmt->close();
        b_out(['success' => true, 'message' => 'Device saved.']);
    }

    case 'delete_device': {
        $id = (int) ($_POST['id'] ?? 0);
        $conn->query("DELETE FROM biometric_devices WHERE id=$id");
        b_out(['success' => true, 'message' => 'Device removed.']);
    }

    case 'search_persons': {
        $q = trim($_GET['q'] ?? $_POST['q'] ?? '');
        $like = '%' . $q . '%';
        $out = [];
        $st = $conn->prepare("SELECT id, first_name, last_name, class FROM students WHERE status='active' AND (CONCAT(first_name,' ',last_name) LIKE ? OR student_id LIKE ?) ORDER BY first_name LIMIT 15");
        $st->bind_param('ss', $like, $like); $st->execute(); $r = $st->get_result();
        while ($row = $r->fetch_assoc()) $out[] = ['type' => 'student', 'id' => $row['id'], 'label' => $row['first_name'] . ' ' . $row['last_name'] . ' (' . $row['class'] . ')'];
        $st->close();
        $st = $conn->prepare("SELECT id, full_name FROM staff WHERE full_name LIKE ? ORDER BY full_name LIMIT 10");
        $st->bind_param('s', $like); $st->execute(); $r = $st->get_result();
        while ($row = $r->fetch_assoc()) $out[] = ['type' => 'staff', 'id' => $row['id'], 'label' => $row['full_name'] . ' (staff)'];
        $st->close();
        b_out(['success' => true, 'data' => $out]);
    }

    case 'enroll_fingerprint': {
        $ptype = $_POST['person_type'] ?? 'student';
        $pid   = (int) ($_POST['person_id'] ?? 0);
        $pname = trim($_POST['person_name'] ?? '');
        $devUserId = trim($_POST['device_user_id'] ?? '');
        $deviceId  = (int) ($_POST['device_id'] ?? 0) ?: null;
        if (!in_array($ptype, ['student', 'staff'], true)) $ptype = 'student';
        if (!$pid || $devUserId === '') b_out(['success' => false, 'message' => 'Select a person and enter the device user ID.']);
        $stmt = $conn->prepare("INSERT INTO biometric_enrollments (person_type, person_id, person_name, method, device_user_id, device_id, enrolled_by)
                                VALUES (?,?,?, 'fingerprint', ?,?,?)");
        $stmt->bind_param('sissii', $ptype, $pid, $pname, $devUserId, $deviceId, $uid);
        $stmt->execute(); $stmt->close();
        b_out(['success' => true, 'message' => 'Fingerprint mapping enrolled.']);
    }

    case 'enroll_face': {
        $ptype = $_POST['person_type'] ?? 'student';
        $pid   = (int) ($_POST['person_id'] ?? 0);
        $pname = trim($_POST['person_name'] ?? '');
        $desc  = trim($_POST['descriptor'] ?? '');
        if (!in_array($ptype, ['student', 'staff'], true)) $ptype = 'student';
        $arr = json_decode($desc, true);
        if (!$pid || !is_array($arr) || count($arr) < 100) b_out(['success' => false, 'message' => 'Capture a valid face first.']);
        $clean = json_encode(array_map(fn($p) => ['x' => (float) $p['x'], 'y' => (float) $p['y'], 'z' => (float) ($p['z'] ?? 0)], $arr));
        $stmt = $conn->prepare("INSERT INTO biometric_enrollments (person_type, person_id, person_name, method, face_descriptor, enrolled_by)
                                VALUES (?,?,?, 'face', ?,?)");
        $stmt->bind_param('sissi', $ptype, $pid, $pname, $clean, $uid);
        $stmt->execute(); $stmt->close();
        b_out(['success' => true, 'message' => 'Face enrolled.']);
    }

    case 'enrollments_list': {
        $rows = [];
        $res = $conn->query("SELECT id, person_type, person_id, person_name, method, device_user_id, enrolled_at
                             FROM biometric_enrollments ORDER BY id DESC LIMIT 200");
        while ($res && $r = $res->fetch_assoc()) $rows[] = $r;
        b_out(['success' => true, 'data' => $rows]);
    }

    case 'delete_enrollment': {
        $id = (int) ($_POST['id'] ?? 0);
        $conn->query("DELETE FROM biometric_enrollments WHERE id=$id");
        b_out(['success' => true, 'message' => 'Enrollment removed.']);
    }

    case 'punches_list': {
        $rows = [];
        $res = $conn->query("SELECT p.*, d.name AS device_name FROM biometric_punches p
                             LEFT JOIN biometric_devices d ON d.id=p.device_id
                             ORDER BY p.id DESC LIMIT 100");
        while ($res && $r = $res->fetch_assoc()) $rows[] = $r;
        b_out(['success' => true, 'data' => $rows]);
    }

    // Manually assign an unmatched punch to a person and write attendance.
    case 'assign_punch': {
        $id    = (int) ($_POST['punch_id'] ?? 0);
        $ptype = $_POST['person_type'] ?? 'student';
        $pid   = (int) ($_POST['person_id'] ?? 0);
        if (!$id || !$pid) b_out(['success' => false, 'message' => 'Punch and person required.']);
        $p = $conn->query("SELECT * FROM biometric_punches WHERE id=$id")->fetch_assoc();
        if (!$p) b_out(['success' => false, 'message' => 'Punch not found.']);
        $written = 0;
        if ($ptype === 'student') $written = biometric_write_attendance($conn, $pid, substr($p['punch_time'], 0, 10)) ? 1 : 0;
        $stmt = $conn->prepare("UPDATE biometric_punches SET person_type=?, person_id=?, matched=1, attendance_written=? WHERE id=?");
        $stmt->bind_param('siii', $ptype, $pid, $written, $id);
        $stmt->execute(); $stmt->close();
        b_out(['success' => true, 'message' => 'Punch assigned' . ($written ? ' and attendance marked.' : '.')]);
    }

    // Browser kiosk: match a captured face and record the punch.
    case 'kiosk_match': {
        $desc = json_decode(trim($_POST['descriptor'] ?? ''), true);
        if (!is_array($desc) || count($desc) < 100) b_out(['success' => false, 'message' => 'No face captured.']);
        $match = biometric_match_face($conn, $desc);
        if (!$match) {
            biometric_record_punch($conn, null, 'kiosk', null, 'face', 'in', date('Y-m-d H:i:s'), 'kiosk');
            b_out(['success' => false, 'message' => 'Face not recognised. Please enrol first or try again.']);
        }
        biometric_record_punch($conn, null, 'kiosk', $match, 'face', 'in', date('Y-m-d H:i:s'), 'kiosk');
        b_out(['success' => true, 'message' => 'Welcome, ' . $match['person_name'] . '! Marked present.', 'person' => $match]);
    }

    default:
        b_out(['success' => false, 'message' => 'Unknown action.']);
}
