<?php
namespace App\Controllers;

/** Base for privileged endpoints: bearer ADMIN_TOKEN or api_auth API key. */
class ApiController extends JsonController
{
    protected ?array $apiUser = null; // set when an api_auth key authenticates

    /** Extract a token from Authorization: Bearer, ?apikey=, or X-Api-Key. */
    private function bearer(): string
    {
        $h = $_SERVER['HTTP_AUTHORIZATION'] ?? ($_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '');
        if (stripos($h, 'Bearer ') === 0) {
            return trim(substr($h, 7));
        }
        return $_SERVER['HTTP_X_API_KEY'] ?? ($_GET['apikey'] ?? '');
    }

    /** Enforce authentication; emits 401 and stops on failure. Also basic per-minute throttle. */
    protected function requireAuth(int $max = 120, int $window = 60): void
    {
        $token = $this->bearer();
        if ($token === '') {
            $this->json(null, 401, ['code' => 'unauthorized', 'message' => 'Missing bearer token']);
        }
        // First-party admin token (constant-time compare).
        if (defined('ADMIN_TOKEN') && hash_equals(ADMIN_TOKEN, $token)) {
            if ($this->throttle('admin', $max, $window)) {
                $this->json(null, 429, ['code' => 'rate_limited', 'message' => 'Too many requests']);
            }
            return;
        }
        // Programmatic api_auth key.
        $row = \Db::getRow(
            "SELECT `id`, `userid`, `active` FROM `api_auth` WHERE `apikey` = ? LIMIT 1",
            [$token]
        );
        if (!$row || (int) $row['active'] !== 1) {
            $this->json(null, 401, ['code' => 'unauthorized', 'message' => 'Invalid API key']);
        }
        $this->apiUser = $row;
        if ($this->throttle('apikey:' . $row['id'], $max, $window)) {
            $this->json(null, 429, ['code' => 'rate_limited', 'message' => 'Too many requests']);
        }
        // NOTE: monthly/plan quota enforcement (api_plans/api_usage) is deferred to a later sub-project.
    }
}
