<?php
declare(strict_types=1);

require_once __DIR__ . '/csrf.php';

const ADMIN_REMEMBER_COOKIE = 'admin_remember';
const ADMIN_REMEMBER_TTL    = 120 * 24 * 60 * 60; // 120 days

function admin_cookie_path(): string {
  $base = rtrim((string)($GLOBALS['BASE_PATH'] ?? ''), '/');
  return $base ? $base . '/' : '/';
}

function admin_ensure_remember_table(): void {
  static $done = false;
  if ($done) return;

  try {
    pdo()->exec("
      CREATE TABLE IF NOT EXISTS admin_remember_tokens (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        admin_id INT UNSIGNED NOT NULL,
        selector CHAR(24) NOT NULL UNIQUE,
        token_hash CHAR(64) NOT NULL,
        expires_at INT UNSIGNED NOT NULL,
        created_at INT UNSIGNED NOT NULL,
        INDEX idx_admin_expires (admin_id, expires_at)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
    ");
  } catch (Throwable $e) {
    // fail silently; remember-me stays disabled
  }

  $done = true;
}

function admin_clear_remember_cookie(): void {
  setcookie(ADMIN_REMEMBER_COOKIE, '', [
    'expires'  => time() - 3600,
    'path'     => admin_cookie_path(),
    'secure'   => is_https(),
    'httponly' => true,
    'samesite' => 'Lax',
  ]);
  unset($_COOKIE[ADMIN_REMEMBER_COOKIE]);
}

function admin_delete_remember_tokens(?int $adminId = null, ?string $selector = null): void {
  admin_ensure_remember_table();

  $now = time();
  $sql = '';
  $args = [];

  if ($selector !== null) {
    $sql  = "DELETE FROM admin_remember_tokens WHERE selector = ?";
    $args = [$selector];
  } elseif ($adminId !== null) {
    $sql  = "DELETE FROM admin_remember_tokens WHERE admin_id = ? OR expires_at < ?";
    $args = [$adminId, $now];
  } else {
    $sql  = "DELETE FROM admin_remember_tokens WHERE expires_at < ?";
    $args = [$now];
  }

  try {
    pdo()->prepare($sql)->execute($args);
  } catch (Throwable $e) {
    // ignore cleanup issues
  }
}

function admin_issue_remember_token(int $adminId): void {
  if ($adminId <= 0) return;

  admin_delete_remember_tokens($adminId);

  $selector = bin2hex(random_bytes(12));  // 24 chars, indexed lookup
  $token    = bin2hex(random_bytes(32));  // 64 chars secret
  $hash     = hash('sha256', $token);
  $expires  = time() + ADMIN_REMEMBER_TTL;

  try {
    pdo()->prepare("
      INSERT INTO admin_remember_tokens (admin_id, selector, token_hash, expires_at, created_at)
      VALUES (?, ?, ?, ?, ?)
    ")->execute([$adminId, $selector, $hash, $expires, time()]);
  } catch (Throwable $e) {
    return;
  }

  $cookieVal = $selector . ':' . $token;
  setcookie(ADMIN_REMEMBER_COOKIE, $cookieVal, [
    'expires'  => $expires,
    'path'     => admin_cookie_path(),
    'secure'   => is_https(),
    'httponly' => true,
    'samesite' => 'Lax',
  ]);
  $_COOKIE[ADMIN_REMEMBER_COOKIE] = $cookieVal;
}

function admin_start_session(array $adminRow): void {
  if (session_status() === PHP_SESSION_ACTIVE) {
    session_regenerate_id(true);
  }
  $_SESSION['admin_id']   = (int)($adminRow['id'] ?? 0);
  $_SESSION['admin_user'] = (string)($adminRow['username'] ?? '');
}

function admin_forget_remember_me(): void {
  $selector = null;
  $cookie   = (string)($_COOKIE[ADMIN_REMEMBER_COOKIE] ?? '');
  if (strpos($cookie, ':') !== false) {
    [$selector] = explode(':', $cookie, 2);
  }

  if ($selector) {
    admin_delete_remember_tokens(null, $selector);
  }
  if (!empty($_SESSION['admin_id'])) {
    admin_delete_remember_tokens((int)$_SESSION['admin_id']);
  } else {
    admin_delete_remember_tokens();
  }

  admin_clear_remember_cookie();
}

function admin_try_remember_login(): bool {
  static $checked = false;
  if ($checked) return !empty($_SESSION['admin_id']);
  $checked = true;

  $cookie = (string)($_COOKIE[ADMIN_REMEMBER_COOKIE] ?? '');
  if ($cookie === '' || strpos($cookie, ':') === false) return false;

  [$selector, $token] = explode(':', $cookie, 2);
  if ($selector === '' || $token === '') {
    admin_clear_remember_cookie();
    return false;
  }

  // guard against oversized/invalid payloads before hitting DB
  if (!preg_match('/^[a-f0-9]{24}$/i', $selector) || !preg_match('/^[a-f0-9]{64}$/i', $token)) {
    admin_clear_remember_cookie();
    return false;
  }

  admin_delete_remember_tokens(); // prune expired

  try {
    $st = pdo()->prepare("SELECT admin_id, token_hash, expires_at FROM admin_remember_tokens WHERE selector = ? LIMIT 1");
    $st->execute([$selector]);
    $row = $st->fetch();
  } catch (Throwable $e) {
    return false;
  }

  if (!$row) {
    admin_clear_remember_cookie();
    return false;
  }

  if ((int)$row['expires_at'] < time()) {
    admin_delete_remember_tokens(null, $selector);
    admin_clear_remember_cookie();
    return false;
  }

  $expected = (string)($row['token_hash'] ?? '');
  if (!hash_equals($expected, hash('sha256', $token))) {
    admin_delete_remember_tokens(null, $selector);
    admin_clear_remember_cookie();
    return false;
  }

  try {
    $u = pdo()->prepare("SELECT id, username FROM admin_users WHERE id = ? LIMIT 1");
    $u->execute([(int)$row['admin_id']]);
    $adminRow = $u->fetch() ?: [];
  } catch (Throwable $e) {
    return false;
  }

  if (empty($adminRow)) {
    admin_delete_remember_tokens(null, $selector);
    admin_clear_remember_cookie();
    return false;
  }

  admin_start_session($adminRow);
  admin_issue_remember_token((int)$adminRow['id']); // rotate token after successful auto-login
  return true;
}

function admin_is_logged_in(): bool {
  if (!empty($_SESSION['admin_id'])) return true;
  return admin_try_remember_login();
}

function admin_login(array $adminRow, bool $remember = false): void {
  admin_start_session($adminRow);
  if ($remember) {
    admin_issue_remember_token((int)$_SESSION['admin_id']);
  } else {
    admin_forget_remember_me();
  }
}

function admin_logout(): void {
  admin_forget_remember_me();
  unset($_SESSION['admin_id'], $_SESSION['admin_user']);
}

function require_admin_login(): void {
  if (!admin_is_logged_in()) {
    header('Location: ' . url_path('/public/admin/login.php'));
    exit;
  }
}

// Optional: normal site users (not admin panel)
function user_is_logged_in(): bool {
  return !empty($_SESSION['uid']);
}
function user_login(array $user): void {
  if (session_status() === PHP_SESSION_ACTIVE) {
    session_regenerate_id(true);
  }
  $_SESSION['uid'] = (int)($user['id'] ?? 0);
}
function user_logout(): void {
  unset($_SESSION['uid']);
}
function require_user_login(): void {
  if (!user_is_logged_in()) {
    header('Location: ' . url_path('/login.php'));
    exit;
  }
}
