<?php

declare(strict_types=1);

namespace App\Framework\Search;

/**
 * Central registry for searchable entity mappings
 */
final class SearchableMappingRegistry
{
    /** @var array<string, SearchableMapping> */
    private array $mappingsByEntityType = [];

    /** @var array<string, SearchableMapping> */
    private array $mappingsByEntityClass = [];

    public function register(SearchableMapping $mapping): void
    {
        $this->mappingsByEntityType[$mapping->entityType] = $mapping;
        $this->mappingsByEntityClass[$mapping->entityClass] = $mapping;
    }

    public function getByEntityType(string $entityType): ?SearchableMapping
    {
        return $this->mappingsByEntityType[$entityType] ?? null;
    }

    public function getByEntityClass(string $entityClass): ?SearchableMapping
    {
        return $this->mappingsByEntityClass[$entityClass] ?? null;
    }

    public function hasMapping(string $entityTypeOrClass): bool
    {
        return isset($this->mappingsByEntityType[$entityTypeOrClass])
            || isset($this->mappingsByEntityClass[$entityTypeOrClass]);
    }

    public function getAllMappings(): array
    {
        return array_values($this->mappingsByEntityType);
    }

    public function getEntityTypes(): array
    {
        return array_keys($this->mappingsByEntityType);
    }

    /**
     * Create adapter for entity
     */
    public function createAdapter(object $entity): ?SearchableAdapter
    {
        $entityClass = get_class($entity);
        $mapping = $this->getByEntityClass($entityClass);

        if (! $mapping || ! $mapping->enabled) {
            return null;
        }

        return new SearchableAdapter($entity, $mapping);
    }

    /**
     * Check if entity is searchable
     */
    public function isSearchable(object|string $entityOrClass): bool
    {
        $entityClass = is_object($entityOrClass) ? get_class($entityOrClass) : $entityOrClass;
        $mapping = $this->getByEntityClass($entityClass);

        return $mapping && $mapping->enabled;
    }

    /**
     * Bulk register mappings from configuration
     */
    public function registerFromConfig(array $config): void
    {
        foreach ($config as $entityClass => $mappingConfig) {
            $builder = SearchableMapping::for($entityClass);

            if (isset($mappingConfig['entity_type'])) {
                $builder->entityType($mappingConfig['entity_type']);
            }

            if (isset($mappingConfig['id_field'])) {
                $builder->idField($mappingConfig['id_field']);
            }

            if (isset($mappingConfig['auto_index'])) {
                $builder->autoIndex($mappingConfig['auto_index']);
            }

            if (isset($mappingConfig['enabled'])) {
                $builder->enabled($mappingConfig['enabled']);
            }

            // Add field mappings
            foreach ($mappingConfig['fields'] ?? [] as $searchField => $fieldConfig) {
                if (is_string($fieldConfig)) {
                    // Simple mapping: 'title' => 'name'
                    $builder->field($searchField, $fieldConfig);
                } elseif (is_array($fieldConfig)) {
                    // Complex mapping with transformer
                    $entityField = $fieldConfig['field'];
                    $transformer = $fieldConfig['transformer'] ?? null;

                    if ($transformer && is_string($transformer) && function_exists($transformer)) {
                        $transformer = $transformer(...);
                    }

                    $builder->field($searchField, $entityField, $transformer);
                }
            }

            // Add boosts
            foreach ($mappingConfig['boosts'] ?? [] as $field => $boost) {
                $builder->boost($field, (float) $boost);
            }

            $this->register($builder->build());
        }
    }
}
