<?php

declare(strict_types=1);

namespace Numinix\SeekmodoWordPress\LocalIndex;

/**
 * Two-phase meta_query intersection preserving relevance order.
 */
final class MetaConstraintFilter
{
    /**
     * @param list<int> $candidateIds Ranked candidate post IDs.
     * @param array<string,mixed> $constraints WP_Query-style args subset.
     * @return list<int>
     */
    public static function filter(array $candidateIds, array $constraints): array
    {
        if ($candidateIds === []) {
            return [];
        }
        if (!function_exists('get_posts')) {
            return $candidateIds;
        }

        $args = [
            'post__in'       => $candidateIds,
            'posts_per_page' => -1,
            'post_status'    => 'publish',
            'orderby'        => 'post__in',
            'fields'         => 'ids',
            'no_found_rows'  => true,
            'suppress_filters' => true, // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters -- batch/index query must bypass filters
        ];

        if (isset($constraints['post_type'])) {
            $args['post_type'] = $constraints['post_type'];
        }
        if (!empty($constraints['meta_query']) && is_array($constraints['meta_query'])) {
            $args['meta_query'] = $constraints['meta_query'];
        }

        $filtered = get_posts($args);
        if (!is_array($filtered) || $filtered === []) {
            return [];
        }
        $allowed = array_fill_keys(array_map('intval', $filtered), true);
        $out = [];
        foreach ($candidateIds as $id) {
            if (isset($allowed[(int) $id])) {
                $out[] = (int) $id;
            }
        }

        return $out;
    }
}
