<?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\Form\DataProvider;

use SimplyIn\BackOffice\ConfigurationKey;
use SimplyIn\BackOffice\ConfigurationRepository;
use SimplyIn\BackOffice\Environment;

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

final class SettingsDataProvider
{
    // 'environment' and 'secret_key' are handled separately in getData()/saveData(): the
    // environment must default through the closed allowlist, and the API key lives in a slot
    // that depends on which environment is selected — neither is a flat 1-1 config lookup.
    private const PERSISTED_FIELDS = [
        'save_checkbox' => ConfigurationKey::SAVE_CHECKBOX,
        'payments_enabled' => ConfigurationKey::PAYMENTS_ENABLED,
        'dpd_carrier_id' => ConfigurationKey::DPD_CARRIER_ID,
        'dhl_carrier_id' => ConfigurationKey::DHL_CARRIER_ID,
        'fedex_carrier_id' => ConfigurationKey::FEDEX_CARRIER_ID,
        'inpost_carrier_id' => ConfigurationKey::INPOST_CARRIER_ID,
        'orlen_carrier_id' => ConfigurationKey::ORLEN_CARRIER_ID,
        'ups_carrier_id' => ConfigurationKey::UPS_CARRIER_ID,
        'default_carrier_id' => ConfigurationKey::DEFAULT_CARRIER_ID,
        'payment_status_pending' => ConfigurationKey::PAYMENT_STATUS_PENDING,
        'payment_status_canceled' => ConfigurationKey::PAYMENT_STATUS_CANCELED,
        'bar_enabled' => ConfigurationKey::BAR_ENABLED,
        'bar_color' => ConfigurationKey::BAR_COLOR,
        'badge_color' => ConfigurationKey::BADGE_COLOR,
        'accent_color' => ConfigurationKey::ACCENT_COLOR,
        'font_color' => ConfigurationKey::FONT_COLOR,
        'confirmation_heading_override' => ConfigurationKey::CONFIRMATION_HEADING_OVERRIDE,
    ];

    private const BOOLEAN_FIELDS = ['save_checkbox', 'payments_enabled', 'bar_enabled', 'bar_color', 'badge_color', 'confirmation_heading_override'];

    /**
     * Per-field default for a BOOLEAN_FIELDS entry that has never been stored, read instead of the
     * blanket `false` {@see getData()} otherwise applies. `confirmation_heading_override` is the
     * only field so far where "never touched" should read as ON: a payment plugin telling the
     * truth about payment state is its core job.
     */
    private const BOOLEAN_DEFAULTS = [
        'confirmation_heading_override' => true,
    ];

    private const STRING_DEFAULTS = [
        'accent_color' => '#2d40f6',
        'font_color' => '#000000',
    ];
    private const INTEGER_FIELDS = [
        'dpd_carrier_id',
        'dhl_carrier_id',
        'fedex_carrier_id',
        'inpost_carrier_id',
        'orlen_carrier_id',
        'ups_carrier_id',
        'default_carrier_id',
        'payment_status_pending',
        'payment_status_canceled',
    ];

    public function __construct(
        private readonly ConfigurationRepository $config,
    ) {
    }

    /**
     * @return array<string, mixed>
     */
    public function getData(): array
    {
        $environment = $this->config->getEnvironment();
        $data = [
            'environment' => $environment->value,
            'secret_key' => $this->config->getApiKey($environment),
        ];
        foreach (self::PERSISTED_FIELDS as $field => $key) {
            if (in_array($field, self::BOOLEAN_FIELDS, true)) {
                $data[$field] = $this->config->getBool($key, self::BOOLEAN_DEFAULTS[$field] ?? false);
            } elseif (in_array($field, self::INTEGER_FIELDS, true)) {
                $data[$field] = $this->config->getInt($key);
            } else {
                // The only fields left in this branch are accent_color/font_color (every other
                // PERSISTED_FIELDS entry is boolean or integer) — both always have a default.
                $value = $this->config->getString($key);
                $data[$field] = $value === '' ? self::STRING_DEFAULTS[$field] : $value;
            }
        }

        if ($this->config->getBool(ConfigurationKey::CHECKBOX_FORCED_DISABLED)) {
            $data['save_checkbox'] = true;
        }

        return $data;
    }

    /**
     * @param array<string, mixed> $data
     */
    public function saveData(array $data): void
    {
        $forced = $this->config->getBool(ConfigurationKey::CHECKBOX_FORCED_DISABLED);

        // Resolve the submitted environment through the allowlist before anything else, so the
        // API key below is written into the correct slot — and never touches the other one.
        $environment = array_key_exists('environment', $data)
            ? Environment::fromStoredValue((string) $data['environment'])
            : $this->config->getEnvironment();
        if (array_key_exists('environment', $data)) {
            $this->config->setEnvironment($environment);
        }
        if (array_key_exists('secret_key', $data)) {
            $this->config->setApiKey($environment, (string) $data['secret_key']);
        }

        foreach (self::PERSISTED_FIELDS as $field => $key) {
            if (!array_key_exists($field, $data)) {
                continue;
            }
            if ($field === 'save_checkbox' && $forced) {
                continue;
            }
            $value = $data[$field];
            if (in_array($field, self::BOOLEAN_FIELDS, true)) {
                $this->config->set($key, $value ? 1 : 0);
            } elseif (in_array($field, self::INTEGER_FIELDS, true)) {
                $this->config->set($key, (int) $value);
            } else {
                $this->config->set($key, (string) $value);
            }
        }

        if (array_key_exists('save_checkbox', $data) && !$forced) {
            $this->config->set(ConfigurationKey::SAVE_CHECKBOX_OVERRIDDEN, true);
        }
    }
}
