<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */

namespace Piwik\Plugins\CorePluginsAdmin;

use Piwik\Common;
use Piwik\Piwik;
use Piwik\Policy\PolicyManager;
use Piwik\Settings\FieldConfig;
use Piwik\Settings\Setting;
use Piwik\Settings\Settings;
use Exception;

class SettingsMetadata
{
    public const PASSWORD_PLACEHOLDER = '******';

    public const EMPTY_ARRAY = '__empty__';

    /**
     * @param Settings[]  $settingsInstances
     * @param array $settingValues   array('pluginName' => array('settingName' => 'settingValue'))
     * @throws Exception;
     */
    public function setPluginSettings($settingsInstances, $settingValues)
    {
        try {
            foreach ($settingsInstances as $pluginName => $pluginSetting) {
                foreach ($pluginSetting->getSettingsWritableByCurrentUser() as $setting) {
                    $value = $this->findSettingValueFromRequest($settingValues, $pluginName, $setting->getName());

                    $fieldConfig = $setting->configureField();

                    // empty arrays are sent as __empty__ value, so we need to convert it here back to an array
                    if ($setting->getType() === FieldConfig::TYPE_ARRAY && $value === self::EMPTY_ARRAY) {
                        $value = [];
                    }

                    if (
                        isset($value) && (
                        $fieldConfig->uiControl !== FieldConfig::UI_CONTROL_PASSWORD ||
                        $value !== self::PASSWORD_PLACEHOLDER
                        )
                    ) {
                        $setting->setValue($value);
                    }
                }
            }
        } catch (Exception $e) {
            $message = $e->getMessage();

            if (!empty($setting)) {
                $title = Piwik::translate(strip_tags($setting->configureField()->title));
                if (strpos($message, $title) !== 0) {
                    // only prefix it if not already prefixed
                    $message = $title . ': ' . $message;
                }
                throw new Exception($message);
            }
        }
    }

    private function findSettingValueFromRequest($settingValues, $pluginName, $settingName)
    {
        if (!array_key_exists($pluginName, $settingValues)) {
            return;
        }

        foreach ($settingValues[$pluginName] as $setting) {
            if ($setting['name'] === $settingName) {
                $value = null;
                if (array_key_exists('value', $setting)) {
                    $value = $setting['value'];
                }

                if (is_string($value)) {
                    return Common::unsanitizeInputValue($value);
                }

                return $value;
            }
        }
    }


    /**
     * @param Settings[] $allSettings A list of Settings instead by pluginname
     * @return array
     */
    public function formatSettings(array $allSettings, ?int $idSite = null)
    {
        $metadata = array();
        foreach ($allSettings as $pluginName => $settings) {
            $writableSettings = $settings->getSettingsWritableByCurrentUser();

            if (empty($writableSettings)) {
                continue;
            }

            $plugin = array(
                'pluginName' => $pluginName,
                'title' => $settings->getTitle(),
                'settings' => array(),
            );

            foreach ($writableSettings as $writableSetting) {
                $plugin['settings'][] = $this->formatSetting($writableSetting, $idSite);
            }

            $metadata[] = $plugin;
        }

        return $metadata;
    }

    public function formatSetting(Setting $setting, ?int $idSite = null)
    {
        $config = $setting->configureField();

        $availableValues = $config->availableValues;

        if (is_array($availableValues)) {
            $availableValues = (object) $availableValues;
        }

        $value = $setting->getValue();

        if (!empty($value) && $config->uiControl === FieldConfig::UI_CONTROL_PASSWORD) {
            $value = self::PASSWORD_PLACEHOLDER;
        }

        $result = [
            'name' => $setting->getName(),
            'title' => $config->title,
            'value' => $value,
            'defaultValue' => $setting->getDefaultValue(),
            'type' => $setting->getType(),
            'uiControl' => $config->uiControl,
            'uiControlAttributes' => $config->uiControlAttributes,
            'availableValues' => $availableValues,
            'description' => $config->description,
            'inlineHelp' => $config->inlineHelp,
            'introduction' => $config->introduction,
            'condition' => $config->condition,
            'fullWidth' => $config->fullWidth,
        ];

        if ($config->customFieldComponent) {
            $result['component'] = $config->customFieldComponent;
        }

        $settingType = PolicyManager::getSettingTypeFromSettingClass($setting);
        $compliancePolicyControlled = PolicyManager::getCompliancePoliciesControllingASetting($setting->getName(), $idSite, $settingType);
        if (!empty($compliancePolicyControlled)) {
            $result['extraMetadata'] = [
                'compliancePolicyControlled' => $compliancePolicyControlled,
                'idSite' => $idSite,
            ];
        }

        return $result;
    }
}
