<?php
declare(strict_types=1);

namespace Ekesto\CacheInvalidator;

/**
 * Internal normalized builder hint describing scan surface only.
 */
final class BuilderUsageHint
{
    /**
     * @var string[]
     */
    private array $postTypes;

    /**
     * @var array<int,array{type:string,key?:string,value?:string}>
     */
    private array $storageLocations;

    /**
     * @var array<int,array{type:string,key?:string,value?:string}>
     */
    private array $containerSelectors;

    private string $confidence;

    /**
     * @param string[]                                            $postTypes
     * @param array<int,array{type:string,key?:string,value?:string}> $storageLocations
     * @param array<int,array{type:string,key?:string,value?:string}> $containerSelectors
     * @param string                                              $confidence
     */
    public function __construct(
        array $postTypes,
        array $storageLocations,
        array $containerSelectors = [],
        string $confidence = 'deterministic'
    ) {
        $this->postTypes = ContentVisibility::normalizePostTypes($postTypes);
        $this->storageLocations = self::normalizeEntries($storageLocations, true);
        $this->containerSelectors = self::normalizeEntries($containerSelectors, false);
        $this->confidence = $confidence === 'partial' ? 'partial' : 'deterministic';

        if (empty($this->postTypes) || empty($this->storageLocations) || empty($this->containerSelectors)) {
            throw new \InvalidArgumentException('Builder usage hints require post types, storage locations, and container selectors.');
        }
    }

    /**
     * @return string[]
     */
    public function postTypes(): array
    {
        return $this->postTypes;
    }

    /**
     * @return array<int,array{type:string,key?:string,value?:string}>
     */
    public function storageLocations(): array
    {
        return $this->storageLocations;
    }

    /**
     * @return array<int,array{type:string,key?:string,value?:string}>
     */
    public function containerSelectors(): array
    {
        return $this->containerSelectors;
    }

    /**
     * @return string
     */
    public function confidence(): string
    {
        return $this->confidence;
    }

    /**
     * Normalize storage-location or selector entries.
     *
     * @param array<int,array{type:string,key?:string,value?:string}> $entries
     * @param bool $allowStorageLocations Whether storage-location entries are allowed.
     * @return array<int,array{type:string,key?:string,value?:string}>
     */
    private static function normalizeEntries(array $entries, bool $allowStorageLocations): array
    {
        $normalized = [];

        foreach ($entries as $entry) {
            if (!is_array($entry)) {
                continue;
            }

            $type = sanitize_key((string) ($entry['type'] ?? ''));
            if ($type === '') {
                continue;
            }

            if ($allowStorageLocations) {
                if ($type === 'post_content') {
                    $normalized['post_content'] = ['type' => 'post_content'];
                    continue;
                }

                if (in_array($type, ['post_meta', 'option'], true)) {
                    $key = sanitize_key((string) ($entry['key'] ?? ''));
                    if ($key === '') {
                        continue;
                    }

                    $normalized[$type . ':' . $key] = [
                        'type' => $type,
                        'key' => $key,
                    ];
                }

                continue;
            }

            if ($type === 'meta_exists') {
                $key = sanitize_key((string) ($entry['key'] ?? ''));
                if ($key === '') {
                    continue;
                }

                $normalized[$type . ':' . $key] = [
                    'type' => $type,
                    'key' => $key,
                ];
                continue;
            }

            if ($type === 'post_content_contains') {
                $value = trim((string) ($entry['value'] ?? ''));
                if ($value === '') {
                    continue;
                }

                $normalized[$type . ':' . $value] = [
                    'type' => $type,
                    'value' => $value,
                ];
            }
        }

        return array_values($normalized);
    }
}
