<?php
namespace Newland\NeosViewHelpers\ViewHelpers\Format;

use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper;

/**
 * Pre-configured version of the `f:format.currency` view helper that sets
 * default values for arguments based on the currency symbol passed.
 */
class CurrencyViewHelper extends AbstractViewHelper
{

    /**
     * Mapping of ISO 4217 currency keys to `f:format.currency` configuration options.
     * The `DEFAULT` configuration is applied to all currencies.
     *
     * @var array
     */
    protected static $currencyConfiguration = [
        'DEFAULT' => [
            'prependCurrency' => false,
            'decimals' => 2,
        ],
        'EUR' => [
            'currencySign' => '€',
            'decimalSeparator' => ',',
            'thousandsSeparator' => '.',
        ],
        'CHF' => [
            'currencySign' => 'CHF',
            'decimalSeparator' => '.',
            'thousandsSeparator' => '\'',
        ],
        'GBP' => [
            'currencySign' => '£',
            'decimalSeparator' => '.',
            'thousandsSeparator' => ',',
        ],
        'USD' => [
            'currencySign' => '$',
            'decimalSeparator' => '.',
            'thousandsSeparator' => ',',
            'prependCurrency' => true,
        ],
    ];

    public function initializeArguments()
    {
        // phpcs:disable
        $this->registerArgument('currencySign', 'string', '(optional) The currency sign, eg $ or €.', false, '');
        $this->registerArgument('decimalSeparator', 'string', '(optional) The separator for the decimal point.', false, ',');
        $this->registerArgument('thousandsSeparator', 'string', '(optional) The thousands separator.', false, '.');
        $this->registerArgument('prependCurrency', 'boolean', '(optional) Indicates if currency symbol should be placed before or after the numeric value.', false, false);
        $this->registerArgument('separateCurrency', 'boolean', '(optional) Indicates if a space character should be placed between the number and the currency sign.', false, true);
        $this->registerArgument('decimals', 'integer', '(optional) The number of decimal places.', false, 2);
        $this->registerArgument('currencyCode', 'string', '(optional) The ISO 4217 currency code of the currency to format. Used to set decimal places and rounding.', false, null);
        // phpcs:enable
    }


    public function render(): string
    {
        $this->applyDefaults();
        $formatted = $this->formatNumber();
        $separator = $this->arguments['separateCurrency'] === true ? ' ' : '';
        $sign = $this->arguments['currencySign'];

        if ($this->arguments['prependCurrency'] === true) {
            $formatted = $sign . $separator . $formatted;
        } else {
            $formatted = $formatted . $separator . $sign;
        }

        return $formatted;
    }

    private function formatNumber(): string
    {
        $stringToFormat = $this->renderChildren();
        return number_format(
            (float) $stringToFormat,
            $this->arguments['decimals'],
            $this->arguments['decimalSeparator'],
            $this->arguments['thousandsSeparator']
        );
    }

    private function applyDefaults()
    {
        $currencyCode = $this->arguments['currencyCode'];
        if (array_key_exists($currencyCode, static::$currencyConfiguration)) {
            $this->applyArgumentsIfEmpty(static::$currencyConfiguration[$currencyCode]);
        }
        $this->applyArgumentsIfEmpty(static::$currencyConfiguration['DEFAULT']);

        if (!$this->arguments['currencySign']) {
            $this->arguments['currencySign'] = $this->arguments['currencyCode'];
        }
    }

    private function applyArgumentsIfEmpty(array $arguments)
    {
        foreach ($arguments as $key => $value) {
            if (!array_key_exists($key, $this->argumentDefinitions)) {
                continue;
            }

            if ($this->arguments[$key] === $this->argumentDefinitions[$key]->getDefaultValue()) {
                $this->arguments[$key] = $value;
            }
        }
    }
}
