<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Repository;

use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Ferienpass\CoreBundle\Entity\BlockedContact;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * @extends ServiceEntityRepository<BlockedContact>
 */
class BlockedContactRepository extends ServiceEntityRepository
{
    public function __construct(
        ManagerRegistry $registry,
        #[Autowire(param: 'kernel.secret')]
        private readonly string $secret,
    ) {
        parent::__construct($registry, BlockedContact::class);
    }

    /**
     * Keyed (HMAC-SHA256) hash of a normalized email address.
     *
     * Replaces the previous unsalted md5() keying, which was reversible via
     * rainbow tables. The email is lowercased and trimmed before hashing so the
     * same value is produced at the write site (BlockEmail handler) and here.
     */
    public static function hashEmail(string $email, string $secret): string
    {
        return hash_hmac('sha256', strtolower(trim($email)), $secret);
    }

    public function findByEmail(string $email): ?BlockedContact
    {
        // Dual-read during the transition: rows written before the switch to
        // HMAC are still keyed on the legacy unsalted md5() of the raw email.
        // Match either keying so previously-suppressed contacts keep working.
        return $this->findOneBy(['email' => self::hashEmail($email, $this->secret)])
            ?? $this->findOneBy(['email' => md5($email)]);
    }
}
