<?php

namespace App\Http\Livewire\Categories;

use App\Http\Livewire\Traits\RequiresAdminAuthorization;
use App\Models\Category;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
use Livewire\WithPagination;
use WireUi\Traits\WireUiActions;

class Manage extends Component
{
    use WithPagination;
    use WireUiActions;
    use RequiresAdminAuthorization;

    public $search = '';
    public $languageFilter = '';
    public $parentFilter = '';
    public $perPage = 10;
    public $page;
    public string $sortField = 'updated_at';
    public string $sortDirection = 'desc';
    public $bulkSelected = []; // Array of category IDs
    public bool $bulkDisabled = true;
    public bool $modalBulkDeleteTranslations = false;
    public bool $modalDeleteTranslation = false;
    public bool $modalEditCategory = false;
    public $selectedTranslations;
    public $selectedTranslation;
    public $selectedTranslationId;
    public $affectedTagsCount = 0;
    public $needsCategoryReassignment = false;
    public $targetCategoryId = null;
    public $categoryReassignments = []; // Array of category_id => target_category_id
    public $categoriesWithTags = []; // Array of category data for bulk delete
    public $availableCategories = [];
    public string $confirmString = '';

    // Edit modal properties
    public $editTranslationId;
    public $editCategoryId;
    public $editName = '';
    public $editLocale = '';
    public $editParentId = null;
    public $editColor = '';
    public $editAffectedTagsCount = 0;
    public $availableColors = [];

    // Create modal properties
    public bool $modalCreateCategory = false;
    public $createTranslations = [];
    public $createParentId = null;
    public $createColor = 'gray';

    protected $listeners = ['colorUpdated'];

    public function mount()
    {
        // Admin Authorization - Prevent IDOR attacks and cross-guard access
        $activeProfileType = session('activeProfileType');
        $activeProfileId = session('activeProfileId');

        if (!$activeProfileType || !$activeProfileId) {
            abort(403, __('No active profile selected'));
        }

        $profile = $activeProfileType::find($activeProfileId);

        if (!$profile) {
            abort(403, __('Active profile not found'));
        }

        // Validate profile ownership using ProfileAuthorizationHelper (prevents cross-guard attacks)
        \App\Helpers\ProfileAuthorizationHelper::authorize($profile);

        // Verify admin or central bank permissions
        if ($profile instanceof \App\Models\Admin) {
            // Admin access OK
        } elseif ($profile instanceof \App\Models\Bank) {
            // Only central bank (level 0) can access category management
            if ($profile->level !== 0) {
                abort(403, __('Central bank access required for category management'));
            }
        } else {
            abort(403, __('Admin or central bank access required'));
        }

        // Log admin access for security monitoring
        \Log::info('Categories management access', [
            'component' => 'Categories\\Manage',
            'profile_id' => $profile->id,
            'profile_type' => get_class($profile),
            'authenticated_guard' => \Auth::getDefaultDriver(),
            'ip_address' => request()->ip(),
        ]);

        // Initialize createTranslations as an empty array
        $this->createTranslations = [];
    }

    protected $queryString = [
        'search' => ['except' => ''],
        'languageFilter' => ['except' => ''],
        'parentFilter' => ['except' => ''],
        'sortField' => ['except' => 'updated_at'],
        'sortDirection' => ['except' => 'desc'],
        'perPage' => ['except' => 10],
        'page' => ['except' => 1]
    ];

    public function searchCategories()
    {
        $this->resetPage();
        $this->dispatch('scroll-to-top');
    }

    public function handleSearchEnter()
    {
        $this->searchCategories();
    }

    public function resetSearch()
    {
        $this->search = '';
        $this->resetPage();
        $this->dispatch('scroll-to-top');
    }

    public function resetLanguageFilter()
    {
        $this->languageFilter = '';
        $this->resetPage();
        $this->dispatch('scroll-to-top');
    }

    public function resetParentFilter()
    {
        $this->parentFilter = '';
        $this->resetPage();
        $this->dispatch('scroll-to-top');
    }

