<?php

namespace App\Http\Livewire;

use App\Models\Call;
use App\Models\Category;
use App\Overrides\Matchish\ScoutElasticSearch\ElasticSearch\EloquentHitsIteratorAggregate;
use App\Traits\ProfilePermissionTrait;
use Elastic\Elasticsearch\Client;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Livewire\Component;
use Matchish\ScoutElasticSearch\MixedSearch;
use ONGR\ElasticsearchDSL\Aggregation\Bucketing\TermsAggregation;
use ONGR\ElasticsearchDSL\Highlight\Highlight;
use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
use ONGR\ElasticsearchDSL\Query\FullText\MatchQuery;
use ONGR\ElasticsearchDSL\Query\TermLevel\ExistsQuery;
use ONGR\ElasticsearchDSL\Query\TermLevel\TermsQuery;
use ONGR\ElasticsearchDSL\Search;

class MainBrowseTagCategories extends Component
{
    use ProfilePermissionTrait;

    public $tagCategories = [];
    public $selectedCategories = [];
    public $fetchedResults = [];
    public $results = [];
    public int $total = 0;

    // Location-based search properties
    public $profileLocation = null;
    public $locationHierarchy = [];

    // Caching keys
    private const CACHE_CATEGORIES_KEY = 'tag_categories_hierarchy';
    private const CACHE_TTL = 3600; // 1 hour

    public function mount()
    {
        $this->loadTagCategories();
        $this->loadProfileLocation();
    }

    public function render()
    {
        return view('livewire.main-browse-tag-categories');
    }

    private function loadTagCategories()
    {
        // Use caching for category hierarchy to improve performance
        $this->tagCategories = Cache::remember(
            self::CACHE_CATEGORIES_KEY . '_' . app()->getLocale(),
            self::CACHE_TTL,
            function () {
                $categories = Category::where('type', 'App\Models\Tag')
                    ->with(['translations' => function ($query) {
                        $query->where('locale', app()->getLocale());
                    }])
                    ->get();

                return $this->buildHierarchy($categories);
            }
        );
    }

    private function loadProfileLocation()
    {
        try {
            if (function_exists('getActiveProfile')) {
                $activeProfile = getActiveProfile();
                if ($activeProfile && $activeProfile->locations) {
                    $this->profileLocation = $activeProfile->locations->first();

                    if ($this->profileLocation) {
                        $this->locationHierarchy = $this->profileLocation->getCompleteHierarchy();
                    }
                }
            }
        } catch (\Exception $e) {
            \Log::warning('Failed to load profile location: ' . $e->getMessage());
            $this->profileLocation = null;
            $this->locationHierarchy = [];
        }
    }

    private function buildHierarchy($categories, $parentId = null)
    {
        $hierarchy = [];

        foreach ($categories as $category) {
            if ($category->parent_id == $parentId) {
                $categoryData = [
                    'id' => $category->id,
                    'name' => $category->translation->name ?? $category->name,
                    'color' => $category->relatedColor,
                    'parent_id' => $category->parent_id,
                    'children' => $this->buildHierarchy($categories, $category->id)
                ];
                $hierarchy[] = $categoryData;
            }
        }

        return $hierarchy;
    }

    public function selectCategory($categoryId)
    {
        if (!$this->validateCategoryId($categoryId)) {
            return;
        }

        $categoryId = (int)$categoryId;

        // Toggle category selection
        if (in_array($categoryId, $this->selectedCategories)) {
            $this->selectedCategories = array_values(array_filter(
                $this->selectedCategories,
                fn($id) => $id != $categoryId
            ));
        } else {
            $this->selectedCategories[] = $categoryId;
        }

        $this->selectedCategories = array_map('intval', $this->selectedCategories);
        $this->performSearch();
    }

    public function removeCategory($categoryId)
    {
        if (!$this->validateCategoryId($categoryId)) {
            return;
        }

        $categoryId = (int)$categoryId;
        $this->selectedCategories = array_values(array_filter(
            $this->selectedCategories,
            fn($id) => $id != $categoryId
        ));

        $this->selectedCategories = array_map('intval', $this->selectedCategories);
        $this->performSearch();
    }

