<?php

namespace App\Support;

/**
 * Who is issuing the invoice.
 *
 * Every field a printed invoice needs, kept in settings rather than in config,
 * because an operator has to be able to change an address without a deployment
 * — and because the values are copied into each invoice at issue anyway, so
 * changing one here never rewrites a document that already exists.
 *
 * A typed front door onto Settings rather than string keys scattered through
 * views and PDF code: there are fifteen of them, an invoice is a legal
 * document, and a typo in a key silently prints an empty line where the VAT
 * number belongs.
 */
final class CompanyProfile
{
    private const PREFIX = 'company.';

    /** Every key, with its default. The list IS the schema. */
    public const FIELDS = [
        'name' => '',
        'address' => '',
        'postcode' => '',
        'city' => '',
        'country' => 'Österreich',
        'phone' => '',
        'email' => '',
        'website' => '',
        // Firmenbuch / commercial register, and the court that keeps it.
        'register_number' => '',
        'register_court' => '',
        // UID / VAT identification number — the one field an invoice is
        // legally worthless without.
        'vat_id' => '',
        'bank_name' => '',
        'iban' => '',
        'bic' => '',
        'logo_path' => '',
        // Payment terms in days, and the sentence printed under the total.
        'payment_days' => 14,
        'payment_terms' => '',
    ];

    /** @return array<string, mixed> */
    public static function all(): array
    {
        $values = [];

        foreach (self::FIELDS as $key => $default) {
            $values[$key] = Settings::get(self::PREFIX.$key, $default);
        }

        return $values;
    }

    public static function get(string $field, mixed $default = null): mixed
    {
        return Settings::get(self::PREFIX.$field, $default ?? (self::FIELDS[$field] ?? null));
    }

    /** @param array<string, mixed> $values */
    public static function put(array $values): void
    {
        foreach ($values as $key => $value) {
            // Unknown keys are dropped rather than stored. This is fed from a
            // form, and a forged field must not be able to write an arbitrary
            // setting into the same table the site-visibility switch lives in.
            if (! array_key_exists($key, self::FIELDS)) {
                continue;
            }

            Settings::set(self::PREFIX.$key, $value);
        }
    }

    /**
     * Is there enough here to put on an invoice?
     *
     * Not a nicety: an invoice without a company name, an address or a VAT
     * number is not a valid invoice in Austria, and issuing one is worse than
     * refusing to. The console asks this before it offers the button.
     *
     * @return array<int, string> the fields that are missing, empty when ready
     */
    public static function missingForInvoicing(): array
    {
        $required = ['name', 'address', 'postcode', 'city', 'vat_id'];

        return array_values(array_filter(
            $required,
            fn (string $field) => trim((string) self::get($field)) === '',
        ));
    }

    /**
     * The domestic VAT rate as a percentage, e.g. 20.0.
     *
     * The ONE place it is decided. App\Services\Billing\TaxTreatment reads it
     * from here rather than from config, because this page can change it and a
     * config value cannot — and two sources for one number is how an invoice
     * ends up disagreeing with the checkout that produced it.
     *
     * Falls back to the .env-derived config until an operator has saved a rate,
     * so an installation that already carries CLUPILOT_TAX_PERCENT keeps
     * working unchanged. Same shape as App\Support\ProvisioningSettings.
     */
    public static function taxRate(): float
    {
        return (float) Settings::get('company.tax_rate', (float) config('provisioning.tax.rate_percent', 20));
    }

    /**
     * What setting a customer up costs once, net, in cents.
     *
     * The price sheet has always said "zzgl. einmaliger Einrichtung" without
     * ever naming a figure — a price that is announced and not stated is worse
     * than no price at all, because the visitor now knows there is one and has
     * to ask. Editable here for the same reason as the tax rate: it is a
     * commercial number that lands on an invoice, and an operator must be able
     * to change it without a deployment.
     *
     * Zero means there is no such fee, and the sentence disappears from the
     * page entirely rather than announcing nothing.
     */
    public static function setupFeeCents(): int
    {
        return (int) Settings::get('company.setup_fee_cents', 0);
    }
}