    public function updatingSearch()
    {
        $this->resetPage();
    }

    public function updatedPage()
    {
        $this->dispatch('scroll-to-top');
    }

    public function updatedPerPage($value)
    {
        $this->resetPage();
        $this->dispatch('scroll-to-top');
    }

    public function sortBy(string $field): void
    {
        if ($this->sortField === $field) {
            $this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
        } else {
            $this->sortDirection = 'asc';
        }

        $this->sortField = $field;
        $this->resetPage();
    }

    public function updatedBulkSelected()
    {
        // Simple toggle: enable bulk actions if any categories are selected
        $this->bulkDisabled = empty($this->bulkSelected);
    }

    public function openBulkDeleteTranslationsModal()
    {
        $this->confirmString = '';
        $this->categoryReassignments = [];
        $this->categoriesWithTags = [];

        // Validate that selected categories exist
        $affectedCategoryIds = Category::whereIn('id', $this->bulkSelected)
            ->pluck('id')
            ->toArray();

        if (empty($affectedCategoryIds)) {
            $this->notification()->error(
                $title = __('Error'),
                $description = __('No valid categories selected for deletion.')
            );
            $this->resetBulkSelection();
            return;
        }

        // Get all translations for the selected categories
        $this->selectedTranslations = DB::table('category_translations')
            ->whereIn('category_id', $affectedCategoryIds)
            ->get();

        $currentLocale = App::getLocale();
        $baseLocale = timebank_config('base_language', 'en');

        // Get available categories for reassignment (excluding those being deleted)
        $this->availableCategories = Category::where('type', \App\Models\Tag::class)
            ->whereNotIn('id', $affectedCategoryIds)
            ->with('translations')
            ->get()
            ->map(function ($category) use ($currentLocale, $baseLocale) {
                // Try current locale first
                $trans = $category->translations->firstWhere('locale', $currentLocale);

                // Fallback to base locale
                if (!$trans) {
                    $trans = $category->translations->firstWhere('locale', $baseLocale);
                }

                // Fallback to any available translation
                if (!$trans) {
                    $trans = $category->translations->first();
                }

                return [
                    'id' => $category->id,
                    'name' => $trans ? $trans->name : __('Category ID') . ' ' . $category->id
                ];
            })
            ->sortBy('name')
            ->values()
            ->toArray();

        // Build category data with tags info (including children)
        $this->affectedTagsCount = 0;
        foreach ($affectedCategoryIds as $categoryId) {
            // Get child category IDs
            $childCategoryIds = Category::where('parent_id', $categoryId)->pluck('id')->toArray();
            $allCategoryIds = array_merge([$categoryId], $childCategoryIds);

            // Count tags for this category AND its children
            $tagsCount = DB::table('taggable_contexts')
                ->whereIn('category_id', $allCategoryIds)
                ->join('taggable_locale_context', 'taggable_contexts.id', '=', 'taggable_locale_context.context_id')
                ->distinct('taggable_locale_context.tag_id')
                ->count('taggable_locale_context.tag_id');

            if ($tagsCount > 0) {
                $this->affectedTagsCount += $tagsCount;

                // Get category name
                $categoryTrans = $validSelectedTranslations->where('category_id', $categoryId)->first();

                $this->categoriesWithTags[] = [
                    'category_id' => $categoryId,
                    'tags_count' => $tagsCount,
                    'name' => $categoryTrans ? $categoryTrans->name : __('Category ID') . ' ' . $categoryId
                ];

                // Initialize reassignment value
                $this->categoryReassignments[$categoryId] = null;
            }
        }

        $this->needsCategoryReassignment = !empty($this->categoriesWithTags);

        $this->modalBulkDeleteTranslations = true;
    }