    private function validateCategoryId($categoryId): bool
    {
        return is_numeric($categoryId) && $categoryId > 0;
    }

    private function performSearch()
    {
        if (!empty($this->selectedCategories)) {
            $this->searchByCategories($this->selectedCategories);
        } else {
            $this->resetResults();
        }
    }

    private function resetResults()
    {
        $this->fetchedResults = collect([]);
        $this->total = 0;
    }

    private function searchByCategories($categoryIds)
    {
        $validCategoryIds = array_filter($categoryIds, [$this, 'validateCategoryId']);

        if (empty($validCategoryIds)) {
            $this->resetResults();
            return;
        }

        // Get all child category IDs including the selected ones
        $allCategoryIds = $this->expandCategoryIds($validCategoryIds);

        if (empty($allCategoryIds)) {
            $this->resetResults();
            return;
        }

        // Get category names with caching
        $categoryNames = $this->getCategoryNames($allCategoryIds);

        if (empty($categoryNames)) {
            $this->resetResults();
            return;
        }

        $this->executeElasticsearchQuery($categoryNames);
    }

    private function expandCategoryIds(array $categoryIds): array
    {
        $allCategoryIds = [];

        foreach ($categoryIds as $categoryId) {
            $childIds = $this->getAllCategoryIds($categoryId);
            $allCategoryIds = array_merge($allCategoryIds, $childIds);
        }

        return array_values(array_unique(array_filter($allCategoryIds, [$this, 'validateCategoryId'])));
    }

    private function getCategoryNames(array $categoryIds): array
    {
        $cacheKey = 'category_names_' . md5(serialize($categoryIds)) . '_' . app()->getLocale();

        return Cache::remember($cacheKey, 300, function () use ($categoryIds) {
            $categories = Category::whereIn('id', $categoryIds)
                ->with(['translations' => function ($query) {
                    $query->where('locale', app()->getLocale());
                }])
                ->get();

            return $categories->map(function ($category) {
                return $category->translation ? $category->translation->name : null;
            })->filter()->values()->toArray();
        });
    }

    private function executeElasticsearchQuery(array $categoryNames)
    {
        $startTime = microtime(true);

        try {
            $rawOutput = MixedSearch::search('', function (Client $client, Search $body) use ($categoryNames) {
                $this->buildElasticsearchQuery($body, $categoryNames);
                $this->addHighlighting($body);
                $this->addAggregations($body);

                // Use your configured max_results
                $body->setSize(timebank_config('main_search_bar.search.max_results', 50) * 1.5);

                \Log::info('Elasticsearch query', ['query' => $body->toArray()]);

                return $client->search([
                    'index' => timebank_config('main_search_bar.model_indices'),
                    'body' => $body->toArray()
                ])->asArray();
            })->raw();

            $executionTime = microtime(true) - $startTime;
            $this->processSearchResults($rawOutput);

            // Track analytics if helper exists
            if (class_exists('App\Helpers\SearchOptimizationHelper')) {
                \App\Helpers\SearchOptimizationHelper::trackLocationSearchAnalytics(
                    $this->selectedCategories,
                    $this->total,
                    $executionTime,
                    $this->locationHierarchy
                );
            }
        } catch (\Exception $e) {
            $this->handleSearchError($e, $categoryNames);
        }
    }

