<?php

declare(strict_types=1);

namespace ApiModel\Infrastructure\Security;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

/**
 * CORS por ambiente: en producción nunca se usa modo relajado y no se admite '*' en la allowlist.
 */
final class CorsPolicy
{
    public static function isProduction(): bool
    {
        return strtolower(trim((string) ($_ENV['APP_ENV'] ?? ''))) === 'production';
    }

    public static function appendHeaders(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $requestOrigin = $request->getHeaderLine('Origin');
        $production = self::isProduction();

        $corsRelaxed = in_array(strtolower((string) ($_ENV['CORS_RELAXED'] ?? '')), ['1', 'true', 'yes'], true);
        if ($production && $corsRelaxed) {
            error_log('[api] CORS_RELAXED ignorado cuando APP_ENV=production.');
            $corsRelaxed = false;
        }

        if ($corsRelaxed) {
            $allowOrigin = $requestOrigin !== '' ? $requestOrigin : '*';
            $withCredentials = $requestOrigin !== '';

            return self::withCorsHeaders($response, $allowOrigin, $withCredentials);
        }

        $allowed = self::allowedOriginsList($production);
        $allowOrigin = null;

        if ($requestOrigin !== '') {
            foreach ($allowed as $o) {
                if (strcasecmp($o, $requestOrigin) === 0) {
                    $allowOrigin = $requestOrigin;
                    break;
                }
            }
        } elseif ($allowed !== []) {
            $allowOrigin = $allowed[0];
        } elseif (! $production) {
            $allowOrigin = '*';
        }

        if ($allowOrigin === null) {
            return $response;
        }

        return self::withCorsHeaders($response, $allowOrigin, true);
    }

    /**
     * @return list<string>
     */
    private static function allowedOriginsList(bool $production): array
    {
        $raw = (string) ($_ENV['CORS_ORIGINS'] ?? '');
        $parts = array_values(array_filter(array_map('trim', explode(',', $raw)), static fn (string $s): bool => $s !== ''));

        if (! $production) {
            return $parts;
        }

        $hadWildcard = false;
        $out = [];
        foreach ($parts as $o) {
            if (strcasecmp($o, '*') === 0) {
                $hadWildcard = true;
                continue;
            }
            $out[] = $o;
        }

        if ($hadWildcard) {
            error_log('[api] CORS: en producción se ignoran entradas * en CORS_ORIGINS; usa URLs explícitas.');
        }

        return $out;
    }

    private static function withCorsHeaders(ResponseInterface $response, string $allowOrigin, bool $withCredentials): ResponseInterface
    {
        $out = $response
            ->withHeader('Access-Control-Allow-Origin', $allowOrigin)
            ->withHeader('Vary', 'Origin')
            ->withHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type, X-API-Key, X-Company-Id, X-Branch-Id')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE, OPTIONS');

        return $withCredentials ? $out->withHeader('Access-Control-Allow-Credentials', 'true') : $out;
    }
}
