<?php
/**
 * Normalize Bricks element interactions and reject custom JavaScript (Law 2).
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Support;

use LolaCoreForBricks\Elements\IdGenerator;

/**
 * Interactions live in settings['_interactions'].
 */
final class ElementInteractions
{
    /**
     * @var string[]
     */
    public const TRIGGERS = [
        'click',
        'mouseover',
        'focus',
        'blur',
        'mouseenter',
        'mouseleave',
        'enterView',
        'leaveView',
        'animationEnd',
        'ajaxStart',
        'ajaxEnd',
        'formSubmit',
        'formSuccess',
        'formError',
        'scroll',
        'contentLoaded',
        'mouseleaveWindow',
        'filterOptionEmpty',
        'filterOptionNotEmpty',
        'wooAddedToCart',
        'wooAddingToCart',
        'wooRemovedFromCart',
        'wooUpdateCart',
        'wooCouponApplied',
        'wooCouponRemoved',
    ];

    /**
     * @var string[]
     */
    public const ACTIONS = [
        'show',
        'hide',
        'click',
        'setAttribute',
        'removeAttribute',
        'toggleAttribute',
        'toggleOffCanvas',
        'loadMore',
        'loadMoreGallery',
        'startAnimation',
        'scrollTo',
        'openAddress',
        'closeAddress',
        'clearForm',
        'storageAdd',
        'storageRemove',
        'storageCount',
    ];

    /**
     * @param mixed $raw
     * @return array{success: true, interactions: array<int, array<string, mixed>>}|array{success: false, message: string, error: string}
     */
    public static function normalize(mixed $raw): array
    {
        if (!is_array($raw)) {
            return [
                'success' => false,
                'message' => 'I need the interactions as a list. What should happen on click or hover?',
                'error'   => 'invalid_interactions',
            ];
        }

        $ids   = new IdGenerator();
        $taken = [];
        $items = [];

        foreach ($raw as $item) {
            if (!is_array($item)) {
                return [
                    'success' => false,
                    'message' => 'Each interaction needs a trigger and an action.',
                    'error'   => 'invalid_interaction',
                ];
            }

            if (self::hasCustomJavascript($item)) {
                return [
                    'success' => false,
                    'message' => 'I cannot save interactions that run custom JavaScript. Use a built-in action such as show, hide, or start animation.',
                    'error'   => 'forbidden_code',
                ];
            }

            $trigger = (string) ($item['trigger'] ?? '');
            $action  = (string) ($item['action'] ?? '');
            if ($trigger === '' || !in_array($trigger, self::TRIGGERS, true)) {
                return [
                    'success' => false,
                    'message' => 'I need a trigger I recognize: click, hover, or enter viewport.',
                    'error'   => 'invalid_interaction_trigger',
                ];
            }

            if ($action === '' || !in_array($action, self::ACTIONS, true)) {
                return [
                    'success' => false,
                    'message' => 'I need an action I recognize: show, hide, scroll to, or start animation.',
                    'error'   => 'invalid_interaction_action',
                ];
            }

            $id = (string) ($item['id'] ?? '');
            if ($id === '' || !IdGenerator::isValid($id)) {
                $id = $ids->generate($taken);
            }
            $taken[] = $id;

            $item['id']      = $id;
            $item['trigger'] = $trigger;
            $item['action']  = $action;
            $items[]         = $item;
        }

        return [
            'success'      => true,
            'interactions' => $items,
        ];
    }

    /**
     * @param array<string, mixed> $item
     */
    public static function hasCustomJavascript(array $item): bool
    {
        $action = (string) ($item['action'] ?? '');
        if ($action === 'javascript') {
            return true;
        }

        foreach (['jsFunction', 'jsFunctionArgs', 'javascript'] as $key) {
            if (isset($item[$key]) && $item[$key] !== '' && $item[$key] !== []) {
                return true;
            }
        }

        return false;
    }
}