    public function deleteSelected()
    {
        // CRITICAL: Authorize admin access for bulk deleting categories
        $this->authorizeAdminAccess();

        // Validate the confirmation string
        $rules = [
            'confirmString' => [
                'required',
                function ($attribute, $value, $fail) {
                    $expected = __('messages.confirm_input_string');
                    if ($value !== $expected) {
                        $fail(__('The confirmation keyword is incorrect.'));
                    }
                },
            ]
        ];

        // If reassignment is needed, validate each category reassignment
        if (count($this->categoriesWithTags) > 0) {
            foreach ($this->categoriesWithTags as $categoryData) {
                $categoryId = $categoryData['category_id'];
                $rules["categoryReassignments.{$categoryId}"] = [
                    'required',
                    'exists:categories,id',
                    function ($attribute, $value, $fail) use ($categoryId) {
                        if ($value == $categoryId) {
                            $fail(__('You cannot reassign tags to the same category being deleted.'));
                        }
                    }
                ];
            }
        }

        $this->validate($rules);

        try {
            DB::transaction(function () {
                // Use the selected category IDs directly
                $categoryIds = $this->bulkSelected;

                // Process each category with tags first
                foreach ($this->categoriesWithTags as $categoryData) {
                    $categoryId = $categoryData['category_id'];
                    $targetCategoryId = $this->categoryReassignments[$categoryId] ?? null;

                    if ($targetCategoryId) {
                        // Get child category IDs
                        $childCategoryIds = Category::where('parent_id', $categoryId)->pluck('id')->toArray();
                        $allCategoryIds = array_merge([$categoryId], $childCategoryIds);

                        // Update all contexts from parent AND children to point to the new category
                        DB::table('taggable_contexts')
                            ->whereIn('category_id', $allCategoryIds)
                            ->update(['category_id' => $targetCategoryId]);
                    }
                }

                // Handle orphaned children for categories being deleted
                foreach ($categoryIds as $categoryId) {
                    $childCategoryIds = Category::where('parent_id', $categoryId)->pluck('id')->toArray();
                    if (!empty($childCategoryIds)) {
                        Category::whereIn('id', $childCategoryIds)
                            ->update(['parent_id' => null]);
                    }
                }

                // Delete all translations for selected categories
                DB::table('category_translations')
                    ->whereIn('category_id', $categoryIds)
                    ->delete();

                // Delete the categories themselves
                Category::whereIn('id', $categoryIds)->delete();
            });

            $message = __('Selected categories were deleted successfully!');
            if (count($this->categoriesWithTags) > 0) {
                $message .= ' ' . __('Tags have been reassigned to the selected categories.');
            }

            $this->notification()->success(
                $title = __('Deleted'),
                $description = $message
            );

            // Reset and close modal
            $this->resetPage();
            $this->dispatch('scroll-to-top');
            $this->bulkSelected = [];
            $this->confirmString = '';
            $this->targetCategoryId = null;
            $this->modalBulkDeleteTranslations = false;
        } catch (\Illuminate\Validation\ValidationException $e) {
            // Re-throw validation errors so they display in the modal
            throw $e;
        } catch (\Exception $e) {
            $this->notification()->error(
                $title = __('Error!'),
                $description = __('Oops, could not delete the selected translations') . '!' . $e->getMessage()
            );
        }
    }

    public function resetBulkSelection()
    {
        $this->bulkSelected = [];
        $this->bulkDisabled = true;

        $this->notification()->info(
            $title = __('Selection cleared'),
            $description = __('Bulk selection has been reset.')
        );
    }

