<?php

namespace App\Services\Billing;

use App\Support\CompanyProfile;

/**
 * The one-off charge for setting a customer up — and the one place it is turned
 * into money.
 *
 * The fee had been advertised for months and charged to nobody. It was on the
 * public price sheet ("Einrichtung kostet einmalig 118,80 €"), on the booking page
 * ("zzgl. Einrichtung einmalig"), and the operator set the figure in the console —
 * and CompanyProfile::setupFeeCents() had no reader outside those two sentences
 * and the form that wrote it. Nothing put it on a checkout, on an invoice item or
 * on any bill at all.
 *
 * It is charged now. The two sentences and the money read the same figure through
 * this class, so a change of rate or of fee cannot move one without moving the
 * others.
 *
 * **What is charged for it follows the same rule as a package.** The console asks
 * the operator for the NET amount, because that is the commercial number and the
 * field says so. What a customer pays is that amount put through their own
 * TaxTreatment: the domestic gross for everybody who is charged VAT, so the
 * figure at the till is the figure the price sheet quoted — and the bare net for
 * a business in another member state whose VAT id is verified, because reverse
 * charge means no VAT is owed to us on the fee either. A fee is a supply like any
 * other; taxing it differently from the package on the same invoice would be a
 * document at two rates.
 *
 * The public price sheet quotes the domestic gross, because it is read by
 * visitors nobody has met — TaxTreatment::advertisedCents(), the same figure the
 * ordinary checkout takes.
 *
 * Zero means there is no such fee. Every reader has to treat that as "no line at
 * all" rather than "a line of nought" — a checkout that itemises nothing owed is
 * worse than one that says nothing.
 */
final class SetupFee
{
    /** The net figure an operator typed, in cents. Zero when there is no fee. */
    public static function netCents(): int
    {
        return CompanyProfile::setupFeeCents();
    }

    /**
     * What a customer treated so is actually charged for it.
     *
     * The treatment is a required argument rather than the domestic one assumed,
     * so that every call site has to say whose fee it is quoting. The page that
     * quotes it to a stranger passes TaxTreatment::domestic(), and says so.
     */
    public static function chargedCents(TaxTreatment $treatment): int
    {
        $net = self::netCents();

        return $net === 0 ? 0 : $treatment->chargeCents($net);
    }

    /**
     * The fee as the extra, non-recurring line of a checkout session — or null
     * when the operator has set none.
     *
     * `$currency` is the recurring Price's own, not the catalogue default: Stripe
     * requires every line of one session to share a currency, and reading two
     * sources for it is how a checkout ends up refused for a mismatch nobody can
     * see from either page.
     *
     * @return array{amount_cents: int, label: string, currency: string}|null
     */
    public static function checkoutLine(string $currency, TaxTreatment $treatment): ?array
    {
        $charged = self::chargedCents($treatment);

        if ($charged === 0) {
            return null;
        }

        return [
            'amount_cents' => $charged,
            // What the customer reads on Stripe's page and on Stripe's receipt.
            // The same words the price sheet uses, because meeting a different
            // name for the same charge at the till is exactly the moment somebody
            // abandons a checkout.
            'label' => __('checkout.setup_fee_line'),
            'currency' => strtoupper($currency),
        ];
    }
}
