<?php

/**
 * Copyright 2024-2025 Simply.IN Sp. z o.o.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the EUPL-1.2 or later.
 * You may not use this work except in compliance with the Licence.
 *
 * Copy of the Licence is available at:
 * https://joinup.ec.europa.eu/software/page/eupl
 * It is bundled with this package in the file LICENSE.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Licence is distributed on an as is basis,
 * without warranties or conditions of any kind, either express or implied.
 * Check the Licence for the specific language governing permissions
 * and limitations under the License.
 *
 * @author   Simply.IN Sp. z o.o.
 * @copyright 2024-2025 Simply.IN Sp. z o.o.
 * @license   https://joinup.ec.europa.eu/software/page/eupl
 */

declare(strict_types=1);

namespace SimplyIn\Payment;

use Cart;
use Configuration;
use Context;
use Currency;
use Media;
use Module;
use PaymentModule;
use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
use SimplyIn\Session\SimplyInSessionInterface;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class PaymentOptionsBuilder
{
    public function __construct(
        private readonly PaymentLogoResolver $logoResolver,
        private readonly SimplyInSessionInterface $session,
        private readonly PaymentMethodsProvider $methodsProvider,
    ) {
    }

    /**
     * @return array<int, PaymentOption>
     */
    public function build(Module $module, Cart $cart): array
    {
        if (!($module instanceof PaymentModule)) {
            return [];
        }
        if (!$this->hasCurrencyEnabled($module, $cart)) {
            return [];
        }
        if (!$module->active || !Configuration::get('SIMPLYIN_PAYMENTS')) {
            return [];
        }

        $methods = $this->methodsProvider->getAvailableMethods();
        if ($methods === []) {
            return [];
        }

        $context = Context::getContext();
        $currencyIso = (string) ($context->currency->iso_code ?? '');
        if ($currencyIso !== 'PLN') {
            $methods = $this->removeBlik($methods);
        }

        $methodsByProvider = $this->groupByProvider($methods);
        if ($methodsByProvider === []) {
            return [];
        }

        $options = [];
        foreach ($methodsByProvider as $providerMethods) {
            $context->smarty->assign($this->buildTemplateVars($module, $cart, $providerMethods));

            $logo = $this->logoResolver->resolve($providerMethods);

            $option = new PaymentOption();
            $option->setModuleName($module->name)
                ->setCallToActionText($module->l('Simple and Safe payments'))
                ->setAction($context->link->getModuleLink($module->name, 'validation', [], true))
                ->setAdditionalInformation($module->fetch('module:simplyin/views/templates/hook/simplyin_payment_info.tpl'));

            if ($logo !== null) {
                $mediaPath = Media::getMediaPath(_MODULE_DIR_ . $module->name . '/views/img/' . $logo);
                $option->setLogo(is_string($mediaPath) ? $mediaPath : '');
            }

            $options[] = $option;
        }

        return $options;
    }

    private function hasCurrencyEnabled(PaymentModule $module, Cart $cart): bool
    {
        $currencyOrder = new Currency($cart->id_currency);
        $currenciesModule = $module->getCurrency($cart->id_currency);

        if (!is_array($currenciesModule)) {
            return false;
        }

        foreach ($currenciesModule as $currencyModule) {
            if ((int) $currencyOrder->id === (int) $currencyModule['id_currency']) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param array<int, object> $methods
     *
     * @return array<int, object>
     */
    private function removeBlik(array $methods): array
    {
        return array_values(array_filter(
            $methods,
            static fn (object $method): bool => ($method->typeName ?? null) !== 'BLIK',
        ));
    }

    /**
     * @param array<int, object> $methods
     *
     * @return array<int|string, array<int, object>>
     */
    private function groupByProvider(array $methods): array
    {
        $grouped = [];
        foreach ($methods as $method) {
            $providerId = $method->paymentProvider->id ?? null;
            if ($providerId === null) {
                continue;
            }
            $grouped[$providerId][] = $method;
        }

        return $grouped;
    }

    /**
     * @param array<int, object> $methods
     *
     * @return array<string, mixed>
     */
    private function buildTemplateVars(Module $module, Cart $cart, array $methods): array
    {
        $context = Context::getContext();
        $total = sprintf(
            $module->l('%1$s (tax incl.)'),
            $context->getCurrentLocale()->formatPrice(
                $cart->getOrderTotal(true, Cart::BOTH),
                (string) ($context->currency->iso_code ?? ''),
            ),
        );

        $addCard = false;
        $blik = false;
        $cards = false;
        foreach ($methods as $method) {
            $type = $method->type ?? null;
            if ($type === 'add_card') {
                $addCard = $method;
            } elseif ($type === 'blik') {
                $blik = $method;
            } elseif ($type === 'card') {
                if ($cards === false) {
                    $cards = [];
                }
                $cards[] = $method;
            }
        }

        $providerLogoUrl = '';
        if ($methods !== []) {
            $first = reset($methods);
            $providerLogoUrl = (string) ($first->paymentProvider->logoUrl ?? '');
        }

        $authToken = (string) $this->session->get('simplyin_auth_token', '');
        $showSaveCard = trim($authToken) !== '';

        return [
            'total' => $total,
            'add_card' => $addCard,
            'blik' => $blik,
            'cards' => $cards,
            'show_save_card' => $showSaveCard,
            'provider_logo_url' => $providerLogoUrl,
        ];
    }
}
