<?php

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\AgeVerification;

use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;

final readonly class AgeVerificationProofManager
{
    public const string COOKIE_NAME = 'viti_age_verified';
    public const string REQUEST_REMEMBER_DAYS = '_viti_age_verification_remember_days';
    public const string REQUEST_CONFIG_FINGERPRINT = '_viti_age_verification_config_fingerprint';

    public function __construct(private string $secret) {}

    public function isVerified(
        Request $request,
        string $configFingerprint,
        ?\DateTimeImmutable $now = null,
    ): bool {
        $proof = $request->cookies->get(self::COOKIE_NAME);
        if (!\is_string($proof)) {
            return false;
        }

        $parts = explode('.', $proof, 4);
        if (4 !== \count($parts) || 'v2' !== $parts[0] || !ctype_digit($parts[1])) {
            return false;
        }

        $expiresAt = (int) $parts[1];
        $now ??= new \DateTimeImmutable();
        if ($expiresAt <= $now->getTimestamp()) {
            return false;
        }

        if (!hash_equals($configFingerprint, $parts[2])) {
            return false;
        }

        return hash_equals($this->sign($expiresAt, $configFingerprint), $parts[3]);
    }

    public function createCookie(
        Request $request,
        int $rememberForDays,
        string $configFingerprint,
        ?\DateTimeImmutable $now = null,
    ): Cookie {
        $now ??= new \DateTimeImmutable();
        $expiresAt = $now->modify(sprintf('+%d days', $rememberForDays));
        $timestamp = $expiresAt->getTimestamp();

        return Cookie::create(
            self::COOKIE_NAME,
            sprintf(
                'v2.%d.%s.%s',
                $timestamp,
                $configFingerprint,
                $this->sign($timestamp, $configFingerprint),
            ),
            $expiresAt,
            '/',
            null,
            $request->isSecure(),
            true,
            false,
            Cookie::SAMESITE_LAX,
        );
    }

    private function sign(int $expiresAt, string $configFingerprint): string
    {
        return hash_hmac('sha256', sprintf('v2.%d.%s', $expiresAt, $configFingerprint), $this->secret);
    }
}