    public function openDeleteCategoryModal($translationId)
    {
        $this->confirmString = '';
        $this->targetCategoryId = null;

        // Get the translation to find the category
        $translation = DB::table('category_translations')->find($translationId);

        if (!$translation) {
            $this->notification()->error(
                $title = __('Error'),
                $description = __('Translation not found.')
            );
            return;
        }

        // Get all translations for this category
        $this->selectedTranslations = DB::table('category_translations')
            ->where('category_id', $translation->category_id)
            ->get();

        $this->selectedTranslationId = $translation->category_id; // Store category ID instead

        // Get child category IDs
        $childCategoryIds = Category::where('parent_id', $translation->category_id)->pluck('id')->toArray();

        // Count affected tags from both the category itself AND its children
        $categoryIds = array_merge([$translation->category_id], $childCategoryIds);

        $this->affectedTagsCount = DB::table('taggable_contexts')
            ->whereIn('category_id', $categoryIds)
            ->join('taggable_locale_context', 'taggable_contexts.id', '=', 'taggable_locale_context.context_id')
            ->distinct('taggable_locale_context.tag_id')
            ->count('taggable_locale_context.tag_id');

        // If there are affected tags, we need category reassignment
        $this->needsCategoryReassignment = ($this->affectedTagsCount > 0);

        if ($this->needsCategoryReassignment) {
            // Get available categories (excluding the one being deleted)
            $currentLocale = App::getLocale();
            $baseLocale = timebank_config('base_language', 'en');

            $this->availableCategories = Category::where('type', \App\Models\Tag::class)
                ->where('id', '!=', $translation->category_id)
                ->with('translations')
                ->get()
                ->map(function ($category) use ($currentLocale, $baseLocale) {
                    // Try current locale first
                    $trans = $category->translations->firstWhere('locale', $currentLocale);

                    // Fallback to base locale
                    if (!$trans) {
                        $trans = $category->translations->firstWhere('locale', $baseLocale);
                    }

                    // Fallback to any available translation
                    if (!$trans) {
                        $trans = $category->translations->first();
                    }

                    return [
                        'id' => $category->id,
                        'name' => $trans ? $trans->name : __('Category ID') . ' ' . $category->id
                    ];
                })
                ->sortBy('name')
                ->values()
                ->toArray();
        }

        $this->modalDeleteTranslation = true;
    }

    public function deleteCategory()
    {
        // CRITICAL: Authorize admin access for deleting category
        $this->authorizeAdminAccess();

        // Validate the confirmation string
        $rules = [
            'confirmString' => [
                'required',
                function ($attribute, $value, $fail) {
                    $expected = __('messages.confirm_input_string');
                    if ($value !== $expected) {
                        $fail(__('The confirmation keyword is incorrect.'));
                    }
                },
            ]
        ];

        // If reassignment is needed, validate target category
        if ($this->needsCategoryReassignment) {
            $rules['targetCategoryId'] = ['required', 'exists:categories,id'];
        }

        $this->validate($rules);

        try {
            DB::transaction(function () {
                $categoryId = $this->selectedTranslationId; // This is actually the category ID now

                // Get child categories
                $childCategoryIds = Category::where('parent_id', $categoryId)->pluck('id')->toArray();

                // If reassignment is needed, move tags from parent AND children to new category
                if ($this->needsCategoryReassignment && $this->targetCategoryId) {
                    $allCategoryIds = array_merge([$categoryId], $childCategoryIds);

                    // Update all contexts from parent and children to point to the new category
                    DB::table('taggable_contexts')
                        ->whereIn('category_id', $allCategoryIds)
                        ->update(['category_id' => $this->targetCategoryId]);
                }

                // Handle orphaned children - convert them to root categories (remove parent_id)
                if (!empty($childCategoryIds)) {
                    Category::whereIn('id', $childCategoryIds)
                        ->update(['parent_id' => null]);
                }

                // Delete all translations for this category
                DB::table('category_translations')
                    ->where('category_id', $categoryId)
                    ->delete();

                // Delete the category
                Category::find($categoryId)?->delete();
            });

            $message = __('Category and all its translations were deleted successfully!');
            if ($this->needsCategoryReassignment && $this->targetCategoryId) {
                $message .= ' ' . __('Tags have been reassigned to the selected category.');
            }

            $this->notification()->success(
                $title = __('Deleted'),
                $description = $message
            );

            // Reset and close modal
            $this->resetPage();
            $this->dispatch('scroll-to-top');
            $this->confirmString = '';
            $this->targetCategoryId = null;
            $this->modalDeleteTranslation = false;
            $this->selectedTranslations = null;
        } catch (\Illuminate\Validation\ValidationException $e) {
            // Re-throw validation errors so they display in the modal
            throw $e;
        } catch (\Exception $e) {
            $this->notification()->error(
                $title = __('Error!'),
                $description = __('Oops, could not delete the category') . '!' . $e->getMessage()
            );
        }
    }

