<?php

declare(strict_types=1);

namespace Numinix\SeekmodoWordPress\Elementor\Widgets;

use Numinix\SeekmodoWordPress\Blocks\AttributeSchema;
use Numinix\SeekmodoWordPress\Elementor\Category;

/**
 * Sprint 11 PR 2 — shared base class for the four Seekmodo
 * Elementor widgets. Each concrete widget plugs in its element
 * slug ({@see elementSlug()}) and the rest is data-driven via
 * {@see \Numinix\SeekmodoWordPress\Blocks\AttributeSchema} so
 * the Elementor surface and the Gutenberg surface (PR 1) cannot
 * drift.
 *
 * Class definition is gated on `\Elementor\Widget_Base` existing
 * so a connector install on a site without Elementor doesn't
 * fatal when something autoloads this file. With Elementor active
 * (production) the parent class exists. In unit tests, a minimal
 * stub is registered before the autoloader fires (see
 * `tests/elementor-shims.php`).
 */
if (!class_exists(\Elementor\Widget_Base::class)) {
    return;
}

abstract class AbstractSeekmodoWidget extends \Elementor\Widget_Base
{
    /**
     * Element slug for the AttributeSchema lookup. One of:
     * `search`, `recommend`, `chat`, `quiz`.
     */
    abstract protected function elementSlug(): string;

    public function get_categories()
    {
        return [Category::SLUG];
    }

    public function get_keywords()
    {
        return ['seekmodo', 'search', 'ai', 'recommendations', 'chat'];
    }

    /**
     * Wire Elementor controls from the shared attribute schema.
     */
    protected function register_controls()
    {
        $this->start_controls_section(
            'section_seekmodo_attributes',
            [
                'label' => function_exists('esc_html__')
                    ? esc_html__('Settings', 'seekmodo')
                    : 'Settings',
                'tab'   => \Elementor\Controls_Manager::TAB_CONTENT,
            ]
        );

        $attrs = AttributeSchema::attributesFor($this->elementSlug());
        foreach ($attrs as $attr) {
            $this->add_control($attr['key'], $this->controlConfigFor($attr));
        }

        $this->end_controls_section();
    }

    /**
     * Render the matching `<seekmodo-...>` element on the front-end.
     */
    protected function render()
    {
        $settings = $this->get_settings_for_display();
        $values   = [];

        foreach (AttributeSchema::attributesFor($this->elementSlug()) as $attr) {
            $key = $attr['key'];
            if (array_key_exists($key, (array) $settings)) {
                $value = $settings[$key];
                if ($attr['type'] === 'boolean') {
                    $values[$key] = ($value === 'yes') || ($value === true) || ($value === 1) || ($value === '1');
                } else {
                    $values[$key] = $value;
                }
            }
        }

        // Tag name is whitelist-controlled; attribute values are esc_attr()'d in AttributeSchema::render().
        echo AttributeSchema::render($this->elementSlug(), $values); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
    }

    /**
     * Map an attribute schema entry to an Elementor control
     * configuration. Public for unit testing.
     *
     * @param array{key:string,attribute:string,type:string,default:mixed,label:string,description:string} $attr
     *
     * @return array<string, mixed>
     */
    public function controlConfigFor(array $attr): array
    {
        $config = [
            'label'   => $attr['label'],
            'description' => $attr['description'],
        ];

        switch ($attr['type']) {
            case 'boolean':
                $config['type']     = \Elementor\Controls_Manager::SWITCHER;
                $config['return_value'] = 'yes';
                $config['default']  = $attr['default'] ? 'yes' : '';
                $config['label_on'] = function_exists('esc_html__') ? esc_html__('On', 'seekmodo') : 'On';
                $config['label_off'] = function_exists('esc_html__') ? esc_html__('Off', 'seekmodo') : 'Off';
                break;
            case 'number':
                $config['type']    = \Elementor\Controls_Manager::NUMBER;
                $config['default'] = $attr['default'];
                break;
            case 'string':
            default:
                if (strlen((string) ($attr['default'] ?? '')) > 60 || $attr['key'] === 'inlineDefinition' || $attr['key'] === 'intro') {
                    $config['type'] = \Elementor\Controls_Manager::TEXTAREA;
                } else {
                    $config['type'] = \Elementor\Controls_Manager::TEXT;
                }
                $config['default'] = (string) ($attr['default'] ?? '');
                break;
        }

        return $config;
    }
}