    private function buildElasticsearchQuery(Search $body, array $categoryNames)
    {
        $body->setSource(['id', '__class_name', '_score']);

        $locale = app()->getLocale();
        $mainBoolQuery = new BoolQuery();

        // Primary category matching with boost from your config
        $categoryBoolQuery = new BoolQuery();
        $categoryField = 'tags.contexts.categories.name_' . $locale;
        $categoryBoost = timebank_config('main_search_bar.boosted_fields.categories', 1.5);

        \Log::info('Building category query', [
            'category_field' => $categoryField,
            'category_names' => $categoryNames,
            'locale' => $locale
        ]);

        foreach ($categoryNames as $categoryName) {
            // Exact match with your configured boost
            $exactMatch = new MatchQuery($categoryField, $categoryName);
            $exactMatch->addParameter('boost', $categoryBoost * 2);
            $categoryBoolQuery->add($exactMatch, BoolQuery::SHOULD);

            // Fuzzy match using your configured fuzziness
            $fuzzyMatch = new MatchQuery($categoryField, $categoryName);
            $fuzzyMatch->addParameter('fuzziness', timebank_config('main_search_bar.search.fuzziness', '1'));
            $fuzzyMatch->addParameter('prefix_length', timebank_config('main_search_bar.search.prefix_length', 2));
            $fuzzyMatch->addParameter('boost', $categoryBoost);
            $categoryBoolQuery->add($fuzzyMatch, BoolQuery::SHOULD);
        }

        // Also match calls by tag name (calls index uses tag.name_{locale}, not the categories field)
        $tagField = 'tag.name_' . $locale;
        foreach ($categoryNames as $categoryName) {
            $exactTagMatch = new MatchQuery($tagField, $categoryName);
            $exactTagMatch->addParameter('boost', $categoryBoost * 2);
            $categoryBoolQuery->add($exactTagMatch, BoolQuery::SHOULD);

            $fuzzyTagMatch = new MatchQuery($tagField, $categoryName);
            $fuzzyTagMatch->addParameter('fuzziness', timebank_config('main_search_bar.search.fuzziness', '1'));
            $fuzzyTagMatch->addParameter('prefix_length', timebank_config('main_search_bar.search.prefix_length', 2));
            $fuzzyTagMatch->addParameter('boost', $categoryBoost);
            $categoryBoolQuery->add($fuzzyTagMatch, BoolQuery::SHOULD);
        }

        $categoryBoolQuery->addParameter('minimum_should_match', 1);
        $mainBoolQuery->add($categoryBoolQuery, BoolQuery::MUST);

        // Add location-based boosting (but make it optional)
        $this->addLocationBoosts($mainBoolQuery);

        // Add model-specific boosts using your configuration
        $this->addModelBoosts($mainBoolQuery, $locale);

        $body->addQuery($mainBoolQuery);
    }

    private function addLocationBoosts(BoolQuery $mainBoolQuery)
    {
        // Re-enable location boosting since basic search is working
        if (empty($this->locationHierarchy)) {
            \Log::info('No location hierarchy available');
            return;
        }

        $locationBoolQuery = new BoolQuery();
        $addedQueries = 0;

        // District level boost (highest priority - same district)
        if (isset($this->locationHierarchy['district']) && $this->locationHierarchy['district']) {
            $districtName = $this->getLocationName($this->locationHierarchy['district']);
            if ($districtName) {
                $districtQuery = new MatchQuery('locations.district', $districtName);
                $districtQuery->addParameter('boost', 5.0);
                $locationBoolQuery->add($districtQuery, BoolQuery::SHOULD);
                $addedQueries++;
                \Log::info('Added district query', ['district_name' => $districtName]);
            }
        }

        // City level boost (high priority - same city)
        if (isset($this->locationHierarchy['city']) && $this->locationHierarchy['city']) {
            $cityName = $this->getLocationName($this->locationHierarchy['city']);
            if ($cityName) {
                $cityQuery = new MatchQuery('locations.city', $cityName);
                $cityQuery->addParameter('boost', 3.0);
                $locationBoolQuery->add($cityQuery, BoolQuery::SHOULD);
                $addedQueries++;
                \Log::info('Added city query', ['city_name' => $cityName]);
            }
        }

        // Division level boost (medium priority - same division/state/province)
        if (isset($this->locationHierarchy['division']) && $this->locationHierarchy['division']) {
            $divisionName = $this->getLocationName($this->locationHierarchy['division']);
            if ($divisionName) {
                $divisionQuery = new MatchQuery('locations.division', $divisionName);
                $divisionQuery->addParameter('boost', 2.0);
                $locationBoolQuery->add($divisionQuery, BoolQuery::SHOULD);
                $addedQueries++;
                \Log::info('Added division query', ['division_name' => $divisionName]);
            }
        }

        // Country level boost (base priority - same country)
        if (isset($this->locationHierarchy['country']) && $this->locationHierarchy['country']) {
            $countryName = $this->getLocationName($this->locationHierarchy['country']);
            if ($countryName) {
                $countryQuery = new MatchQuery('locations.country', $countryName);
                $countryQuery->addParameter('boost', 1.5);
                $locationBoolQuery->add($countryQuery, BoolQuery::SHOULD);
                $addedQueries++;
                \Log::info('Added country query', ['country_name' => $countryName]);
            }
        }

        // Only add location queries if we have some
        if ($addedQueries > 0) {
            $mainBoolQuery->add($locationBoolQuery, BoolQuery::SHOULD);
            \Log::info('Location-based boosting applied', [
                'queries_added' => $addedQueries,
                'country_id' => $this->locationHierarchy['country']->id ?? null,
                'division_id' => $this->locationHierarchy['division']->id ?? null,
                'city_id' => $this->locationHierarchy['city']->id ?? null,
                'district_id' => $this->locationHierarchy['district']->id ?? null,
            ]);
        } else {
            \Log::info('No location queries added - no valid location names found');
        }
    }

