<?php

namespace App\Actions;

use App\Models\Customer;
use App\Services\Tax\VatIdCheck;
use App\Services\Tax\VatIdVerifier;

/**
 * Ask the register about a customer's VAT number and record what it said.
 *
 * The one place a check becomes a stored verification, so the portal form, the
 * console and the nightly re-check cannot disagree about what counts. It decides
 * nothing about tax: TaxTreatment reads the stored verification and applies the
 * reverse-charge rule. This only answers "is the number real".
 *
 * Deliberately not gated on the customer's recorded type. Whether a verified
 * number earns reverse charge is TaxTreatment's question — it already refuses a
 * customer who has recorded themselves as a private person — and a number that
 * is registered is registered whoever holds it. Splitting that decision across
 * two files is how the two would drift.
 */
class VerifyCustomerVatId
{
    public function __construct(private VatIdVerifier $verifier) {}

    /**
     * Returns what the register said, so the caller can tell the customer.
     *
     * Null when there is no number to check at all — not an outcome, an absence,
     * and a caller showing "invalid" for an empty field would be wrong.
     */
    public function __invoke(Customer $customer): ?VatIdCheck
    {
        $vatId = $customer->normalisedVatId();

        if ($vatId === '') {
            // Removing the number removes the verification with it. Otherwise the
            // stamp would sit on the record with nothing to compare against, and
            // the next number typed in would look pre-verified for one save.
            $this->clear($customer);

            return null;
        }

        $check = $this->verifier->check($vatId);

        // The whole reason VatIdCheck has three outcomes. An outage tells us
        // nothing, so nothing is written: a verification that has been standing
        // for months must not be cleared — and a customer's invoices changed —
        // because a national register was down for the night.
        if ($check->isUnavailable()) {
            return $check;
        }

        if ($check->isInvalid()) {
            $this->clear($customer);

            return $check;
        }

        // Bound to the value that was checked, not to a flag. Customer::
        // hasVerifiedVatId() compares the two, so editing the number afterwards
        // cannot inherit this confirmation whichever code path does the editing.
        $customer->forceFill([
            'vat_id_verified_at' => now(),
            'vat_id_verified_value' => $vatId,
        ])->save();

        return $check;
    }

    private function clear(Customer $customer): void
    {
        if ($customer->vat_id_verified_at === null && $customer->vat_id_verified_value === null) {
            return;
        }

        $customer->forceFill([
            'vat_id_verified_at' => null,
            'vat_id_verified_value' => null,
        ])->save();
    }
}
