<?php
/**
 * 2026 Paysera
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * @author Paysera <plugins@paysera.com>
 * @copyright 2026 Paysera
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 * International Registered Trademark & Property of Paysera
 */

declare(strict_types=1);

namespace Paysera\PrestashopPayments\Form;

use Configuration;
use Paysera\PrestashopPayments\Enum\ConfigurationKey;
use PrestaShop\PrestaShop\Core\Configuration\DataConfigurationInterface;

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

/**
 * Handles Payment Settings configuration storage and retrieval.
 * Implements PrestaShop's DataConfigurationInterface for form integration.
 */
final class PaymentSettingsDataConfiguration implements DataConfigurationInterface
{
    public const PAYMENT_WINDOW_MODE_SAME_PAGE = 'same_page';
    public const PAYMENT_WINDOW_MODE_NEW_WINDOW = 'new_window';

    public const ALLOWED_PAYMENT_WINDOW_MODES = [
        self::PAYMENT_WINDOW_MODE_SAME_PAGE,
        self::PAYMENT_WINDOW_MODE_NEW_WINDOW,
    ];

    public const DEFAULT_ENABLE_PAYMENTS = false;
    public const DEFAULT_PAYMENT_WINDOW_MODE = self::PAYMENT_WINDOW_MODE_SAME_PAGE;
    public const DEFAULT_STATUS_AWAITING_CONFIRMATION = 'awaiting_paysera';
    public const DEFAULT_STATUS_AWAITING_PAYMENT = 'awaiting_paysera';
    public const DEFAULT_STATUS_CONFIRMED_PAYMENT = '2';
    public const DEFAULT_PAYMENT_TITLE = 'All popular payment methods';

    private const TYPE_BOOL = 'bool';
    private const TYPE_STRING = 'string';

    /**
     * Field configuration mapping: field name => [key, default, type]
     *
     * @return array<string, array{key: string, default: bool|string, type: string}>
     */
    private static function getFieldConfig(): array
    {
        return [
            'enable_payments' => [
                'key' => ConfigurationKey::ENABLE_PAYMENTS,
                'default' => self::DEFAULT_ENABLE_PAYMENTS,
                'type' => self::TYPE_BOOL,
            ],
            'payment_window_mode' => [
                'key' => ConfigurationKey::PAYMENT_WINDOW_MODE,
                'default' => self::DEFAULT_PAYMENT_WINDOW_MODE,
                'type' => self::TYPE_STRING,
            ],
            'status_awaiting_confirmation' => [
                'key' => ConfigurationKey::STATUS_AWAITING_CONFIRMATION,
                'default' => self::DEFAULT_STATUS_AWAITING_CONFIRMATION,
                'type' => self::TYPE_STRING,
            ],
            'status_confirmed_payment' => [
                'key' => ConfigurationKey::STATUS_CONFIRMED_PAYMENT,
                'default' => self::DEFAULT_STATUS_CONFIRMED_PAYMENT,
                'type' => self::TYPE_STRING,
            ],
            'status_awaiting_payment' => [
                'key' => ConfigurationKey::STATUS_AWAITING_PAYMENT,
                'default' => self::DEFAULT_STATUS_AWAITING_PAYMENT,
                'type' => self::TYPE_STRING,
            ],
            'payment_title' => [
                'key' => ConfigurationKey::PAYMENT_TITLE,
                'default' => self::DEFAULT_PAYMENT_TITLE,
                'type' => self::TYPE_STRING,
            ],
        ];
    }

    /**
     * Get current configuration values for the form.
     *
     * @return array{
     *     enable_payments: bool,
     *     payment_window_mode: string,
     *     status_awaiting_confirmation: string,
     *     status_confirmed_payment: string,
     *     status_awaiting_payment: string,
     *     payment_title: string
     * }
     */
    public function getConfiguration(): array
    {
        $config = [];

        foreach (self::getFieldConfig() as $field => $settings) {
            $config[$field] = $this->getConfigValue(
                $settings['key'],
                $settings['default'],
                $settings['type']
            );
        }

        return $config;
    }

    /**
     * Update configuration with new values.
     *
     * @param array{
     *     enable_payments?: bool,
     *     payment_window_mode?: string,
     *     status_awaiting_confirmation?: string,
     *     status_confirmed_payment?: string,
     *     status_awaiting_payment?: string,
     *     payment_title?: string
     * } $configuration
     *
     * @return list<string> List of error messages, empty if successful
     */
    public function updateConfiguration(array $configuration): array
    {
        if (!$this->validateConfiguration($configuration)) {
            return ['Invalid configuration data provided.'];
        }

        try {
            $this->saveConfigurationValues($configuration);
        } catch (\Exception $exception) {
            return ['Failed to save configuration: ' . $exception->getMessage()];
        }

        return [];
    }

    /**
     * Validate configuration data.
     *
     * @param array{
     *     enable_payments?: bool,
     *     payment_window_mode?: string,
     *     status_awaiting_confirmation?: string,
     *     status_confirmed_payment?: string,
     *     status_awaiting_payment?: string,
     *     payment_title?: string
     * } $configuration
     */
    public function validateConfiguration(array $configuration): bool
    {
        if (isset($configuration['payment_window_mode'])) {
            if (!in_array($configuration['payment_window_mode'], self::ALLOWED_PAYMENT_WINDOW_MODES, true)) {
                return false;
            }
        }

        return $this->validateRequiredStringFields($configuration);
    }

    /**
     * Get default configuration values.
     *
     * @return array{
     *     enable_payments: bool,
     *     payment_window_mode: string,
     *     status_awaiting_confirmation: string,
     *     status_confirmed_payment: string,
     *     status_awaiting_payment: string,
     *     payment_title: string
     * }
     */
    public static function getDefaults(): array
    {
        $defaults = [];

        foreach (self::getFieldConfig() as $field => $settings) {
            $defaults[$field] = $settings['default'];
        }

        return $defaults;
    }

    /**
     * @return bool|string
     */
    private function getConfigValue(string $key, mixed $default, string $type): mixed
    {
        $value = \Configuration::get($key, null, null, null, $default);

        return $type === self::TYPE_BOOL ? (bool) $value : (string) $value;
    }

    /**
     * @param array<string, mixed> $configuration
     */
    private function validateRequiredStringFields(array $configuration): bool
    {
        $stringFields = array_keys(
            array_filter(self::getFieldConfig(), fn ($settings) => $settings['type'] === self::TYPE_STRING)
        );

        foreach ($stringFields as $field) {
            if (isset($configuration[$field]) && trim((string) $configuration[$field]) === '') {
                return false;
            }
        }

        return true;
    }

    /**
     * @param array<string, mixed> $configuration
     */
    private function saveConfigurationValues(array $configuration): void
    {
        foreach (self::getFieldConfig() as $field => $settings) {
            if (!array_key_exists($field, $configuration)) {
                continue;
            }

            $value = $configuration[$field];

            if (is_bool($value)) {
                $value = $value ? '1' : '0';
            }

            \Configuration::updateValue($settings['key'], $value);
        }
    }
}