    private function getLocationName($location)
    {
        if (!$location) {
            return null;
        }

        // Try to get translated name for current locale
        $locale = app()->getLocale();
        if ($location->translations && $location->translations->count() > 0) {
            $translation = $location->translations->where('locale', $locale)->first();
            if ($translation && $translation->name) {
                return $translation->name;
            }
        }

        // Fallback to default name or base language
        return $location->name ?? null;
    }

    private function addModelBoosts(BoolQuery $mainBoolQuery, string $locale)
    {
        // Temporarily disable model boosts to avoid ExistsQuery issues
        // Model boosting will be handled in PHP during result processing
        \Log::info('Model boosting disabled - will be applied during result processing');
        return;
    }

    private function addHighlighting(Search $body)
    {
        $highlight = new Highlight();
        $locale = app()->getLocale();

        $fields = [
            'tags.contexts.categories.name_' . $locale,
            'tags.contexts.tags.name_' . $locale,
            'name',
            'about_short_' . $locale,
            'about_' . $locale,
            'motivation_' . $locale,
            'post_translations.title_' . $locale,
            'post_translations.excerpt_' . $locale,
            'post_category.name_' . $locale,
        ];

        // Use your existing highlight configuration
        $highlightConfig = [
            'fragment_size' => timebank_config('main_search_bar.search.fragment_size', 50),
            'fragmenter' => timebank_config('main_search_bar.search.fragmenter', 'simple'),
            'number_of_fragments' => timebank_config('main_search_bar.search.number_of_fragments', 1),
            'pre_tags' => [timebank_config('main_search_bar.search.pre-tags', '<span class="font-semibold text-white leading-tight">')],
            'post_tags' => [timebank_config('main_search_bar.search.post-tags', '</span>')],
            'order' => timebank_config('main_search_bar.search.order', 'score'),
        ];

        foreach ($fields as $field) {
            $highlight->addField($field, $highlightConfig);
        }

        $body->addHighlight($highlight);
    }

    private function addAggregations(Search $body)
    {
        // Add aggregation to get model type distribution
        $modelTypeAgg = new TermsAggregation('model_types', '__class_name');
        $modelTypeAgg->addParameter('size', 10);
        $body->addAggregation($modelTypeAgg);
    }

    private function processSearchResults($rawOutput)
    {
        $rawData = $rawOutput['hits']['hits'] ?? [];
        $this->total = $rawOutput['hits']['total']['value'] ?? 0;

        \Log::info('Elasticsearch response', [
            'total_hits' => $this->total,
            'returned_hits' => count($rawData),
            'raw_query_time' => $rawOutput['took'] ?? 'unknown'
        ]);

        if ($this->total === 0) {
            \Log::warning('No search results found', [
                'selected_categories' => $this->selectedCategories,
                'location_hierarchy_present' => !empty($this->locationHierarchy)
            ]);
            $this->fetchedResults = collect([]);
            return;
        }

        // Process results efficiently
        $results = $this->processHitsWithOptimization($rawOutput);

        \Log::info('After hit processing', [
            'processed_results_count' => count($results)
        ]);

        // Apply final filtering and sorting
        $filteredResults = $this->applyBusinessLogicFiltering($results);

        \Log::info('After business logic filtering', [
            'filtered_results_count' => count($filteredResults)
        ]);

        $this->fetchedResults = $this->sortAndLimitResults($filteredResults);

        \Log::info('Final results', [
            'final_results_count' => $this->fetchedResults->count()
        ]);
    }

