<?php
/**
 * Normalize Bricks element display conditions.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Support;

use LolaCoreForBricks\Elements\IdGenerator;

/**
 * Conditions are OR groups of AND clauses stored in settings['_conditions'].
 */
final class ElementConditions
{
    /**
     * @var string[]
     */
    public const COMPARE = ['==', '!=', '>=', '<=', '>', '<', 'contains', 'contains_not'];

    /**
     * @param mixed $raw
     * @return array{success: true, conditions: array<int, 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 display conditions as a list. When should this element show?',
                'error'   => 'invalid_conditions',
            ];
        }

        if ($raw === []) {
            return [
                'success'    => true,
                'conditions' => [],
            ];
        }

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

        if (self::looksLikeNativeGroups($raw)) {
            $groups = [];
            foreach ($raw as $group) {
                $normalized = self::normalizeGroup($group, $ids, $taken);
                if (isset($normalized['error'])) {
                    return $normalized;
                }
                $groups[] = $normalized['group'];
            }

            return [
                'success'    => true,
                'conditions' => $groups,
            ];
        }

        $flat = self::normalizeGroup($raw, $ids, $taken);
        if (isset($flat['error'])) {
            return $flat;
        }

        return [
            'success'    => true,
            'conditions' => [$flat['group']],
        ];
    }

    /**
     * @param mixed $raw
     */
    private static function looksLikeNativeGroups(mixed $raw): bool
    {
        if (!is_array($raw) || $raw === []) {
            return false;
        }

        $first = reset($raw);

        return is_array($first) && isset($first[0]) && is_array($first[0]) && isset($first[0]['key']);
    }

    /**
     * @param mixed $raw
     * @param string[] $taken
     * @return array{group: array<int, array<string, mixed>>}|array{success: false, message: string, error: string}
     */
    private static function normalizeGroup(mixed $raw, IdGenerator $ids, array &$taken): array
    {
        if (!is_array($raw) || $raw === []) {
            return [
                'success' => false,
                'message' => 'Each condition needs a key. What should I check?',
                'error'   => 'invalid_condition',
            ];
        }

        $group = [];
        foreach ($raw as $item) {
            if (!is_array($item)) {
                return [
                    'success' => false,
                    'message' => 'Each condition needs a key. What should I check?',
                    'error'   => 'invalid_condition',
                ];
            }

            $key = (string) ($item['key'] ?? '');
            if ($key === '' || !preg_match('/^[a-z0-9_]+$/', $key)) {
                return [
                    'success' => false,
                    'message' => 'I do not recognize that condition. Use something like post_id, user_logged_in, or date.',
                    'error'   => 'invalid_condition_key',
                ];
            }

            $compare = (string) ($item['compare'] ?? '==');
            if (!in_array($compare, self::COMPARE, true)) {
                return [
                    'success' => false,
                    'message' => 'I do not recognize that comparison. Use ==, !=, contains, or a number comparison.',
                    'error'   => 'invalid_condition_compare',
                ];
            }

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

            $group[] = [
                'id'      => $id,
                'key'     => $key,
                'compare' => $compare,
                'value'   => $item['value'] ?? '',
            ];
        }

        return ['group' => $group];
    }
}
