<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Content-Type: application/json; charset=utf-8");

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }

ini_set('display_errors', 0);
error_reporting(0);

// Force PHP to UTC so strtotime() of MySQL TIMESTAMP columns
// matches time(). Otherwise host-local timezone drift (e.g. UTC+6)
// makes every freshly-issued token instantly look "expired".
date_default_timezone_set('UTC');

const SESSION_TIMEOUT_SECONDS = 1800;

// Database credentials can be supplied in either of these ways:
// 1) Server-side environment variables: DB_HOST, DB_USER, DB_PASS, DB_NAME
// 2) A private api/db.local.php file returning the same values as an array.
//    This fallback is for shared/cPanel hosting where SetEnv/getenv may be disabled.
$host = getenv('DB_HOST') ?: '';
$user = getenv('DB_USER') ?: '';
$pass = getenv('DB_PASS') ?: '';
$db   = getenv('DB_NAME') ?: '';

$localConfigPath = __DIR__ . '/db.local.php';
if ((!$host || !$user || !$db) && is_readable($localConfigPath)) {
    $local = include $localConfigPath;
    if (is_array($local)) {
        $host = $host ?: (string)($local['DB_HOST'] ?? '');
        $user = $user ?: (string)($local['DB_USER'] ?? '');
        $pass = $pass ?: (string)($local['DB_PASS'] ?? '');
        $db   = $db   ?: (string)($local['DB_NAME'] ?? '');
    }
}

if (!$host || !$user || !$db) {
    http_response_code(500);
    echo json_encode([
        "error" => "Database not configured",
        "hint" => "Set DB_HOST, DB_USER, DB_PASS, DB_NAME in hosting env/.htaccess, or create api/db.local.php from db.local.example.php."
    ]);
    exit;
}

$conn = new mysqli($host, $user, $pass, $db);
if ($conn->connect_error) {
    http_response_code(500);
    echo json_encode(["error" => "DB connection failed", "hint" => "Check DB_HOST, DB_USER, DB_PASS, DB_NAME values and MySQL user permissions."]);
    exit;
}
$conn->set_charset("utf8mb4");
// Align MySQL session clock with PHP (UTC) so NOW() and strtotime() agree.
@$conn->query("SET time_zone = '+00:00'");

function e($str) { return htmlspecialchars($str ?? '', ENT_QUOTES, 'UTF-8'); }

function json_response($data, $code = 200) {
    http_response_code($code);
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
    exit;
}

function get_input() {
    return json_decode(file_get_contents("php://input"), true) ?? [];
}

function get_authorization_header() {
    if (function_exists('getallheaders')) {
        foreach (getallheaders() as $key => $value) {
            if (strtolower($key) === 'authorization') {
                return trim((string)$value);
            }
        }
    }

    $serverKeys = ['HTTP_AUTHORIZATION', 'REDIRECT_HTTP_AUTHORIZATION', 'Authorization'];
    foreach ($serverKeys as $key) {
        if (!empty($_SERVER[$key])) {
            return trim((string)$_SERVER[$key]);
        }
    }

    return '';
}

function extract_bearer_token() {
    $authHeader = get_authorization_header();
    if (!$authHeader) return '';

    if (preg_match('/Bearer\s+(\S+)/i', $authHeader, $matches)) {
        return trim($matches[1]);
    }

    return trim($authHeader);
}

function verify_token($conn) {
    $token = extract_bearer_token();

    if (!$token) {
        json_response(["error" => "No token provided"], 401);
    }

    $stmt = $conn->prepare("SELECT id, full_name, username, role, user_image, token, last_activity FROM admin_users WHERE token = ? LIMIT 1");
    $stmt->bind_param("s", $token);
    $stmt->execute();
    $result = $stmt->get_result();
    $user = $result->fetch_assoc();
    $stmt->close();

    if (!$user) {
        json_response(["error" => "Invalid token"], 401);
    }

    $lastActivityTs = !empty($user['last_activity']) ? strtotime($user['last_activity']) : 0;
    if ($lastActivityTs > 0 && (time() - $lastActivityTs) > SESSION_TIMEOUT_SECONDS) {
        $clear = $conn->prepare("UPDATE admin_users SET token = NULL WHERE id = ? AND token = ?");
        $clear->bind_param("is", $user['id'], $token);
        $clear->execute();
        $clear->close();
        json_response(["error" => "Session expired"], 401);
    }

    $touch = $conn->prepare("UPDATE admin_users SET last_activity = NOW() WHERE id = ?");
    $touch->bind_param("i", $user['id']);
    $touch->execute();
    $touch->close();

    return [
        'id' => (int)$user['id'],
        'full_name' => $user['full_name'],
        'username' => $user['username'],
        'role' => $user['role'],
        'user_image' => $user['user_image'] ?? '',
        'token' => $token,
    ];
}

function generate_token($length = 64) {
    return bin2hex(random_bytes($length / 2));
}

/**
 * Insert a notification row. Safe to call from anywhere — silently swallows
 * errors so a bad notify() never breaks the user's primary action.
 *
 * @param mysqli      $conn
 * @param string      $category   e.g. 'student' | 'teacher' | 'staff' | 'admin'
 *                                | 'message' | 'notice' | 'result' | 'invoice'
 *                                | 'gallery' | 'reset' | 'system'
 * @param string      $title      short headline
 * @param string|null $message    longer detail
 * @param string|null $actor      who did it (admin username, or 'public')
 * @param string|null $link       optional deep-link path
 */
function notify(mysqli $conn, string $category, string $title, ?string $message = null, ?string $actor = null, ?string $link = null): void {
    try {
        $stmt = $conn->prepare("INSERT INTO notifications (category, title, message, actor, link, is_read, created_at) VALUES (?, ?, ?, ?, ?, 0, NOW())");
        if (!$stmt) return;
        $stmt->bind_param("sssss", $category, $title, $message, $actor, $link);
        $stmt->execute();
        $stmt->close();
    } catch (Throwable $e) {
        // never propagate notification failures
    }
}

/**
 * Best-effort lookup of the current admin's username for use as `actor`.
 * Returns null if no valid bearer token is present.
 */
function current_actor(mysqli $conn): ?string {
    $token = extract_bearer_token();
    if (!$token) return null;
    $stmt = $conn->prepare("SELECT username FROM admin_users WHERE token = ? LIMIT 1");
    if (!$stmt) return null;
    $stmt->bind_param("s", $token);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc();
    $stmt->close();
    return $row['username'] ?? null;
}
?>