    private function processHitsWithOptimization($rawOutput): array
    {
        $includedCategoryIds = timebank_config('main_search_bar.category_ids_posts');
        $canManageProfiles = $this->getCanManageProfiles();

        $callback = function ($model) use ($includedCategoryIds, $canManageProfiles) {
            $modelClass = get_class($model);

            // Handle Posts
            if ($modelClass === 'App\Models\Post') {
                $categoryId = optional($model->category)->id;
                return in_array($categoryId, $includedCategoryIds) ? $model : null;
            }

            // Handle Calls
            if ($modelClass === 'App\Models\Call') {
                if ($model->trashed() || $model->is_suppressed || $model->is_paused) return null;
                if ($model->till !== null && $model->till->isPast()) return null;
                if (!$model->is_public && !\Illuminate\Support\Facades\Auth::check()) return null;
                return $model;
            }

            // Handle Profiles (User, Organization, Bank)
            if (in_array($modelClass, ['App\Models\User', 'App\Models\Organization', 'App\Models\Bank'])) {
                return $this->filterProfile($model, $canManageProfiles);
            }

            return null;
        };

        $results = [];
        $hitsIterator = new EloquentHitsIteratorAggregate($rawOutput, $callback);

        foreach ($hitsIterator as $model) {
            if ($model) {
                $results[] = $this->transformModelToResult($model, $rawOutput);
            }
        }

        return $results;
    }

    private function filterProfile($model, bool $canManageProfiles)
    {
        if ($canManageProfiles) {
            return $model;
        }

        // Check inactive profiles
        if (
            timebank_config('profile_inactive.profile_search_hidden')
            && !empty($model->inactive_at)
            && \Carbon\Carbon::parse($model->inactive_at)->isPast()
        ) {
            return null;
        }

        // Check unverified emails
        if (
            timebank_config('profile_email_unverified.profile_search_hidden')
            && empty($model->email_verified_at)
        ) {
            return null;
        }

        // Check deleted profiles
        if (
            !empty($model->deleted_at)
            && \Carbon\Carbon::parse($model->deleted_at)->isPast()
        ) {
            return null;
        }

        // Check incomplete profiles
        if (
            timebank_config('profile_incomplete.profile_search_hidden')
            && method_exists($model, 'hasIncompleteProfile')
            && $model->hasIncompleteProfile($model)
        ) {
            return null;
        }

        return $model;
    }

    private function transformModelToResult($model, $rawOutput): array
    {
        $modelClass = get_class($model);
        $modelId = $model->id;

        // Find corresponding raw data for highlights
        $rawItem = collect($rawOutput['hits']['hits'])->first(function ($hit) use ($modelId) {
            return ($hit['_source']['id'] ?? null) == $modelId;
        });

        $result = [
            'id' => $modelId,
            'model' => $modelClass,
            'score' => $rawItem['_score'] ?? 1,
            'highlight' => $rawItem['highlight'] ?? [],
        ];

        // Add model-specific data
        if ($modelClass === 'App\Models\Post') {
            $result = array_merge($result, $this->getPostData($model));
        } elseif ($modelClass === 'App\Models\Call') {
            $result = array_merge($result, $this->getCallData($model));
        } else {
            $result = array_merge($result, $this->getProfileData($model));
        }

        // Add location proximity information for debugging/display
        $result['location_proximity'] = $this->calculateLocationProximity($model);

        return $result;
    }