    public function openEditCategoryModal($translationId)
    {
        $this->confirmString = '';

        // Get the translation
        $translation = DB::table('category_translations')->find($translationId);

        if (!$translation) {
            $this->notification()->error(
                $title = __('Error'),
                $description = __('Translation not found.')
            );
            return;
        }

        // Get the category
        $category = Category::find($translation->category_id);

        if (!$category) {
            $this->notification()->error(
                $title = __('Error'),
                $description = __('Category not found.')
            );
            return;
        }

        // Set edit properties
        $this->editTranslationId = $translationId;
        $this->editCategoryId = $category->id;
        $this->editName = $translation->name;
        $this->editLocale = $translation->locale;
        $this->editParentId = $category->parent_id;
        $this->editColor = $category->color ?? 'gray';

        // Count affected tags
        $this->editAffectedTagsCount = DB::table('taggable_contexts')
            ->where('category_id', $category->id)
            ->join('taggable_locale_context', 'taggable_contexts.id', '=', 'taggable_locale_context.context_id')
            ->distinct('taggable_locale_context.tag_id')
            ->count('taggable_locale_context.tag_id');

        // Build colors array from tailwind.config.js safelist
        $this->availableColors = $this->getAvailableColors();

        $this->modalEditCategory = true;
    }

    public function updateCategory()
    {
        // CRITICAL: Authorize admin access for updating category
        $this->authorizeAdminAccess();

        // Validate the input
        $rules = [
            'editName' => ['required', 'string', 'max:255'],
            'editParentId' => ['nullable', 'exists:categories,id'],
            'confirmString' => [
                'required',
                function ($attribute, $value, $fail) {
                    $expected = __('messages.confirm_input_string');
                    if ($value !== $expected) {
                        $fail(__('The confirmation keyword is incorrect.'));
                    }
                },
            ]
        ];

        // Color is required only if no parent is selected
        if (!$this->editParentId) {
            $rules['editColor'] = ['required', 'string'];
        }

        $this->validate($rules);

        try {
            DB::transaction(function () {
                // Update the translation name
                DB::table('category_translations')
                    ->where('id', $this->editTranslationId)
                    ->update([
                        'name' => $this->editName,
                        'updated_at' => now()
                    ]);

                // Determine color: inherit from parent or use selected color
                $color = $this->editColor;
                if ($this->editParentId) {
                    $parentCategory = Category::find($this->editParentId);
                    if ($parentCategory) {
                        $color = $parentCategory->color;
                    }
                }

                // Update the category (parent and color - affects all translations)
                Category::where('id', $this->editCategoryId)
                    ->update([
                        'parent_id' => $this->editParentId,
                        'color' => $color,
                        'updated_at' => now()
                    ]);
            });

            $this->notification()->success(
                $title = __('Updated'),
                $description = __('Category updated successfully!')
            );

            // Reset and close modal
            $this->resetPage();
            $this->dispatch('scroll-to-top');
            $this->confirmString = '';
            $this->modalEditCategory = false;
        } catch (\Illuminate\Validation\ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            $this->notification()->error(
                $title = __('Error!'),
                $description = __('Oops, could not update the category') . '!' . $e->getMessage()
            );
        }
    }

    private function getAvailableColors()
    {
        // Extract colors from the safelist pattern
        $colors = [
            'slate', 'gray', 'zinc', 'neutral', 'stone',
            'red', 'orange', 'amber', 'yellow', 'lime',
            'green', 'emerald', 'teal', 'cyan', 'sky',
            'blue', 'indigo', 'violet', 'purple', 'fuchsia',
            'pink', 'rose'
        ];

        return collect($colors)->map(function ($color) {
            return [
                'value' => $color,
                'label' => ucfirst($color)
            ];
        })->toArray();
    }

    public function colorUpdated($color)
    {
        $this->createColor = $color;
    }

    public function updatedCreateTranslations()
    {
        // This method is called when any createTranslations value changes
        // Ensure the array remains valid
        if (!is_array($this->createTranslations)) {
            $this->createTranslations = [];
        }
    }

