<?php
/**
 * Arrow scaffold shared helpers: trivial-but-real session auth + atomic JSON IO.
 * MVP-grade. Not Fort Knox, but no obvious RCE: image-only uploads, atomic writes,
 * password-gated admin, output always escaped at the template.
 */

require_once __DIR__ . '/config.php';

/* mb_substr may be unavailable on minimal hosts; fall back to substr. */
function arrow_trunc($s, $len) {
    $s = (string)$s;
    if (function_exists('mb_substr')) { return mb_substr($s, 0, $len, 'UTF-8'); }
    return substr($s, 0, $len);
}


/* ------------------------------------------------------------------ paths */
function arrow_data_path($name) {
    return __DIR__ . '/data/' . basename($name);
}
function arrow_img_dir() {
    return __DIR__ . '/assets/img';
}

/* ------------------------------------------------------------- atomic JSON */
function arrow_read_json($path, $default = []) {
    if (!is_file($path)) return $default;
    $raw = file_get_contents($path);
    $val = json_decode($raw, true);
    return is_array($val) ? $val : $default;
}

function arrow_write_json($path, $data) {
    $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    $tmp  = $path . '.tmp.' . getmypid();
    if (file_put_contents($tmp, $json, LOCK_EX) === false) return false;
    return rename($tmp, $path); // atomic on same filesystem
}

/* -------------------------------------------------------------------- auth */
function arrow_require_login() {
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }
    $err = '';
    if (($_POST['_action'] ?? '') === 'login') {
        if (hash_equals(ARROW_ADMIN_PASSWORD, (string)($_POST['password'] ?? ''))) {
            $_SESSION['arrow_admin'] = true;
        } else {
            $err = 'Wrong password.';
        }
    }
    if (($_GET['logout'] ?? '') === '1') {
        $_SESSION = [];
        session_destroy();
        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
        exit;
    }
    if (empty($_SESSION['arrow_admin'])) {
        arrow_login_form($err);
        exit;
    }
}

function arrow_login_form($err = '') {
    header('Content-Type: text/html; charset=UTF-8');
    $e = $err ? '<p style="color:#b00;margin:0 0 12px">' . htmlspecialchars($err) . '</p>' : '';
    echo <<<HTML
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Arrow Admin — Sign in</title>
<style>
 body{font-family:system-ui,sans-serif;background:#0F4C5C;display:grid;place-items:center;min-height:100vh;margin:0}
 form{background:#fff;padding:32px;border-radius:10px;box-shadow:0 8px 40px rgba(0,0,0,.3);width:min(360px,90vw)}
 h1{font-size:1.2rem;margin:0 0 16px;color:#1C2326}
 input{width:100%;padding:12px;border:1px solid #ccc;border-radius:6px;font-size:1rem;margin-bottom:12px}
 button{width:100%;padding:12px;background:#D68910;color:#1C2326;font-weight:700;border:0;border-radius:6px;font-size:1rem;cursor:pointer}
</style></head><body>
<form method="post"><h1>Arrow Admin</h1>{$e}
<input type="password" name="password" placeholder="Admin password" autofocus required>
<input type="hidden" name="_action" value="login">
<button type="submit">Sign in</button></form>
</body></html>
HTML;
}

/* --------------------------------------------------------------- CSRF-lite */
function arrow_csrf_token() {
    if (session_status() === PHP_SESSION_NONE) session_start();
    if (empty($_SESSION['arrow_csrf'])) {
        $_SESSION['arrow_csrf'] = bin2hex(random_bytes(16));
    }
    return $_SESSION['arrow_csrf'];
}
function arrow_csrf_check() {
    if (session_status() === PHP_SESSION_NONE) session_start();
    $ok = isset($_POST['_csrf']) && isset($_SESSION['arrow_csrf'])
        && hash_equals($_SESSION['arrow_csrf'], (string)$_POST['_csrf']);
    if (!$ok) { http_response_code(400); exit('Bad CSRF token. Reload the page.'); }
}

/* ------------------------------------------------------------ image upload */
function arrow_handle_image_upload($field) {
    if (empty($_FILES[$field]) || $_FILES[$field]['error'] !== UPLOAD_ERR_OK) return null;
    $tmp  = $_FILES[$field]['tmp_name'];
    $size = $_FILES[$field]['size'];
    if ($size <= 0 || $size > 8 * 1024 * 1024) return null; // 8MB cap

    // Validate it is really an image (not just by extension).
    $info = @getimagesize($tmp);
    if ($info === false) return null;
    $allowed = [
        IMAGETYPE_JPEG => 'jpg',
        IMAGETYPE_PNG  => 'png',
        IMAGETYPE_WEBP => 'webp',
        IMAGETYPE_GIF  => 'gif',
    ];
    if (!isset($allowed[$info[2]])) return null;
    $ext = $allowed[$info[2]];

    $name = 'up-' . date('Ymd-His') . '-' . bin2hex(random_bytes(3)) . '.' . $ext;
    $dest = arrow_img_dir() . '/' . $name;
    if (!move_uploaded_file($tmp, $dest)) return null;
    @chmod($dest, 0644);
    return [
        'src' => 'assets/img/' . $name,
        'w'   => (int)$info[0],
        'h'   => (int)$info[1],
    ];
}
