<?php

declare(strict_types=1);

namespace Numinix\SeekmodoWordPress\LocalIndex;

/**
 * Public local search API for themes and grouped queries.
 */
final class LocalSearch
{
    /**
     * @param array{
     *   q: string,
     *   post_type?: array<int,string>|string,
     *   meta_query?: array<string,mixed>,
     *   post__not_in?: list<int>,
     *   page?: int,
     *   page_size?: int,
     *   vertical?: string
     * } $params
     * @return array{ids: list<int>, total: int, source: string}|null
     */
    public static function search(array $params): ?array
    {
        if (!numinix_seekmodo_enhanced_native_enabled() || !VerticalConfig::isEnabled()) {
            return null;
        }
        $q = trim((string) ($params['q'] ?? ''));
        if ($q === '') {
            return null;
        }
        $page = max(1, (int) ($params['page'] ?? 1));
        $pageSize = max(1, min(100, (int) ($params['page_size'] ?? 10)));
        $vertical = (string) ($params['vertical'] ?? 'content');
        $constraints = [];
        if (isset($params['post_type'])) {
            $constraints['post_type'] = $params['post_type'];
        }
        if (!empty($params['meta_query']) && is_array($params['meta_query'])) {
            $constraints['meta_query'] = $params['meta_query'];
        }
        if (!empty($params['post__not_in']) && is_array($params['post__not_in'])) {
            $constraints['post__not_in'] = $params['post__not_in'];
        }

        if ($vertical === 'commerce') {
            $result = LocalIndexRetriever::searchProducts($q, $page, $pageSize, $constraints);
        } else {
            $result = LocalIndexRetriever::search($q, $page, $pageSize, $constraints);
        }

        if ($result['ids'] === [] && $result['total'] === 0) {
            return ['ids' => [], 'total' => 0, 'source' => 'enhanced_native'];
        }

        return [
            'ids'    => $result['ids'],
            'total'  => $result['total'],
            'source' => 'enhanced_native',
        ];
    }

    /**
     * Hydrate a WP_Query from local index results.
     *
     * @param mixed $query WP_Query
     */
    public static function applyToQuery($query): bool
    {
        if (!is_object($query) || !method_exists($query, 'get') || !method_exists($query, 'set')) {
            return false;
        }
        $keyword = trim((string) $query->get('s'));
        if ($keyword === '') {
            return false;
        }

        $postType = $query->get('post_type');
        $constraints = [];
        if ($postType !== '' && $postType !== null) {
            $constraints['post_type'] = $postType;
        }
        $metaQuery = $query->get('meta_query');
        if (is_array($metaQuery) && $metaQuery !== [] && !$query->get('seekmodo_skip_meta_constraint')) {
            $constraints['meta_query'] = $metaQuery;
        }
        $notIn = $query->get('post__not_in');
        if (is_array($notIn) && $notIn !== []) {
            $constraints['post__not_in'] = array_map('intval', $notIn);
        }

        $page = max(1, (int) $query->get('paged'));
        if ($page <= 0) {
            $page = 1;
        }
        $pageSize = (int) $query->get('posts_per_page');
        if ($pageSize <= 0) {
            $pageSize = 10;
        }

        $vertical = ($postType === 'product' || (is_array($postType) && in_array('product', $postType, true)))
            ? 'commerce' : 'content';

        $result = self::search([
            'q'         => $keyword,
            'page'      => $page,
            'page_size' => $pageSize,
            'vertical'  => $vertical,
            'post_type' => $constraints['post_type'] ?? null,
            'meta_query'=> $constraints['meta_query'] ?? null,
            'post__not_in' => $constraints['post__not_in'] ?? null,
        ]);
        if ($result === null) {
            return false;
        }

        $ids = $result['ids'];
        $query->set('post__in', $ids !== [] ? $ids : [0]);
        $query->set('orderby', 'post__in');
        $query->set('s', '');
        $query->set('meta_query', []);
        $query->found_posts = $result['total'];
        $query->max_num_pages = $pageSize > 0 ? (int) ceil($result['total'] / $pageSize) : 1;

        return true;
    }
}
