<?php

declare(strict_types=1);

namespace App\Domain\Reputation;

use App\Domain\Ip\IpAddress;
use App\Infrastructure\Reputation\CidrEvaluatorFactory;
use App\Infrastructure\Reputation\IpScoreRepository;

/**
 * Resolves an IP to one of `allowlisted | manually_blocked | scored | clean`.
 *
 * SPEC §5 resolution order — allowlist wins over everything; manual block
 * wins over scored; otherwise we look at `ip_scores` to distinguish a
 * `Scored` IP (any non-zero score in any category) from a `Clean` one
 * (no rows, or all zero).
 *
 * M07 added the policy-evaluator for the distribution endpoint; the
 * single-IP "is this scored?" question for the admin UI uses any non-
 * zero score across all categories, which is a coarser but stable
 * signal independent of which policy the caller is asking about.
 */
final class EffectiveStatusService
{
    public function __construct(
        private readonly CidrEvaluatorFactory $evaluatorFactory,
        private readonly IpScoreRepository $ipScores,
    ) {
    }

    public function forIp(IpAddress $ip): EffectiveStatus
    {
        $evaluator = $this->evaluatorFactory->get();

        if ($evaluator->isAllowlisted($ip)) {
            return EffectiveStatus::Allowlisted;
        }
        if ($evaluator->isManuallyBlocked($ip)) {
            return EffectiveStatus::ManuallyBlocked;
        }
        if ($this->ipScores->hasAnyScore($ip->binary())) {
            return EffectiveStatus::Scored;
        }

        return EffectiveStatus::Clean;
    }
}
