<?php

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Manager;

use CpCreation\VitiCore\Behavior\HasPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\AxeptaPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\CawlPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\EtransactionsPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\MoneticoPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\PayPlugPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\Sherlock2Payment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\SogeCommercePayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\SystemPayPayment;
use CpCreation\VitiCore\Contact\Model\Contact;
use Symfony\Component\HttpFoundation\RedirectResponse;

final class CheckoutPaymentSubmissionBuilder
{
    public function __construct(
        private readonly EtransactionsPayment $etransactionsPayment,
        private readonly MoneticoPayment $moneticoPayment,
        private readonly SystemPayPayment $systemPayPayment,
        private readonly SogeCommercePayment $sogeCommercePayment,
        private readonly AxeptaPayment $axeptaPayment,
        private readonly Sherlock2Payment $sherlock2Payment,
        private readonly PayPlugPayment $payPlugPayment,
        private readonly CawlPayment $cawlPayment,
        private readonly PaymentProviderManager $paymentProviderManager,
    ) {
    }

    /**
     * @return array{
     *     mode: 'form'|'redirect',
     *     action?: string,
     *     method?: 'POST',
     *     fields?: array<string, scalar|null>,
     *     url?: string
     * }
     */
    public function build(Contact $contact, HasPayment $payment): array
    {
        return match ($payment->getPaymentMethod()?->getMethod()) {
            EtransactionsPayment::METHOD => $this->buildFormSubmission($this->etransactionsPayment->createData($payment)),
            MoneticoPayment::METHOD => $this->buildFormSubmission($this->moneticoPayment->createData($payment)),
            SystemPayPayment::METHOD => $this->buildFormSubmission($this->systemPayPayment->createData($payment)),
            SogeCommercePayment::METHOD => $this->buildFormSubmission($this->sogeCommercePayment->createData($payment)),
            AxeptaPayment::METHOD => $this->buildFormSubmission($this->axeptaPayment->createData($payment)),
            Sherlock2Payment::METHOD => $this->buildFormSubmission($this->sherlock2Payment->createData($payment)),
            PayPlugPayment::METHOD => [
                'mode' => 'redirect',
                'url' => (string) $this->payPlugPayment->createData($payment)->hosted_payment->payment_url,
            ],
            CawlPayment::METHOD => [
                'mode' => 'redirect',
                'url' => (string) ($this->cawlPayment->createData($payment)['URL'] ?? ''),
            ],
            default => $this->buildRedirectSubmission(
                $this->paymentProviderManager->createPaymentProviderManager($contact, $payment)
            ),
        };
    }

    /**
     * @param array<string, mixed> $data
     *
     * @return array{
     *     mode: 'form',
     *     action: string,
     *     method: 'POST',
     *     fields: array<string, scalar|null>
     * }
     */
    private function buildFormSubmission(array $data): array
    {
        $action = $data['URL'] ?? null;
        if (!\is_string($action) || '' === $action) {
            throw new \RuntimeException('URL de soumission PSP manquante.');
        }

        unset($data['URL']);

        $fields = [];
        foreach ($data as $key => $value) {
            if (!\is_string($key)) {
                continue;
            }

            if (\is_scalar($value) || null === $value) {
                $fields[$key] = $value;
            }
        }

        return [
            'mode' => 'form',
            'action' => $action,
            'method' => 'POST',
            'fields' => $fields,
        ];
    }

    /**
     * @return array{mode: 'redirect', url: string}
     */
    private function buildRedirectSubmission(mixed $response): array
    {
        if (!$response instanceof RedirectResponse) {
            throw new \RuntimeException('La soumission de paiement attend une redirection HTTP.');
        }

        return [
            'mode' => 'redirect',
            'url' => $response->getTargetUrl(),
        ];
    }
}