    public function getSupportedLocalesProperty()
    {
        // Get supported locales from config, with app locale first
        $allLocales = array_keys(config('laravellocalization.supportedLocales'));
        $appLocale = app()->getLocale();

        // Put app locale first
        return array_merge(
            [$appLocale],
            array_diff($allLocales, [$appLocale])
        );
    }

    public function openCreateCategoryModal()
    {
        $this->confirmString = '';

        // Initialize translation array with all supported locales
        $this->createTranslations = [];
        $supportedLocales = $this->supportedLocales; // Get the computed property value
        foreach ($supportedLocales as $locale) {
            $this->createTranslations[$locale] = '';
        }

        $this->createParentId = null;
        $this->createColor = 'gray';

        $this->modalCreateCategory = true;
    }

    public function storeCategory()
    {
        // CRITICAL: Authorize admin access for creating category
        $this->authorizeAdminAccess();

        // Build validation rules
        $rules = [];

        // Get supported locales
        $supportedLocales = $this->supportedLocales;

        // All translations are required
        foreach ($supportedLocales as $locale) {
            $rules["createTranslations.{$locale}"] = ['required', 'string', 'max:255'];
        }

        $rules['createParentId'] = ['nullable', 'exists:categories,id'];

        // Color is required if no parent is selected
        if (!$this->createParentId) {
            $rules['createColor'] = ['required', 'string'];
        }

        $rules['confirmString'] = [
            'required',
            function ($attribute, $value, $fail) {
                $expected = __('messages.confirm_input_string');
                if ($value !== $expected) {
                    $fail(__('The confirmation keyword is incorrect.'));
                }
            },
        ];

        $this->validate($rules);

        try {
            DB::transaction(function () use ($supportedLocales) {
                // Determine color: inherit from parent or use selected color
                $color = $this->createColor;
                if ($this->createParentId) {
                    $parentCategory = Category::find($this->createParentId);
                    if ($parentCategory) {
                        $color = $parentCategory->color;
                    }
                }

                // Create the category
                $category = Category::create([
                    'type' => \App\Models\Tag::class,
                    'parent_id' => $this->createParentId,
                    'color' => $color,
                    'created_at' => now(),
                    'updated_at' => now()
                ]);

                // Track slugs used in this batch to avoid duplicates
                $usedSlugs = [];

                // Create translations for all locales
                foreach ($supportedLocales as $locale) {
                    $name = $this->createTranslations[$locale];
                    $baseSlug = \Illuminate\Support\Str::slug($name);

                    // Add locale prefix to slug (e.g., en-test-category)
                    $slug = $locale . '-' . $baseSlug;

                    // Ensure slug is globally unique
                    $originalSlug = $slug;
                    $counter = 1;
                    while (
                        DB::table('category_translations')->where('slug', $slug)->exists() ||
                        in_array($slug, $usedSlugs)
                    ) {
                        $slug = $originalSlug . '-' . $counter;
                        $counter++;
                    }

                    // Mark this slug as used
                    $usedSlugs[] = $slug;

                    DB::table('category_translations')->insert([
                        'category_id' => $category->id,
                        'locale' => $locale,
                        'slug' => $slug,
                        'name' => $name,
                        'created_at' => now(),
                        'updated_at' => now()
                    ]);
                }
            });

            $this->notification()->success(
                $title = __('Created'),
                $description = __('Category created successfully!')
            );

            // Reset and close modal
            $this->resetPage();
            $this->dispatch('scroll-to-top');
            $this->confirmString = '';
            $this->modalCreateCategory = false;
        } catch (\Illuminate\Validation\ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            $this->notification()->error(
                $title = __('Error!'),
                $description = __('Oops, could not create the category') . '!' . $e->getMessage()
            );
        }
    }

    public function getBulkDisabledProperty()
    {
        return count($this->bulkSelected) === 0;
    }