    private function calculateLocationProximity($model): array
    {
        if (empty($this->locationHierarchy)) {
            return ['level' => 'unknown', 'distance' => null];
        }

        // For posts, check the post author's location
        if (get_class($model) === 'App\Models\Post') {
            $modelLocation = optional($model->user)->locations->first();
        } elseif (get_class($model) === 'App\Models\Call') {
            // Calls have a single location (belongsTo), not a collection
            $modelLocation = $model->location;
        } else {
            // For profiles (User, Organization, Bank)
            $modelLocation = $model->locations->first();
        }

        if (!$modelLocation) {
            return ['level' => 'no_location', 'distance' => null];
        }

        // Get model's location hierarchy
        try {
            $modelHierarchy = $modelLocation->getCompleteHierarchy();
        } catch (\Exception $e) {
            return ['level' => 'error', 'distance' => null];
        }

        // Calculate proximity level (district > city > division > country > different_country)
        if (
            isset($this->locationHierarchy['district'], $modelHierarchy['district'])
            && $this->locationHierarchy['district']
            && $modelHierarchy['district']
            && $this->locationHierarchy['district']->id === $modelHierarchy['district']->id
        ) {
            return ['level' => 'same_district', 'distance' => 1];
        }

        if (
            isset($this->locationHierarchy['city'], $modelHierarchy['city'])
            && $this->locationHierarchy['city']
            && $modelHierarchy['city']
            && $this->locationHierarchy['city']->id === $modelHierarchy['city']->id
        ) {
            return ['level' => 'same_city', 'distance' => 2];
        }

        if (
            isset($this->locationHierarchy['division'], $modelHierarchy['division'])
            && $this->locationHierarchy['division']
            && $modelHierarchy['division']
            && $this->locationHierarchy['division']->id === $modelHierarchy['division']->id
        ) {
            return ['level' => 'same_division', 'distance' => 3];
        }

        if (
            isset($this->locationHierarchy['country'], $modelHierarchy['country'])
            && $this->locationHierarchy['country']
            && $modelHierarchy['country']
            && $this->locationHierarchy['country']->id === $modelHierarchy['country']->id
        ) {
            return ['level' => 'same_country', 'distance' => 4];
        }

        return ['level' => 'different_country', 'distance' => 5];
    }

    private function getCallData(Call $call): array
    {
        $call->loadMissing([
            'callable',
            'translations',
            'tag.contexts.category.translations',
            'tag.contexts.category.ancestors.translations',
            'location.city.translations',
            'location.country.translations',
            'loveReactant.reactionCounters',
        ]);

        $tag         = $call->tag;
        $tagName     = $tag?->translation?->name ?? $tag?->name;
        $tagCategory = $tag?->contexts->first()?->category;
        $tagColor    = $tagCategory?->relatedColor ?? 'gray';
        $city        = optional($call->location?->city?->translations->first())->name;
        $country     = optional($call->location?->country?->translations->first())->name;

        $tagCategories = [];
        if ($tagCategory) {
            $locale    = app()->getLocale();
            $ancestors = $tagCategory->ancestorsAndSelf()->get()->reverse();
            foreach ($ancestors as $cat) {
                $catName = $cat->translations->firstWhere('locale', $locale)?->name
                    ?? $cat->translations->first()?->name
                    ?? '';
                if ($catName) {
                    $tagCategories[] = [
                        'name'  => $catName,
                        'color' => $cat->relatedColor ?? 'gray',
                    ];
                }
            }
        }

        return [
            'title'          => $tagName ?? '',
            'tag_name'       => $tagName,
            'tag_color'      => $tagColor,
            'tag_categories' => $tagCategories,
            'callable_name'  => $call->callable?->name ?? '',
            'photo'          => $call->callable?->profile_photo_url ?? '',
            'location'       => collect([$city, $country])->filter()->implode(', '),
            'location_short' => $city ?? '',
            'till'           => $call->till,
            'expiry_badge_text' => \App\Http\Livewire\Calls\ProfileCalls::buildExpiryBadgeText($call->till),
            'like_count'     => $call->loveReactant?->reactionCounters
                ->firstWhere('reaction_type_id', 3)?->count ?? 0,
            'excerpt'        => $call->translations->first()?->content ?? '',
            'status'         => '',
        ];
    }

