<?php

namespace App\Services\Tax;

use App\Models\Customer;
use App\Services\Billing\TaxTreatment;

/**
 * Whether a string is even worth asking VIES about.
 *
 * Shared by the real verifier and the fake, deliberately. A fake that answers
 * where the real one would not have asked is not a simplification, it is a
 * different product — and every test written against it proves something about
 * that product instead of about this one.
 *
 * Two conditions, and the second is less obvious than it looks. Free text
 * normalises into a well-formed VAT number more easily than one would think:
 * "not a number" loses its spaces and becomes NOTANUMBER, which the shape rule
 * alone reads as a perfectly good Norwegian number. VIES is the EU's register and
 * holds nothing else, and reverse charge is an intra-EU rule in any case, so a
 * prefix outside the union is answered here rather than spent on a request.
 */
final class VatIdShape
{
    /** @return bool  false when no member state could hold a number like this */
    public static function verifiable(string $vatId): bool
    {
        $normalised = Customer::normaliseVatId($vatId);

        if (preg_match('/^([A-Z]{2})([0-9A-Z]{8,12})$/', $normalised, $parts) !== 1) {
            return false;
        }

        // Against TaxTreatment's list rather than a second copy of it: two lists
        // of member states is how one of them ends up a year out of date.
        return in_array($parts[1], TaxTreatment::EU_MEMBER_STATES, true);
    }

    /**
     * The two halves VIES wants, or null when there is nothing to ask.
     *
     * @return array{0: string, 1: string}|null
     */
    public static function split(string $vatId): ?array
    {
        $normalised = Customer::normaliseVatId($vatId);

        if (! self::verifiable($normalised)) {
            return null;
        }

        return [substr($normalised, 0, 2), substr($normalised, 2)];
    }
}