    public function getEditPreviewColorProperty()
    {
        // If a parent is selected, use the parent's color
        if ($this->editParentId && $this->editParentId !== 'none') {
            $parentCategory = Category::find($this->editParentId);
            if ($parentCategory) {
                return $parentCategory->color;
            }
        }

        // Otherwise use the selected color
        return $this->editColor ?: 'gray';
    }

    public function getCreatePreviewColorProperty()
    {
        // If a parent is selected, use the parent's color
        if ($this->createParentId && $this->createParentId !== 'none') {
            $parentCategory = Category::find($this->createParentId);
            if ($parentCategory) {
                return $parentCategory->color;
            }
        }

        // Otherwise use the selected color
        return $this->createColor ?: 'gray';
    }

    public function getLanguagesProperty()
    {
        return DB::table('category_translations')
            ->select('locale')
            ->distinct()
            ->orderBy('locale')
            ->get()
            ->map(function ($item) {
                return [
                    'id' => $item->locale,
                    'name' => __('messages.' . $item->locale)
                ];
            });
    }

    public function getParentsProperty()
    {
        $query = Category::with(['translations' => function ($query) {
            $query->where('locale', App::getLocale());
        }])
        ->where('type', \App\Models\Tag::class)
        ->whereNull('parent_id'); // Only root categories (no parent) can be parents

        // When editing, exclude the current category and its children to prevent circular references
        if ($this->editCategoryId) {
            $query->where('id', '!=', $this->editCategoryId)
                  ->doesntHave('children'); // When editing, only allow categories without children
        }

        $parents = $query->get()
            ->map(function ($category) {
                return [
                    'id' => $category->id,
                    'name' => $category->translation ? $category->translation->name : __('Untitled category')
                ];
            })
            ->sortBy('name');

        // Add "No parent" option
        return collect([
            ['id' => 'none', 'name' => '(' . __('No parent') . ')']
        ])->merge($parents);
    }

