<?php

namespace Storeplugin\PDFInvoice\Framework\Fields\Types;

defined('ABSPATH') || exit;

use Storeplugin\PDFInvoice\Framework\Abstracts\AbstractField;
use Storeplugin\PDFInvoice\Config;
use Storeplugin\PDFInvoice\Asset;

class Select2Field extends AbstractField
{
    private static bool $assetsEnqueued = false;

    /**
     * Get the field type.
     *
     * @return string
     */
    public static function getType(): string
    {
        return 'select2';
    }

    /**
     * Render the field.
     *
     * @param array  $field
     * @param mixed  $value
     * @param string $prefix
     *
     * @return string
     */
    public function render(array $field, $value, string $prefix): string
    {
        $options = $this->normalizeOptionDefinitions($field);
        if ($options === []) {
            return '';
        }

        $isDisabled = $this->hasTruthyFlag($field, 'disabled');
        $isRequired = $this->hasTruthyFlag($field, 'required');
        $disabledOptionLookup = $this->getDisabledOptionLookup($field);

        $support = $this->normalizeSupport($field['support'] ?? ['single', 'search']);
        $isMultiple = in_array('multi', $support, true);
        $allowSearch = in_array('search', $support, true);

        $placeholder = $field['placeholder'] ?? '';
        if (!is_string($placeholder)) {
            $placeholder = '';
        }

        $this->enqueueAssets();

        $selectAttrs = $this->buildAttributes([
            'id' => $this->getFieldId($field),
            'name' => $this->getFieldName($field['id'], $prefix, $isMultiple),
            'class' => $this->resolveClass($field, $this->getInputClasses()),
            'autocomplete' => $field['autocomplete'] ?? null,
            'multiple' => $isMultiple ? true : null,
            'disabled' => $isDisabled ? true : null,
            'required' => $isRequired ? true : null,
            'data-nxtf-select2' => '1',
            'data-nxtf-select2-search' => $allowSearch ? '1' : '0',
            'data-nxtf-select2-placeholder' => $placeholder !== '' ? $placeholder : null,
            'data-nxtf-disabled-options' => $this->getDisabledOptionsAttribute($disabledOptionLookup),
        ]);

        $optionItems = [];
        if (!$isMultiple && $placeholder !== '') {
            $optionItems[] = sprintf(
                '<option %s>%s</option>',
                $this->buildAttributes([
                    'value' => '',
                    'disabled' => isset($disabledOptionLookup['']) ? true : null,
                ]),
                \esc_html($placeholder)
            );
        }

        if ($isMultiple) {
            $selectedValues = is_array($value) ? array_map('strval', $value) : ($value !== '' ? [(string) $value] : []);
        } else {
            $selectedValue = (string) $value;
        }

        foreach ($options as $option) {
            $optionAttrs = $this->buildAttributes([
                'value' => $option['value'],
                'selected' => $isMultiple
                    ? in_array($option['value'], $selectedValues ?? [], true)
                    : $selectedValue === $option['value'],
                'disabled' => $option['disabled'] ? true : null,
                'title' => $option['title'] !== '' ? $option['title'] : null,
            ]);

            $optionItems[] = sprintf(
                '<option %s>%s</option>',
                $optionAttrs,
                \esc_html($option['label'])
            );
        }

        return sprintf('<select %s>%s</select>', $selectAttrs, implode('', $optionItems));
    }

    /**
     * Enqueue assets.
     */
    private function enqueueAssets(): void
    {
        if (self::$assetsEnqueued) {
            return;
        }

        self::$assetsEnqueued = true;

        Asset::registerFrameworkAssets();
        \wp_enqueue_style(Config::asset('select2-style'));
        \wp_enqueue_script(Config::asset('select2-script'));
    }

    /**
     * Normalize support.
     *
     * @param mixed $support
     *
     * @return array
     */
    private function normalizeSupport($support): array
    {
        $normalized = [];

        if (is_string($support)) {
            $support = [$support];
        }

        if (!is_array($support)) {
            $support = [];
        }

        foreach ($support as $featureName => $featureValue) {
            if (is_string($featureName) && is_bool($featureValue)) {
                if ($featureValue) {
                    $normalized[] = strtolower($featureName);
                }
                continue;
            }

            if (is_string($featureValue)) {
                $normalized[] = strtolower($featureValue);
            }
        }

        $normalized = array_unique($normalized);

        if (!in_array('multi', $normalized, true) && !in_array('single', $normalized, true)) {
            $normalized[] = 'single';
        }

        return $normalized;
    }
}