    private function getPostData($post): array
    {
        $categoryId = optional($post->category)->id;
        $categoryName = optional($post->category->translations
            ->where('locale', app()->getLocale())->first())->name;

        return [
            'category_id' => $categoryId,
            'category' => $categoryName,
            'title' => $post->title,
            'subtitle' => $post->excerpt,
            'photo' => $post->getFirstMediaUrl('posts', 'hero'),
            'location_short' => '',
            'location' => '',
            'status' => '',
        ];
    }

    private function getProfileData($profile): array
    {
        // Eager load relationships for better performance
        $profile->load([
            'locations.district.translations',
            'locations.city.translations',
            'locations.division.translations',
            'locations.country.translations',
        ]);

        return [
            'name' => $profile->name,
            'photo' => $profile->profile_photo_url ?? '',
            'location' => $this->formatProfileLocation($profile),
            'type' => strtolower(class_basename($profile)),
        ];
    }

    private function formatProfileLocation($profile): string
    {
        $location = $profile->locations->first();
        if (!$location) {
            return '';
        }

        $parts = [];
        if ($location->city && $city = optional($location->city->translations->where('locale', app()->getLocale())->first())->name) {
            $parts[] = $city;
        }
        if ($location->division && $division = optional($location->division->translations->where('locale', app()->getLocale())->first())->name) {
            $parts[] = $division;
        }

        return implode(', ', $parts);
    }

    private function applyBusinessLogicFiltering(array $results): array
    {
        // Apply any additional business logic filtering here
        return array_filter($results, function ($result) {
            // Example: Filter out results with very low scores
            return ($result['score'] ?? 0) > 0.1;
        });
    }

    private function sortAndLimitResults(array $results): \Illuminate\Support\Collection
    {
        // Apply model-specific score boosts using your configuration
        $results = array_map(function ($result) {
            $type = strtolower(class_basename($result['model']));
            $boost = timebank_config('main_search_bar.boosted_models.' . $type, 1);

            // Apply location proximity boost
            $locationBoost = $this->getLocationProximityBoost($result['location_proximity'] ?? []);

            $result['score'] = ($result['score'] ?? 1) * $boost * $locationBoost;
            return $result;
        }, $results);

        // Sort by score and location proximity, then limit results using your configuration
        return collect($results)
            ->sortBy([
                // Primary sort: location proximity (closer locations first)
                ['location_proximity.distance', 'asc'],
                // Secondary sort: score (higher scores first)
                ['score', 'desc']
            ])
            ->take(timebank_config('main_search_bar.search.max_results', 50))
            ->map(function ($result) {
                return [
                    'model' => $result['model'] ?? '',
                    'id' => $result['id'] ?? '',
                    'score' => $result['score'] ?? '',
                    'highlight' => $this->extractBestHighlight($result['highlight'] ?? []),
                    'suggest' => [],
                    'location_proximity' => $result['location_proximity'] ?? [],
                ];
            });
    }

    private function getLocationProximityBoost(array $locationProximity): float
    {
        if (empty($locationProximity) || !isset($locationProximity['level'])) {
            return 1.0; // No location data, neutral boost
        }

        // Location-based boost multipliers (closer = higher boost)
        $boostMap = [
            'same_district' => 2.5,    // Highest boost for same district
            'same_city' => 2.0,        // High boost for same city
            'same_division' => 1.5,    // Medium boost for same division/state
            'same_country' => 1.2,     // Small boost for same country
            'different_country' => 1.0, // Neutral for different countries
            'no_location' => 0.9,      // Slight penalty for no location
            'unknown' => 1.0,          // Neutral for unknown
            'error' => 1.0,           // Neutral for errors
        ];

        return $boostMap[$locationProximity['level']] ?? 1.0;
    }

    private function extractBestHighlight(array $highlights): array
    {
        if (empty($highlights)) {
            return [];
        }

        // Return the first highlight from the most relevant field
        $priorityFields = [
            'tags.contexts.categories.name_' . app()->getLocale(),
            'name',
            'about_short_' . app()->getLocale(),
            'post_translations.title_' . app()->getLocale(),
        ];

        foreach ($priorityFields as $field) {
            if (isset($highlights[$field]) && !empty($highlights[$field])) {
                return $highlights[$field];
            }
        }

        // Fallback to first available highlight
        return $highlights[array_key_first($highlights)] ?? [];
    }

