<?php

declare(strict_types=1);

namespace PpPhp\Core\Auth;

use PpPhp\Core\Security;

/**
 * Per-action page access gate for generated apps (platform feature A8).
 *
 * By default every generated page calls Security::RequireAuth() + a page
 * permission check, so an auth-enabled build gates the whole app behind login.
 * A8 lets a table's READ pages (list + view) be PUBLIC — reachable by anonymous
 * visitors (and search-engine crawlers, which is what makes the A1/A2/A4 SEO
 * work reachable) — WHILE its write pages (add/edit/delete) and A6 actions still
 * require login.
 *
 * `guard()` replaces the two auth calls at the top of a page. It is behaviour-
 * preserving: with `$publicRead = false` (the default for every table) it does
 * exactly what the old code did, and when auth is disabled it is a no-op just as
 * RequireAuth() already was. Only a table explicitly marked "publicly readable"
 * opens its list/view to anonymous.
 */
final class PageAccess
{
    /** The only actions a public table opens to anonymous visitors. */
    private const PUBLIC_READ_ACTIONS = ['view', 'list'];

    /** Whether anonymous access is allowed for this action on a public table. */
    public static function allowsAnonymous(string $action, bool $publicRead): bool
    {
        return $publicRead && in_array($action, self::PUBLIC_READ_ACTIONS, true);
    }

    /**
     * Gate the current page. Public read → return (anonymous allowed). Otherwise
     * require login + the page permission, exactly as before.
     */
    public static function guard(string $action, string $table, bool $publicRead = false): void
    {
        $authOn = defined('PP_AUTH_ENABLED') && (bool) constant('PP_AUTH_ENABLED');
        if ($authOn && self::allowsAnonymous($action, $publicRead)) {
            return;                                       // public content: no login, no per-user permission
        }
        Security::RequireAuth();                          // no-op when auth is disabled
        Permissions::requirePage($action, $table);
    }
}