    public function render()
    {
        $query = Category::query();

        // Determine if we're sorting by translation fields (which breaks grouping)
        $sortingByTranslation = in_array($this->sortField, ['name', 'locale', 'updated_at']);

        // Apply with conditions based on language filter and sort field
        if ($sortingByTranslation) {
            // When sorting by translation fields, only load one translation per category
            if ($this->languageFilter) {
                $query->with([
                    'translations' => function ($q) {
                        $q->where('locale', $this->languageFilter)->limit(1);
                    },
                    'parent.translations' => function ($q) {
                        $q->where('locale', App::getLocale());
                    }
                ]);
            } else {
                // Load only the translation we're actually displaying (from the join)
                $query->with([
                    'parent.translations' => function ($q) {
                        $q->where('locale', App::getLocale());
                    }
                ]);
            }
        } else {
            // Normal grouping behavior - load all translations
            if ($this->languageFilter) {
                $query->with([
                    'translations' => function ($q) {
                        $q->where('locale', $this->languageFilter);
                    },
                    'parent.translations' => function ($q) {
                        $q->where('locale', App::getLocale());
                    }
                ]);
            } else {
                $query->with([
                    'translations',
                    'parent.translations' => function ($q) {
                        $q->where('locale', App::getLocale());
                    }
                ]);
            }
        }

        // Filter only Tag categories
        $query->where('categories.type', \App\Models\Tag::class);

        // Add tags count using a left join and count (but don't apply select/groupBy yet for translation sorting)
        $query->leftJoin('taggable_contexts', 'categories.id', '=', 'taggable_contexts.category_id')
            ->leftJoin('taggable_locale_context', 'taggable_contexts.id', '=', 'taggable_locale_context.context_id');

        // Apply filters
        $query->when($this->search, function ($query) {
            $query->where(function ($q) {
                $q->where('categories.id', $this->search)
                  ->orWhereHas('translations', function ($q) {
                      $q->where('name', 'like', '%' . $this->search . '%')
                        ->orWhere('slug', 'like', '%' . $this->search . '%');
                  })
                  ->orWhereHas('parent.translations', function ($q) {
                      $q->where('name', 'like', '%' . $this->search . '%');
                  });
            });
        })
        ->when($this->languageFilter, function ($query) {
            $query->whereHas('translations', function ($q) {
                $q->where('locale', $this->languageFilter);
            });
        })
        ->when($this->parentFilter, function ($query) {
            if ($this->parentFilter === 'none') {
                $query->whereNull('parent_id');
            } else {
                $query->where('parent_id', $this->parentFilter);
            }
        });

        // Apply sorting
        switch ($this->sortField) {
            case 'id':
                $query->selectRaw('categories.*, COUNT(DISTINCT taggable_locale_context.tag_id) as tags_count')
                    ->groupBy('categories.id', 'categories.type', 'categories.categoryable_id', 'categories.categoryable_type',
                             'categories.parent_id', 'categories.color', 'categories.created_at', 'categories.updated_at',
                             'categories.deleted_at')
                    ->orderBy('categories.id', $this->sortDirection);
                break;

            case 'name':
            case 'locale':
            case 'updated_at':
                // For translation fields, join and sort - this creates one row per translation
                $query->join('category_translations', 'categories.id', '=', 'category_translations.category_id')
                    ->when($this->languageFilter, function ($q) {
                        $q->where('category_translations.locale', $this->languageFilter);
                    })
                    ->selectRaw('categories.*, COUNT(DISTINCT taggable_locale_context.tag_id) as tags_count,
                                category_translations.id as joined_translation_id,
                                category_translations.locale as joined_locale,
                                category_translations.name as joined_name,
                                category_translations.updated_at as joined_updated_at')
                    ->groupBy('categories.id', 'categories.type', 'categories.categoryable_id', 'categories.categoryable_type',
                             'categories.parent_id', 'categories.color', 'categories.created_at', 'categories.updated_at',
                             'categories.deleted_at', 'category_translations.id', 'category_translations.locale',
                             'category_translations.name', 'category_translations.updated_at')
                    ->orderBy('category_translations.' . $this->sortField, $this->sortDirection);
                break;

            case 'parent':
                $query->leftJoin('categories as parent_categories', 'categories.parent_id', '=', 'parent_categories.id')
                    ->leftJoin('category_translations as parent_translations', function ($join) {
                        $join->on('parent_categories.id', '=', 'parent_translations.category_id')
                            ->where('parent_translations.locale', App::getLocale());
                    })
                    ->selectRaw('categories.*, COUNT(DISTINCT taggable_locale_context.tag_id) as tags_count')
                    ->groupBy('categories.id', 'categories.type', 'categories.categoryable_id', 'categories.categoryable_type',
                             'categories.parent_id', 'categories.color', 'categories.created_at', 'categories.updated_at',
                             'categories.deleted_at')
                    ->orderBy('parent_translations.name', $this->sortDirection)
                    ->orderBy('categories.id', 'asc'); // Secondary sort by ID to group translations
                break;

            case 'tags_count':
                $query->selectRaw('categories.*, COUNT(DISTINCT taggable_locale_context.tag_id) as tags_count')
                    ->groupBy('categories.id', 'categories.type', 'categories.categoryable_id', 'categories.categoryable_type',
                             'categories.parent_id', 'categories.color', 'categories.created_at', 'categories.updated_at',
                             'categories.deleted_at')
                    ->orderBy('tags_count', $this->sortDirection)
                    ->orderBy('categories.id', 'asc'); // Secondary sort by ID to group translations
                break;

            default:
                $query->selectRaw('categories.*, COUNT(DISTINCT taggable_locale_context.tag_id) as tags_count')
                    ->groupBy('categories.id', 'categories.type', 'categories.categoryable_id', 'categories.categoryable_type',
                             'categories.parent_id', 'categories.color', 'categories.created_at', 'categories.updated_at',
                             'categories.deleted_at')
                    ->orderBy('categories.updated_at', $this->sortDirection)
                    ->orderBy('categories.id', 'asc'); // Secondary sort by ID to group translations
                break;
        }

        $categories = $query->paginate($this->perPage);

        return view('livewire.categories.manage', [
            'categories' => $categories
        ]);
    }
}
