<?php

declare(strict_types=1);

namespace Numinix\SeekmodoWordPress\LocalIndex;

/**
 * Dynamic search excerpts with hit highlighting.
 */
final class ExcerptBuilder
{
    public static function forPost(int $post_id, string $query, int $length = 240): string
    {
        if (!function_exists('get_post')) {
            return '';
        }
        $post = get_post($post_id);
        if (!$post) {
            return '';
        }
        $parsed = QueryParser::parse($query);
        $terms = array_merge($parsed['terms'], $parsed['phrases']);
        $candidates = [
            (string) ($post->post_excerpt ?? ''),
            (string) ($post->post_content ?? ''),
        ];
        if (function_exists('get_post_meta')) {
            foreach (IndexSettings::defaultMetaKeys() as $key) {
                $val = get_post_meta($post_id, $key, true);
                if (is_string($val) && trim($val) !== '') {
                    $candidates[] = $val;
                }
            }
        }
        $best = '';
        $bestScore = -1;
        foreach ($candidates as $raw) {
            $plain = wp_strip_all_tags($raw);
            $plain = trim(preg_replace('/\s+/u', ' ', $plain) ?? '');
            if ($plain === '') {
                continue;
            }
            $score = self::hitScore(mb_strtolower($plain), $terms);
            if ($score > $bestScore) {
                $bestScore = $score;
                $best = $plain;
            }
        }
        if ($best === '') {
            $best = (string) ($post->post_title ?? '');
        }
        $snippet = mb_strlen($best) > $length ? mb_substr($best, 0, $length) . '…' : $best;

        return self::highlight($snippet, $terms);
    }

    public static function highlightTitle(string $title, string $query): string
    {
        $parsed = QueryParser::parse($query);

        return self::highlight($title, array_merge($parsed['terms'], $parsed['phrases']));
    }

    /**
     * @param list<string> $terms
     */
    private static function hitScore(string $text, array $terms): int
    {
        $score = 0;
        foreach ($terms as $term) {
            if ($term !== '' && str_contains($text, $term)) {
                $score++;
            }
        }

        return $score;
    }

    /**
     * @param list<string> $terms
     */
    private static function highlight(string $text, array $terms): string
    {
        if ($terms === []) {
            return esc_html($text);
        }
        usort($terms, static fn ($a, $b) => mb_strlen($b) <=> mb_strlen($a));
        $out = esc_html($text);
        foreach ($terms as $term) {
            if ($term === '') {
                continue;
            }
            $pattern = '/' . preg_quote($term, '/') . '/iu';
            $out = preg_replace($pattern, '<strong>$0</strong>', $out) ?? $out;
        }

        return $out;
    }
}
