<?php
declare(strict_types=1);

function csrf_token(): string {
  if (empty($_SESSION['csrfToken']) || !is_string($_SESSION['csrfToken'])) {
    $_SESSION['csrfToken'] = bin2hex(random_bytes(16));
  }
  return $_SESSION['csrfToken'];
}

function reply(array $data, int $status = 200): never {
  if (session_status() === PHP_SESSION_ACTIVE && !isset($data['csrfToken'])) {
    $data['csrfToken'] = csrf_token();
  }
  http_response_code($status);
  echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
  exit;
}

function body(): array {
  $json = json_decode(file_get_contents('php://input') ?: '', true);
  return is_array($json) ? $json : $_POST;
}

function csrf_request_token(array $data): string {
  $header = (string)($_SERVER['HTTP_X_CSRF_TOKEN'] ?? '');
  if ($header !== '') return $header;
  return (string)($data['csrfToken'] ?? '');
}

function csrf_free_actions(): array {
  return [
    'state' => true,
    'login' => true,
    'register' => true,
    'managerSetup' => true,
    'managerNewGameSetup' => true,
    'managerSaveList' => true,
    'managerTeamDetails' => true,
    'browseTeamDetails' => true,
    'clientDebugLog' => true,
  ];
}

function validate_request_method_and_csrf(string $action, array $data): void {
  if ($action === 'version') return;
  if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
    reply(['ok' => false, 'error' => 'method_not_allowed'], 405);
  }
  if (isset(csrf_free_actions()[$action])) return;
  $sessionUser = $_SESSION['user'] ?? '';
  if (!is_string($sessionUser) || $sessionUser === '') return;
  if (!hash_equals(csrf_token(), csrf_request_token($data))) {
    reply(['ok' => false, 'error' => 'bad_csrf'], 403);
  }
}