    private function handleSearchError(\Exception $e, array $categoryNames)
    {
        \Log::error('MainBrowseTagCategories search error', [
            'error' => $e->getMessage(),
            'categoryNames' => $categoryNames,
            'locale' => app()->getLocale(),
            'trace' => $e->getTraceAsString()
        ]);

        $this->resetResults();
    }

    private function getAllCategoryIds($categoryId)
    {
        if (!$this->validateCategoryId($categoryId)) {
            return [];
        }

        $cacheKey = 'category_descendants_' . $categoryId;

        return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($categoryId) {
            $category = Category::find($categoryId);
            if (!$category) {
                return [(int)$categoryId];
            }

            try {
                $descendants = $category->descendants()->pluck('id')->toArray();
                $allIds = array_merge([(int)$categoryId], array_map('intval', $descendants));

                return array_values(array_filter($allIds, [$this, 'validateCategoryId']));
            } catch (\Exception $e) {
                return [(int)$categoryId];
            }
        });
    }

    public function showCategoryResults()
    {
        if (empty($this->selectedCategories)) {
            return null;
        }

        $validCategoryIds = array_filter($this->selectedCategories, [$this, 'validateCategoryId']);

        if (empty($validCategoryIds)) {
            return null;
        }

        $searchTerm = $this->buildSearchTermFromCategories($validCategoryIds);

        // Ensure fetchedResults is a Collection before calling map()
        $fetchedResults = is_array($this->fetchedResults) ? collect($this->fetchedResults) : $this->fetchedResults;

        $results = $fetchedResults->map(fn($r) => [
            'model' => $r['model'],
            'id' => $r['id'],
            'highlight' => $r['highlight'] ?? [],
            'score' => $r['score'] ?? null,
        ])->values()->all();

        // Cache results for search.show view using your configuration
        $key = 'main_search_bar_results_' . Auth::guard('web')->id();
        $cacheData = [
            'results' => $results,
            'searchTerm' => $searchTerm,
            'total' => $this->total
        ];

        Cache::put($key, $cacheData, now()->addMinutes(
            timebank_config('main_search_bar.cache_results', 5)
        ));

        return redirect()->route('search.show');
    }

    private function buildSearchTermFromCategories(array $categoryIds): string
    {
        $categories = Category::whereIn('id', $categoryIds)
            ->with(['translations' => function ($query) {
                $query->where('locale', app()->getLocale());
            }])
            ->get();

        $searchTerm = $categories->map(function ($category) {
            return $category->translation ? $category->translation->name : $category->name;
        })->filter()->implode(', ');

        return $searchTerm ?: 'Selected Categories (' . count($categoryIds) . ')';
    }

    // Keep the original renderHorizontalCategoryTree method if still needed
    public function renderHorizontalCategoryTree($categories, $level = 0)
    {
        $html = '';
        $baseSize = $level === 0 ? 'text-sm' : 'text-xs';
        $padding = $level === 0 ? 'px-3 py-1.5' : 'px-2 py-1';

        foreach ($categories as $category) {
            $isSelected = in_array($category['id'], $this->selectedCategories);
            $selectedClass = $isSelected ? 'ring-2 ring-blue-500 ring-offset-1' : '';
            $opacity = $level > 0 ? 'opacity-90' : '';

            $html .= '<button wire:click="selectCategory(' . $category['id'] . ')" class="bg-' . $category['color'] . '-400 hover:bg-' . $category['color'] . '-500 text-black inline-flex items-center rounded-md ' . $padding . ' ' . $baseSize . ' font-normal transition duration-150 ease-in-out cursor-pointer ' . $selectedClass . ' ' . $opacity . '">';

            if ($level > 0) {
                $html .= str_repeat('・', $level) . ' ';
            }

            $html .= htmlspecialchars($category['name']);
            $html .= '</button>';

            if (!empty($category['children'])) {
                $html .= $this->renderHorizontalCategoryTree($category['children'], $level + 1);
            }
        }

        return $html;
    }
}
