<?php

namespace MintyPHP\Support\Search;

use MintyPHP\Service\Docs\DocsCatalogService;
use MintyPHP\Service\Ui\HotkeyService;

class SearchSpecialResourceProvider
{
    private static function hotkeyEntries(): array
    {
        $rows = [];
        foreach (HotkeyService::list() as $row) {
            $actionKey = trim($row['action_key']);
            $mac = trim($row['mac']);
            $win = trim($row['win']);
            if ($actionKey === '' || $mac === '' || $win === '') {
                continue;
            }

            $rows[] = [
                'label' => t($actionKey),
                'mac' => $mac,
                'win' => $win,
            ];
        }

        return $rows;
    }

    // Two-tier match: first checks against the hotkey service's keyword list (e.g. "shortcut", "keyboard"),
    // then falls back to substring matching against individual entry labels/key combos.
    private static function matchesHotkeyQueryWith(string $query, array $entries): bool
    {
        $query = trim(mb_strtolower($query));
        if ($query === '') {
            return false;
        }

        $tokens = preg_split('/[^a-z0-9]+/i', $query);
        $tokens = is_array($tokens) ? array_values(array_filter($tokens, static fn ($part): bool => $part !== '')) : [];

        foreach (HotkeyService::searchKeywords() as $keywordRaw) {
            $keyword = trim(mb_strtolower((string) $keywordRaw));
            if ($keyword === '') {
                continue;
            }
            if (in_array($keyword, $tokens, true)) {
                return true;
            }
            foreach ($tokens as $token) {
                if (strlen($token) >= 3 && str_starts_with($keyword, $token)) {
                    return true;
                }
            }
            if (strlen($query) >= 3 && str_starts_with($keyword, $query)) {
                return true;
            }
        }

        foreach ($entries as $entry) {
            $label = mb_strtolower((string) ($entry['label'] ?? ''));
            $mac = mb_strtolower((string) ($entry['mac'] ?? ''));
            $win = mb_strtolower((string) ($entry['win'] ?? ''));
            if (($label !== '' && str_contains($label, $query))
                || ($mac !== '' && str_contains($mac, $query))
                || ($win !== '' && str_contains($win, $query))) {
                return true;
            }
        }

        return false;
    }

    private static function filterHotkeyEntries(string $query): array
    {
        $needle = trim(mb_strtolower($query));
        $entries = self::hotkeyEntries();

        if (!self::matchesHotkeyQueryWith($query, $entries)) {
            return [];
        }

        if ($needle === '') {
            return $entries;
        }

        $filtered = [];
        foreach ($entries as $entry) {
            $label = mb_strtolower((string) ($entry['label'] ?? ''));
            $mac = mb_strtolower((string) ($entry['mac'] ?? ''));
            $win = mb_strtolower((string) ($entry['win'] ?? ''));
            if (str_contains($label, $needle) || str_contains($mac, $needle) || str_contains($win, $needle)) {
                $filtered[] = $entry;
            }
        }

        return $filtered;
    }

    public static function hotkeyPreviewResource(string $query): ?array
    {
        $entries = self::filterHotkeyEntries($query);
        if ($entries === []) {
            return null;
        }

        $items = [];
        foreach ($entries as $entry) {
            $items[] = [
                'label' => trim((string) ($entry['label'] ?? '') . ' - ' . (string) ($entry['mac'] ?? '') . ' / ' . (string) ($entry['win'] ?? '')),
                'url' => lurl('help/hotkeys'),
            ];
        }

        return [
            'key' => 'hotkeys',
            'label' => t('Keyboard shortcuts'),
            'count' => count($items),
            'url' => lurl('help/hotkeys'),
            'items' => array_slice($items, 0, 5),
        ];
    }

    public static function hotkeyResultItems(string $query): array
    {
        $entries = self::filterHotkeyEntries($query);
        if ($entries === []) {
            return [];
        }

        $result = [];
        foreach ($entries as $entry) {
            $result[] = [
                'type' => t('Keyboard shortcuts'),
                'title' => (string) ($entry['label'] ?? ''),
                'description' => trim((string) ($entry['mac'] ?? '') . ' / ' . (string) ($entry['win'] ?? '')),
                'url' => lurl('help/hotkeys'),
                'image' => '',
                'icon' => 'bi-keyboard',
            ];
        }

        return $result;
    }

    private static function docsResultUrl(string $slug, string $anchor = ''): string
    {
        $url = lurl('admin/docs/' . $slug);
        if ($anchor !== '') {
            $url .= '#' . $anchor;
        }

        return $url;
    }

    public static function docsPreviewResource(string $query): ?array
    {
        $matches = DocsCatalogService::search($query);
        if ($matches === []) {
            return null;
        }

        $seenDocs = [];
        $previewItems = [];
        foreach ($matches as $match) {
            $slug = trim((string) $match['slug']);
            if ($slug === '') {
                continue;
            }

            $seenDocs[$slug] = true;
            if (isset($previewItems[$slug])) {
                continue;
            }

            $title = trim((string) $match['title']);
            if ($title === '') {
                $title = $slug;
            }
            $section = trim((string) $match['section']);
            $label = $title;
            if ($section !== '' && mb_strtolower($section) !== mb_strtolower($title)) {
                $label .= ' - ' . $section;
            }

            $previewItems[$slug] = [
                'label' => $label,
                'url' => self::docsResultUrl($slug, (string) $match['anchor']),
            ];
        }

        return [
            'key' => 'docs',
            'label' => t('Documentation'),
            'count' => count($seenDocs),
            'url' => lurl('admin/docs/' . DocsCatalogService::defaultSlug()) . '?search=' . urlencode($query),
            'items' => array_values(array_slice($previewItems, 0, 5)),
        ];
    }

    public static function docsResultItems(string $query): array
    {
        $matches = DocsCatalogService::search($query);
        if ($matches === []) {
            return [];
        }

        $items = [];
        foreach ($matches as $match) {
            $slug = trim((string) $match['slug']);
            $title = trim((string) $match['title']);
            if ($slug === '' || $title === '') {
                continue;
            }

            $section = trim((string) $match['section']);
            $snippet = trim((string) $match['snippet']);
            $descriptionParts = [];
            if ($section !== '' && mb_strtolower($section) !== mb_strtolower($title)) {
                $descriptionParts[] = $section;
            }
            if ($snippet !== '') {
                $descriptionParts[] = $snippet;
            }

            // Map raw doc scores (0–1000+) to coarser search_score buckets for result ranking.
            $rawScore = (int) $match['score'];
            $searchScore = match (true) {
                $rawScore >= 1000 => 400,
                $rawScore >= 900 => 360,
                $rawScore >= 800 => 330,
                $rawScore >= 700 => 300,
                $rawScore >= 650 => 260,
                $rawScore >= 600 => 230,
                $rawScore >= 500 => 200,
                default => 150,
            };

            $items[] = [
                'type' => t('Documentation'),
                'title' => $title,
                'description' => implode(' - ', $descriptionParts),
                'url' => self::docsResultUrl($slug, (string) $match['anchor']),
                'image' => '',
                'icon' => 'bi-journal-text',
                'search_score' => $searchScore,
            ];
        }

        return $items;
    }
}
