<?php

namespace MintyPHP\Http;

use MintyPHP\I18n;
use MintyPHP\Router;

/**
 * Handles public path detection and authentication guards.
 */
class AccessControl
{
    /** Prefixes that are always public */
    private const ALWAYS_PUBLIC_PREFIXES = [
        'branding/',
        'auth/tenant-logo-file',
        'flash/',
        'auth/microsoft/',
        'api/',
    ];

    private array $configuredPublicPaths;
    private IntendedUrlService $intendedUrlService;

    public function __construct(array $publicPaths, IntendedUrlService $intendedUrlService)
    {
        $normalizedPaths = [];
        foreach ($publicPaths as $path) {
            $rawPath = trim((string) $path);
            if ($rawPath === '') {
                continue;
            }
            $normalizedPaths[] = $rawPath === '/' ? '/' : trim($rawPath, '/');
        }

        $this->configuredPublicPaths = array_values(array_unique($normalizedPaths));
        $this->intendedUrlService = $intendedUrlService;
    }

    /**
     * Check if a path is publicly accessible (no authentication required).
     */
    public function isPublicPath(string $path): bool
    {
        $normalizedPath = $this->normalizePath($path);

        // Root path check
        if ($normalizedPath === '/') {
            return in_array('/', $this->configuredPublicPaths, true);
        }

        // Check configured public paths
        if (in_array($normalizedPath, $this->configuredPublicPaths, true)) {
            return true;
        }

        // Check always-public prefixes
        foreach (self::ALWAYS_PUBLIC_PREFIXES as $prefix) {
            if (str_starts_with($normalizedPath, $prefix)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Redirect to login if the path requires authentication and user is not logged in.
     *
     * @return bool True if access is allowed, false if redirected
     */
    /**
     * Redirect to login if the path requires authentication and user is not logged in.
     * Appends ?return_to= so the user is redirected back after login.
     *
     * @return bool True if access is allowed, false if redirected
     */
    public function requireAuthOrRedirect(string $path, bool $isLoggedIn): bool
    {
        if ($this->isPublicPath($path) || $isLoggedIn) {
            return true;
        }

        $locale = I18n::$locale ?? I18n::$defaultLocale;
        // Use the concrete target route. Minty alias rewrites compare the full
        // REQUEST_URI (including query), so alias paths with query params are fragile.
        $loginPath = Request::withLocale('auth/login', $locale);

        $requestUri = $_SERVER['REQUEST_URI'] ?? '';
        $loginTarget = $this->intendedUrlService->buildLoginRedirect($loginPath, $requestUri);

        Router::redirect($loginTarget);

        return false;
    }

    private function normalizePath(string $path): string
    {
        $normalized = trim($path, '/');
        return $normalized === '' ? '/' : $normalized;
    }
}
