<?php

namespace App\Http\Controllers;

use App\Enums\HuntDifficulty;
use App\Models\Hunts;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;

class HuntsController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        try {
            $searchTerm = $this->resolveSearchTerm($request);
            $filters = $this->buildMeilisearchFilters($request);

            $search = Hunts::search($searchTerm ?? '')
                ->query(fn ($query) => $query->with('participants:id,avatar_uri'));

            // ✅ IMPORTANT: n’envoie PAS filter s’il est vide
            if ($filters !== '') {
                $search->options(['filter' => $filters]);
            }

            Log::info('HUNTS_SEARCH', [
                'q' => $searchTerm ?? '',
                'filters' => $filters,
                'meili_host' => config('scout.meilisearch.host'),
                'index' => (new Hunts)->searchableAs(),
            ]);

            return response()->json($search->paginate(10));
        } catch (\Throwable $e) {
            Log::error('Error fetching hunts: '.$e->getMessage());

            return response()->json([
                'error' => 'Server Error',
                'message' => $e->getMessage(),
            ], 500);
        }
    }

    private function buildMeilisearchFilters(Request $request): string
    {
        $filters = [];

        // participating
        if ($request->has('participating')) {
            $participating = filter_var(
                $request->query('participating'),
                FILTER_VALIDATE_BOOLEAN,
                FILTER_NULL_ON_FAILURE
            );

            $userId = auth('sanctum')->id(); // chez toi => UUID string

            if ($userId) {
                $escapedUserId = $this->escapeMeiliString((string) $userId);

                if ($participating === true) {
                    // ✅ UUID => string
                    $filters[] = "participant_ids = \"{$escapedUserId}\"";
                } elseif ($participating === false) {
                    $filters[] = "participant_ids != \"{$escapedUserId}\"";
                }
            } elseif ($participating === true) {
                $filters[] = "id < 0";
            }
        }

        // active
        if ($request->has('active')) {
            $now = Carbon::now('UTC')->timestamp;
            $active = filter_var($request->query('active'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);

            if ($active === true) {
                // Hunt actif = démarré ET (pas terminé OU pas de date de fin)
                $filters[] = "start_at_timestamp <= {$now}";
                // Meilisearch : la syntaxe est 'field EXISTS' et non 'EXISTS field'
                // Un hunt est actif si end_at_timestamp n'existe pas OU >= now
                $filters[] = "(end_at_timestamp >= {$now} OR NOT end_at_timestamp EXISTS)";
            } elseif ($active === false) {
                // Hunt non actif = pas encore commencé OU (déjà terminé ET a une date de fin)
                // Si pas de end_at_timestamp, le hunt ne peut pas être terminé
                $filters[] = "(start_at_timestamp > {$now} OR (end_at_timestamp < {$now} AND end_at_timestamp EXISTS))";
            }
        }

        // city
        if ($request->filled('city')) {
            $city = $request->query('city');
            if (is_string($city)) {
                $city = $this->escapeMeiliString($city);
                $filters[] = "city = \"{$city}\"";
            }
        }

        // difficulty
        if ($request->filled('difficulty')) {
            $difficulties = $request->query('difficulty');

            if (is_string($difficulties)) {
                $difficulties = explode(',', $difficulties);
            }

            if (is_array($difficulties)) {
                $validDifficulties = array_values(array_intersect(
                    HuntDifficulty::values(),
                    array_map('strtolower', $difficulties)
                ));

                if (!empty($validDifficulties)) {
                    $difficultyFilters = array_map(
                        fn ($d) => 'difficulty = "'.$this->escapeMeiliString($d).'"',
                        $validDifficulties
                    );
                    $filters[] = '(' . implode(' OR ', $difficultyFilters) . ')';
                }
            }
        }

        // dates (UTC)
        $startFrom = $this->parseDateFilterUtc($request->query('start_from'));
        $startTo   = $this->parseDateFilterUtc($request->query('start_to'));
        $endFrom   = $this->parseDateFilterUtc($request->query('end_from'));
        $endTo     = $this->parseDateFilterUtc($request->query('end_to'));

        if ($startFrom) {
            $filters[] = "start_at_timestamp >= {$startFrom->timestamp}";
        }
        if ($startTo) {
            $filters[] = "start_at_timestamp <= {$startTo->timestamp}";
        }
        if ($endFrom) {
            $filters[] = "end_at_timestamp >= {$endFrom->timestamp}";
        }
        if ($endTo) {
            $filters[] = "end_at_timestamp <= {$endTo->timestamp}";
        }

        // Filtre par défaut : si aucun filtre n'est spécifié, afficher uniquement les hunts publics
        // Cela évite l'erreur Meilisearch avec une chaîne de filtres vide
        if (empty($filters)) {
            $filters[] = "is_public = true";
        }

        return implode(' AND ', $filters);
    }

    private function resolveSearchTerm(Request $request): ?string
    {
        $searchTerm = $request->query('search') ?? $request->query('q');

        if (!is_string($searchTerm)) {
            return null;
        }

        $searchTerm = trim($searchTerm);

        return $searchTerm !== '' ? $searchTerm : null;
    }

    private function parseDateFilterUtc(mixed $value): ?Carbon
    {
        if (!is_string($value) || trim($value) === '') {
            return null;
        }

        try {
            return Carbon::parse(trim($value))->utc();
        } catch (\Throwable $e) {
            return null;
        }
    }

    private function escapeMeiliString(string $value): string
    {
        // Échappe les backslashes et les guillemets pour une string Meilisearch
        $value = str_replace('\\', '\\\\', $value);
        return str_replace('"', '\"', $value);
    }
}
