<?php

namespace Storeplugin\PDFInvoice\Framework\Fields\Types;

defined('ABSPATH') || exit;

use Storeplugin\PDFInvoice\Framework\Abstracts\AbstractField;

class WysiwygField extends AbstractField
{
    private static bool $editor_enqueued = false;
    private static bool $media_enqueued = false;

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

    /**
     * Render the field.
     *
     * @param array  $field
     * @param mixed  $value
     * @param string $prefix
     *
     * @return string
     */
    public function render(array $field, $value, string $prefix): string
    {
        $isDisabled = $this->hasTruthyFlag($field, 'disabled');
        $isReadonly = !$isDisabled && $this->hasTruthyFlag($field, 'readonly');
        $isRequired = $this->hasTruthyFlag($field, 'required');
        $isLocked = $isDisabled || $isReadonly;
        $settings = $this->buildEditorSettings($field);
        $shouldEnqueueMedia = !empty($settings['mediaButtons']);
        if ($isLocked) {
            $settings = $this->buildReadonlyEditorSettings($settings);
        }

        $shouldEnhance = $this->shouldInitializeEditor($settings);

        $this->enqueueAssets($shouldEnqueueMedia);

        $rows = $this->resolveRows($field);
        $settings_json = null;
        if ($shouldEnhance) {
            $settings_json = \wp_json_encode($settings);
            if (!is_string($settings_json) || $settings_json === '') {
                $settings_json = null;
            }
        }

        $wrapper_attrs = $this->buildAttributes([
            'class' => trim('nxtf-wysiwyg-field'
                . ($isLocked ? ' nxtf-wysiwyg-locked' : '')
                . ($isDisabled ? ' nxtf-wysiwyg-disabled' : '')
                . ($isReadonly ? ' nxtf-wysiwyg-readonly' : '')),
        ]);

        $textarea_attrs = $this->buildAttributes([
            'id' => $this->getFieldId($field),
            'name' => $this->getFieldName($field['id'], $prefix),
            'rows' => $rows,
            'class' => $this->resolveClass($field, $this->getInputClasses(), '', 'editor_class', 'editor_extra_class'),
            // Keep rich editor rendering for locked WYSIWYG fields; server-side locking prevents mutation on save.
            'disabled' => ($isDisabled && !$shouldEnhance) ? true : null,
            'readonly' => $isLocked ? true : null,
            'required' => $isRequired ? true : null,
            'data-wysiwyg' => $shouldEnhance ? '1' : null,
            'data-wysiwyg-settings' => $shouldEnhance ? $settings_json : null,
        ]);

        return sprintf(
            '<div %s><textarea %s>%s</textarea></div>',
            $wrapper_attrs,
            $textarea_attrs,
            \esc_textarea((string) $value)
        );
    }

    /**
     * Resolve rows.
     *
     * @param array $field
     *
     * @return int
     */
    private function resolveRows(array $field): int
    {
        $rows = $field['rows'] ?? $field['textarea_rows'] ?? 8;
        if (!is_numeric($rows)) {
            $rows = 8;
        }

        return max(3, (int) $rows);
    }

    /**
     * Determine whether the editor should be enhanced by wp.editor.
     *
     * @param array $settings
     * @return bool
     */
    private function shouldInitializeEditor(array $settings): bool
    {
        return $this->isEditorModeEnabled($settings['tinymce'] ?? false)
            || $this->isEditorModeEnabled($settings['quicktags'] ?? false);
    }

    /**
     * Build editor settings.
     *
     * @param array $field
     *
     * @return array
     */
    private function buildEditorSettings(array $field): array
    {
        $settings = [
            'tinymce' => $this->normalizeEditorSetting($field['tinymce'] ?? true, true),
            'quicktags' => $this->normalizeEditorSetting($field['quicktags'] ?? true, true),
            'mediaButtons' => $this->isTruthy($field['media_buttons'] ?? false),
        ];

        if (isset($field['editor_settings']) && is_array($field['editor_settings'])) {
            $settings = array_replace_recursive($settings, $field['editor_settings']);
        }

        return $settings;
    }

    /**
     * Make the editor settings safe for read-only display.
     *
     * Quicktags are intentionally disabled for locked fields; they provide
     * raw-HTML editing controls that should not appear in a read-only context.
     * Rich visual display is only preserved when TinyMCE is enabled.
     *
     * @param array $settings
     * @return array
     */
    private function buildReadonlyEditorSettings(array $settings): array
    {
        $settings['mediaButtons'] = false;
        $settings['quicktags'] = false;

        if ($settings['tinymce'] === false) {
            return $settings;
        }

        if ($settings['tinymce'] === true || !is_array($settings['tinymce'])) {
            $settings['tinymce'] = [];
        }

        $settings['tinymce']['readonly'] = 1;

        return $settings;
    }

    /**
     * Normalize editor setting.
     *
     * @param mixed $value
     * @param bool  $default
     *
     * @return array|bool
     */
    private function normalizeEditorSetting($value, bool $default)
    {
        if (is_array($value)) {
            return $value;
        }

        if (is_bool($value)) {
            return $value;
        }

        if (is_string($value)) {
            return $this->isTruthy($value);
        }

        if (is_int($value)) {
            return $value === 1;
        }

        return $default;
    }

    /**
     * Determine whether an editor mode should initialize.
     *
     * Empty config arrays intentionally count as enabled, because WordPress
     * treats them as "use default settings", not "disable this mode".
     *
     * @param mixed $value
     * @return bool
     */
    private function isEditorModeEnabled($value): bool
    {
        return $value === true || is_array($value);
    }

    /**
     * Enqueue assets.
     *
     * @param bool $media_buttons
     */
    private function enqueueAssets(bool $media_buttons): void
    {
        if (!self::$editor_enqueued && function_exists('wp_enqueue_editor')) {
            \wp_enqueue_editor();
            self::$editor_enqueued = true;
        }

        if ($media_buttons && !self::$media_enqueued && function_exists('wp_enqueue_media')) {
            \wp_enqueue_media();
            self::$media_enqueued = true;
        }
    }
}
