<?php

declare(strict_types=1);

namespace App\Controllers;

use App\ApiClient\AdminClient;
use App\ApiClient\ApiException;
use App\Auth\SessionManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Views\Twig;

/**
 * `/app/search` — global IP lookup driven by the topnav search box.
 *
 * Aggregates results from three API surfaces:
 *   • `/api/v1/admin/ips` (uses native `q` prefix filter)
 *   • `/api/v1/admin/manual-blocks` (filtered client-side; api has no `q`)
 *   • `/api/v1/admin/allowlist`     (same)
 *
 * The IPs list page already supports `?q=`; the manual-blocks and
 * allowlist pages do not — the UI link drops the user on the section's
 * index where the matched entries are visible.
 */
final class SearchController
{
    private const MAX_QUERY_LENGTH = 64;

    public function __construct(
        private readonly Twig $twig,
        private readonly SessionManager $sessions,
        private readonly AdminClient $admin,
    ) {
    }

    public function index(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $user = $this->sessions->getUser();
        if ($user === null) {
            return $response->withStatus(302)->withHeader('Location', '/login');
        }

        $raw = $request->getQueryParams()['q'] ?? null;
        $query = is_string($raw) ? trim($raw) : '';
        if ($query === '') {
            return $this->twig->render($response, 'pages/search/index.twig', [
                'active_section' => null,
                'query' => '',
                'has_query' => false,
                'ips' => null,
                'manual_blocks' => [],
                'allowlist' => [],
                'errors' => [],
            ]);
        }
        if (strlen($query) > self::MAX_QUERY_LENGTH) {
            $query = substr($query, 0, self::MAX_QUERY_LENGTH);
        }

        $ips = null;
        $manualBlocks = [];
        $allowlist = [];
        $errors = [];

        try {
            $ips = $this->admin->searchIps($user->userId, ['q' => $query], 1, 25);
        } catch (ApiException $e) {
            $errors['ips'] = $e->getMessage();
        }

        try {
            $manualPayload = $this->admin->listManualBlocks($user->userId, null);
            $manualBlocks = $this->filterEntries($manualPayload, $query);
        } catch (ApiException $e) {
            $errors['manual_blocks'] = $e->getMessage();
        }

        try {
            $allowPayload = $this->admin->listAllowlist($user->userId, null);
            $allowlist = $this->filterEntries($allowPayload, $query);
        } catch (ApiException $e) {
            $errors['allowlist'] = $e->getMessage();
        }

        return $this->twig->render($response, 'pages/search/index.twig', [
            'active_section' => null,
            'query' => $query,
            'has_query' => true,
            'ips' => $ips,
            'manual_blocks' => $manualBlocks,
            'allowlist' => $allowlist,
            'errors' => $errors,
        ]);
    }

    /**
     * @param array<string, mixed> $payload
     * @return list<array<string, mixed>>
     */
    private function filterEntries(array $payload, string $query): array
    {
        $items = $payload['items'] ?? [];
        if (!is_array($items)) {
            return [];
        }
        $needle = strtolower($query);
        $out = [];
        foreach ($items as $item) {
            if (!is_array($item)) {
                continue;
            }
            $haystack = strtolower((string) ($item['ip'] ?? '')) . ' ' . strtolower((string) ($item['cidr'] ?? ''));
            if ($haystack !== ' ' && str_contains($haystack, $needle)) {
                $out[] = $item;
            }
        }

        return $out;
    }
}
