<?php

use MintyPHP\DB;
use MintyPHP\I18n;
use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionService;
use MintyPHP\Service\User\UserServicesFactory;
use MintyPHP\Support\Guard;
use MintyPHP\Support\SearchConfig;

Guard::requireLogin();

$userId = (int) ($_SESSION['user']['id'] ?? 0);
if ($userId > 0) {
    permissionGateway()->getUserPermissions($userId);
}

$query = trim((string) ($_GET['search'] ?? ''));
if ($query === '') {
    Router::json(['data' => [], 'total' => 0]);
}

$limit = (int) ($_GET['limit'] ?? 10);
if ($limit < 1) {
    $limit = 10;
} elseif ($limit > 100) {
    $limit = 100;
}
$offset = (int) ($_GET['offset'] ?? 0);
if ($offset < 0) {
    $offset = 0;
}

$locale = I18n::$locale ?? (I18n::$defaultLocale ?? 'de');
$userTenantRepository = (new UserServicesFactory())->createUserTenantRepository();
$tenantIds = $userId > 0 ? $userTenantRepository->listTenantIdsByUserId($userId) : [];
$tenantScoped = !empty($tenantIds);

$tenantScopeFilters = SearchConfig::tenantScopeFilters();
$resources = SearchConfig::resources($query, $locale);
$items = [];

foreach ($resources as $resource) {
    $key = (string) ($resource['key'] ?? '');
    if ($key === '') {
        continue;
    }

    $perm = (string) ($resource['permission'] ?? '');
    if ($perm !== '' && !permissionGateway()->userHas($userId, $perm)) {
        continue;
    }

    $tenantFilter = $tenantScopeFilters[$key] ?? '';
    $isTenantScoped = $tenantFilter !== '';
    if ($isTenantScoped && !$tenantScoped) {
        continue;
    }

    $sql = $resource['resultSql'] ?? '';
    if ($sql === '') {
        continue;
    }
    $sql = str_replace('{{tenantFilter}}', $isTenantScoped ? $tenantFilter : '', $sql);
    $params = $resource['resultParams'] ?? [];
    if ($isTenantScoped && strpos($sql, '???') !== false) {
        $params[] = $tenantIds;
    }

    $rows = DB::select($sql, ...$params);
    foreach ($rows as $row) {
        $data = $row;
        if (is_array($row) && count($row) === 1) {
            $data = reset($row);
        }
        $data = is_array($data) ? $data : [];
        $mapped = SearchConfig::mapResultItem($key, (string) ($resource['label'] ?? ''), $data);
        if ($mapped !== null) {
            $items[] = $mapped;
        }
    }
}

$items = array_merge($items, SearchConfig::hotkeyResultItems($query));
if (permissionGateway()->userHas($userId, PermissionService::DOCS_VIEW)) {
    $items = array_merge($items, SearchConfig::docsResultItems($query));
}

$scoreQuery = SearchConfig::normalizeScoreQuery($query);
$queryLower = mb_strtolower($scoreQuery);
$scoreItem = static function (array $item) use ($queryLower): int {
    $manualScore = (int) ($item['search_score'] ?? 0);
    if ($manualScore > 0) {
        return $manualScore;
    }

    $title = mb_strtolower((string) ($item['title'] ?? ''));
    $description = mb_strtolower((string) ($item['description'] ?? ''));
    if ($title === $queryLower) {
        return 400;
    }
    if ($title !== '' && strpos($title, $queryLower) === 0) {
        return 300;
    }
    if ($title !== '' && strpos($title, $queryLower) !== false) {
        return 200;
    }
    if ($description !== '' && strpos($description, $queryLower) !== false) {
        return 100;
    }
    return 0;
};

usort($items, static function (array $a, array $b) use ($scoreItem): int {
    $scoreA = $scoreItem($a);
    $scoreB = $scoreItem($b);
    if ($scoreA !== $scoreB) {
        return $scoreB <=> $scoreA;
    }
    $title = strcmp((string) ($a['title'] ?? ''), (string) ($b['title'] ?? ''));
    if ($title !== 0) {
        return $title;
    }
    return strcmp((string) ($a['type'] ?? ''), (string) ($b['type'] ?? ''));
});

$total = count($items);
$items = array_slice($items, $offset, $limit);

Router::json([
    'data' => $items,
    'total' => $total,
]);
