<?php

namespace App\Services\Tax;

/**
 * What VIES answered about one VAT number.
 *
 * Three outcomes, not two, and the third is the whole reason this class exists.
 * VIES is a gateway onto twenty-seven national registers, and any one of them is
 * regularly unreachable — a member state takes its service down for the night,
 * the concurrency limit is hit, the gateway times out. None of that says anything
 * about the number.
 *
 * So UNAVAILABLE must never be read as INVALID. Treating an outage as a failed
 * check would clear a verification that has been standing for months, move that
 * customer from reverse charge onto the domestic rate, and change what their next
 * invoice says — because a national register was asleep. It must not be read as
 * VALID either: reverse charge on an unchecked number is our liability, not the
 * customer's.
 *
 * The name and address are what the register holds. They are kept because they
 * are the evidence that the number belongs to the company we are invoicing, and
 * because a mismatch there is worth an operator's attention even when the number
 * itself is registered.
 */
final readonly class VatIdCheck
{
    public const VALID = 'valid';

    public const INVALID = 'invalid';

    public const UNAVAILABLE = 'unavailable';

    private function __construct(
        public string $outcome,
        public ?string $name = null,
        public ?string $address = null,
        public ?string $reason = null,
    ) {}

    public static function valid(?string $name = null, ?string $address = null): self
    {
        return new self(self::VALID, $name, $address);
    }

    public static function invalid(): self
    {
        return new self(self::INVALID);
    }

    /** @param  string|null  $reason  what stopped us asking — for the log, never for the customer */
    public static function unavailable(?string $reason = null): self
    {
        return new self(self::UNAVAILABLE, reason: $reason);
    }

    public function isValid(): bool
    {
        return $this->outcome === self::VALID;
    }

    public function isInvalid(): bool
    {
        return $this->outcome === self::INVALID;
    }

    /**
     * Nothing was learnt.
     *
     * Callers must leave whatever they already knew alone when this is true —
     * see the class comment for why that is not merely cautious.
     */
    public function isUnavailable(): bool
    {
        return $this->outcome === self::UNAVAILABLE;
    }
}
