<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Payments;

use Ferienpass\CoreBundle\Entity\Payment;

/**
 * Derives a human-readable payment method ("Zahlungsart") for a payment.
 *
 * There is no first-class payment-method column. A payment that never went
 * through the online gateway (no pmPayment transaction) was collected at the
 * counter and counts as cash. For online payments the concrete instrument
 * (giropay, credit card, …) is read from the stored pmPayment status payload.
 */
class PaymentMethodResolver
{
    public const string CASH = 'Bargeld';
    public const string ONLINE_FALLBACK = 'Online-Zahlung';

    /**
     * Payload keys (case-insensitive) under which pmPayment may expose the
     * chosen instrument. The status payload is provider-specific and not
     * formally documented, so we search for any of these recursively.
     */
    private const array METHOD_KEYS = ['payment_method', 'paymentmethod', 'method'];

    /**
     * Normalises raw provider method codes to display labels. Unknown codes
     * fall through and are shown capitalised verbatim.
     */
    private const array LABELS = [
        'giropay' => 'giropay',
        'paydirekt' => 'paydirekt',
        'paypal' => 'PayPal',
        'creditcard' => 'Kreditkarte',
        'credit_card' => 'Kreditkarte',
        'kreditkarte' => 'Kreditkarte',
        'lastschrift' => 'SEPA-Lastschrift',
        'sepa' => 'SEPA-Lastschrift',
        'directdebit' => 'SEPA-Lastschrift',
        'sofort' => 'Sofortüberweisung',
        'ueberweisung' => 'Überweisung',
        'überweisung' => 'Überweisung',
    ];

    public function resolve(Payment $payment): string
    {
        // No online transaction recorded → collected at the counter (cash).
        if (null === $payment->getPmPaymentTransactionId()) {
            return self::CASH;
        }

        $status = $payment->getPmPaymentTransactionStatus();
        $raw = null !== $status ? $this->extractMethod($status->getPayload()) : null;

        if (null === $raw || '' === $raw) {
            return self::ONLINE_FALLBACK;
        }

        return self::LABELS[strtolower($raw)] ?? ucfirst($raw);
    }

    /**
     * @param array<array-key, mixed> $payload
     */
    private function extractMethod(array $payload): ?string
    {
        $found = null;

        array_walk_recursive($payload, static function ($value, $key) use (&$found): void {
            if (null !== $found) {
                return;
            }

            if (\is_string($value) && '' !== $value && \in_array(strtolower((string) $key), self::METHOD_KEYS, true)) {
                $found = $value;
            }
        });

        return $found;
    }
}
