<?php

declare(strict_types=1);

namespace Numinix\SeekmodoWordPress\Search;

use Numinix\SeekmodoSdk\Search\EnhancedNativeOrchestrator;
use Numinix\SeekmodoSdk\Search\FallbackBundle;
use Numinix\SeekmodoSdk\Search\LkgCache;
use Numinix\SeekmodoSdk\Search\QueryNormalizer;
use Numinix\SeekmodoSdk\Storage\InMemoryCache;
use Numinix\SeekmodoWordPress\Config\Options;
use Numinix\SeekmodoWordPress\Config\RemoteConfig;
use Numinix\SeekmodoWordPress\Content\PostTypeRegistry;
use Numinix\SeekmodoWordPress\Events\EventsQueue;
use Numinix\SeekmodoWordPress\LocalIndex\LocalIndexRetriever;
use Numinix\SeekmodoWordPress\LocalIndex\LocalMerchandising;
use Numinix\SeekmodoWordPress\LocalIndex\VerticalConfig;

/**
 * Wires SDK Enhanced Native orchestrator for WordPress/Woo.
 */
final class EnhancedNativeRegistry
{
    private static ?EnhancedNativeOrchestrator $orchestrator = null;

    public static function orchestrator(): ?EnhancedNativeOrchestrator
    {
        if (!class_exists(EnhancedNativeOrchestrator::class)) {
            return null;
        }
        if (self::$orchestrator === null) {
            $cache = new WpTransientCache();
            $bundleWrapper = new FallbackBundle($cache);
            $snap = RemoteConfig::cached();
            if (is_array($snap)) {
                $bundleWrapper->ingestFromSnapshot($snap);
            }
            $stored = get_option(Options::OPT_FALLBACK_BUNDLE, null);
            if (is_array($stored)) {
                $bundleWrapper->ingestFromSnapshot(['fallback_bundle' => $stored]);
            }
            self::injectLocalMerchandising($cache, $bundleWrapper);

            $bias = new \Numinix\SeekmodoSdk\Search\LocalClickBias();
            $bias->load(EventsQueue::recentClicks(7));
            self::$orchestrator = new EnhancedNativeOrchestrator(
                new QueryNormalizer(2, 120, true),
                new LkgCache($cache),
                $bundleWrapper,
                null,
                null,
                null,
                $bias
            );
        }

        return self::$orchestrator;
    }

    /**
     * @return array{ids: list<int>, total: int, source: string, stale: bool}|null
     */
    public static function runContentSearch(string $q, int $page, int $pageSize): ?array
    {
        $orch = self::orchestrator();
        if ($orch === null) {
            return null;
        }

        return $orch->run($q, static function (string $expanded) use ($page, $pageSize): array {
            return self::retrieveContent($expanded, $page, $pageSize);
        });
    }

    /**
     * @return array{ids: list<int>, total: int, source: string, stale: bool}|null
     */
    public static function runCommerceSearch(string $q, int $page, int $pageSize): ?array
    {
        $orch = self::orchestrator();
        if ($orch === null) {
            return null;
        }

        return $orch->run($q, static function (string $expanded) use ($page, $pageSize): array {
            return self::retrieveCommerce($expanded, $page, $pageSize);
        });
    }

    /**
     * @return list<array<string,mixed>>
     */
    public static function runContentTypeahead(string $q, int $max): array
    {
        if (VerticalConfig::shouldUseLocalIndex('content')) {
            return LocalIndexRetriever::typeaheadRows($q, $max, 'content');
        }
        $orch = self::orchestrator();
        if ($orch === null) {
            return WpContentRetriever::typeaheadRows($q, $max);
        }
        $result = $orch->run($q, static function (string $expanded): array {
            $r = self::retrieveContent($expanded, 1, $max);

            return ['ids' => $r['ids'], 'total' => $r['total']];
        });

        return WpContentRetriever::rowsFromIds($result['ids'], $max);
    }

    /**
     * @return list<array<string,mixed>>
     */
    public static function runCommerceTypeahead(string $q, int $max): array
    {
        if (VerticalConfig::shouldUseLocalIndex('commerce')) {
            return LocalIndexRetriever::typeaheadRows($q, $max, 'commerce');
        }
        $orch = self::orchestrator();
        if ($orch === null) {
            return WooCommerceRetriever::typeaheadRows($q, $max);
        }
        $result = $orch->run($q, static function (string $expanded): array {
            $r = self::retrieveCommerce($expanded, 1, $max);

            return ['ids' => $r['ids'], 'total' => $r['total']];
        });

        return WooCommerceRetriever::rowsFromIds($result['ids'], $max);
    }

    public static function recordGatewayIds(string $q, array $ids): void
    {
        $orch = self::orchestrator();
        if ($orch === null) {
            return;
        }
        $orch->recordGatewaySuccess($q, $ids);
    }

    /**
     * @return array{ids: list<int>, total: int}
     */
    private static function retrieveContent(string $q, int $page, int $pageSize): array
    {
        if (VerticalConfig::shouldUseLocalIndex('content')) {
            return LocalIndexRetriever::search($q, $page, $pageSize, [
                'post_type' => PostTypeRegistry::indexable(),
            ]);
        }

        return WpContentRetriever::search($q, $page, $pageSize);
    }

    /**
     * @return array{ids: list<int>, total: int}
     */
    private static function retrieveCommerce(string $q, int $page, int $pageSize): array
    {
        if (VerticalConfig::shouldUseLocalIndex('commerce')) {
            return LocalIndexRetriever::searchProducts($q, $page, $pageSize);
        }

        return WooCommerceRetriever::search($q, $page, $pageSize);
    }

    private static function injectLocalMerchandising(WpTransientCache $cache, FallbackBundle $bundleWrapper): void
    {
        $merged = LocalMerchandising::mergeIntoBundle($bundleWrapper->get());
        if ($merged['synonyms'] === [] && $merged['pins'] === [] && $merged['rescue'] === []) {
            return;
        }
        $cache->set(FallbackBundle::CACHE_KEY, $merged, FallbackBundle::EXTENDED_TTL);
    }
}
