{{--
|--------------------------------------------------------------------------
| Plik Widoku: ZarzÄ…dzanie Kategoriami Menu
|--------------------------------------------------------------------------
|
| Lokalizacja: resources/views/categories/index.blade.php
| Autor: Tomasz KapÅ‚aÅ„ski & Coding Partner (Gemini)
| Wersja: 3.0 (Drag & Drop, bez paginacji)
| Ostatnia modyfikacja: 6 lipca 2025
|
|--------------------------------------------------------------------------
| Opis Przeznaczenia
|--------------------------------------------------------------------------
|
| Ten plik Blade renderuje w peÅ‚ni interaktywny, jednostronicowy interfejs
| (Single Page Application-like experience) do zarzÄ…dzania kategoriami menu
| restauracji. ZostaÅ‚ on zbudowany w nowoczesnym stosie technologicznym,
| kÅ‚adÄ…c nacisk na doskonaÅ‚e doÅ›wiadczenie uÅ¼ytkownika (UX) i wydajnoÅ›Ä‡
| poprzez minimalizacjÄ™ przeÅ‚adowaÅ„ strony.
|
|--------------------------------------------------------------------------
| Kluczowe FunkcjonalnoÅ›ci
|--------------------------------------------------------------------------
|
| - WyÅ›wietlanie PEÅNEJ listy kategorii z opcjÄ… wyszukiwania i sortowania po nazwie.
| - Zmiana kolejnoÅ›ci kategorii metodÄ… "PrzeciÄ…gnij i UpuÅ›Ä‡" (Drag & Drop)
| na caÅ‚ej liÅ›cie, z natychmiastowÄ… wizualnÄ… informacjÄ… zwrotnÄ….
| - BÅ‚yskawiczna zmiana statusu publikacji (widoczna/ukryta) za pomocÄ… przeÅ‚Ä…cznika
| "toggle" bez koniecznoÅ›ci przeÅ‚adowania strony.
| - Usuwanie kategorii z modalem potwierdzajÄ…cym, aby zapobiec przypadkowym akcjom.
| - Linki do stron tworzenia nowej kategorii oraz edycji juÅ¼ istniejÄ…cej.
| - PeÅ‚na obsÅ‚uga asynchronicznych operacji na bazie danych z wizualnym
| wskaÅºnikiem Å‚adowania (loader na caÅ‚Ä… stronÄ™).
| - System powiadomieÅ„ "toast" informujÄ…cych uÅ¼ytkownika o sukcesie lub
| niepowodzeniu wykonanej operacji.
|
|--------------------------------------------------------------------------
| Stos Technologiczny
|--------------------------------------------------------------------------
|
| - Backend: Laravel (silnik szablonÃ³w Blade)
| - Frontend (InteraktywnoÅ›Ä‡): Alpine.js
| - Frontend (Style): Tailwind CSS
| - Baza Danych: Google Firebase (Firestore)
| - Biblioteki dodatkowe: SortableJS (dla funkcji Drag & Drop)
|
|--------------------------------------------------------------------------
| ZaleÅ¼noÅ›ci
|--------------------------------------------------------------------------
|
| - Poprawnie zdefiniowane nazwane trasy (routes) w Laravelu: 'foods',
| 'category.create', 'category.edit'.
| - Skonfigurowany dostÄ™p do bazy danych Firestore (globalnie dostÄ™pny obiekt `database`).
| - DoÅ‚Ä…czone biblioteki JavaScript w gÅ‚Ã³wnym szablonie aplikacji (np. layouts/app.blade.php):
| 1. Alpine.js
| 2. SortableJS
|
--}}

@extends('layouts.app')

@section('content')

{{-- Styl dla przeciÄ…ganych wierszy --}}
<style>
    /* Styl dla wiersza, ktÃ³ry jest aktualnie przeciÄ…gany */
    .sortable-drag {
        opacity: 0.85;
        background: #fff;
        box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
        /* Lekkie uniesienie i obrÃ³t dajÄ… wraÅ¼enie "trzymania" karty */
        transform: rotate(1deg);
    }

    /* OSTATECZNY, PRECYZYJNY STYL DLA "DUCHA" (WSKAÅ¹NIKA MIEJSCA) */
    .sortable-ghost {
        /* Tworzymy "faÅ‚szywy" wiersz, ktÃ³ry jest praktycznie niewidzialny... */
        background: #f0f9ff;
        /* Kolor tÅ‚a dla lepszej widocznoÅ›ci */
        overflow: hidden;
    }

    .sortable-ghost td {
        /* ...jego zawartoÅ›Ä‡ jest caÅ‚kowicie przezroczysta... */
        color: transparent;
        /* ...a jego wysokoÅ›Ä‡ jest zredukowana do zera, aby nie wpÅ‚ywaÅ‚ na layout. */
        padding-top: 0;
        padding-bottom: 0;
        line-height: 0;
        height: 0;
    }

    /* ...a sam wskaÅºnik tworzymy za pomocÄ… grubej GÃ“RNEJ ramki. */
    .sortable-ghost {
        border-top: 3px solid #0ea5e9;
        /* uÅ¼yliÅ›my koloru sky-500 z Tailwind */
    }
    
    /* Styl dla body podczas przeciÄ…gania */
    body.dragging {
        cursor: grabbing !important;
        user-select: none;
    }
    
    body.dragging * {
        cursor: grabbing !important;
    }
    
    /* Lepsze style dla drag handle */
    .drag-handle:hover {
        color: #0ea5e9 !important;
        transform: scale(1.1);
        transition: all 0.2s ease;
    }
</style>

{{-- GÅ‚Ã³wny kontener z treÅ›ciÄ… --}}
<div id="main-wrapper" class="p-10"
    x-data="categoriesPage()" x-init="initCategories()">

    {{-- GÅ‚Ã³wny kontener z treÅ›ciÄ… --}}
    <div class="flex flex-col gap-6">
        {{-- NagÅ‚Ã³wek z tytuÅ‚em i przyciskami --}}
        <div class="p-6 bg-gradient-to-r from-slate-900 via-blue-800 to-blue-500 rounded-lg shadow-[1px_1px_4px_0px_#e2e8f0]">

            {{-- TytuÅ‚ i przyciski --}}
            <div class="flex flex-col md:flex-row justify-between md:items-start gap-4">
                {{-- TytuÅ‚ i opis --}}
                <div>
                    <h3 class="text-2xl font-bold text-slate-50">{!! trans('lang.categories_management_title') !!} </h3>
                    <p class="text-sm text-slate-200 mt-1 m-0">{!! trans('lang.categories_management_description') !!}</p>
                </div>
                {{-- Przyciski akcji --}}
                <div class="flex items-center gap-4 flex-shrink-0 mt-2 md:mt-0">
                    <a href="{!! route('foods') !!}"
                        class="flex items-center gap-2 px-4 py-2 text-sm bg-white text-slate-600 rounded-md hover:bg-slate-100 hover:text-slate-900 hover:no-underline transition whitespace-nowrap focus:outline-none">
                        <i class="fa fa-rotate-left text-xs"></i>
                        <span>{{ trans('lang.go_back_to_menu') }}</span>
                    </a>
                    <a href="{!! route('category.create') !!}"
                        class="flex items-center gap-2 px-4 py-2 text-sm bg-white text-slate-600 rounded-md hover:bg-slate-100 hover:text-slate-900 hover:no-underline transition whitespace-nowrap focus:outline-none">
                        <i class="fa-solid fa-plus text-xs"></i>
                        <span>{!! trans('lang.create_menu_category') !!}</span>
                    </a>
                </div>
            </div>

            {{-- Pasek wyszukiwania --}}
            <div class="flex flex-col md:flex-row items-start md:items-center gap-4 md:gap-6 mt-6">
                <div class="flex-1 relative w-full md:w-auto">
                    <input x-model.debounce.300ms="searchTerm" type="text"
                        placeholder="{{ trans('lang.category_search_placeholder') }}"
                        class="w-full rounded-md pl-10 pr-4 py-2 text-sm focus:outline-none focus:ring-0 border-0 transition" />
                    <i class="fa fa-search text-lg absolute left-3 top-1/2 -translate-y-1/2 text-slate-700"></i>
                </div>
            </div>
        </div>

        {{-- Tabela z danymi --}}
        <div
            class="bg-white border border-slate-200 rounded-lg shadow-[1px_1px_4px_0px_#e2e8f0] relative">
            <table class="w-full text-sm text-slate-700">
                <thead class="bg-gradient-to-r from-slate-900 via-slate-800 to-slate-900 text-slate-50">
                    <tr>
                        <th class="w-12 rounded-tl-lg"></th>
                        <th
                            class="pl-2 pr-2 py-3 uppercase font-semibold text-left align-middle relative before:absolute before:right-0 before:top-[20%] before:h-[60%] before:border-r before:border-slate-600">
                            {{ trans('lang.category_name') }}
                        </th>
                        <th
                            class="px-2 py-3 uppercase font-semibold text-center align-middle relative before:absolute before:right-0 before:top-[20%] before:h-[60%] before:border-r before:border-slate-600">
                            {{ trans('lang.category_publish') }}
                        </th>
                        <th class="px-2 py-3 uppercase font-semibold text-center align-middle relative rounded-tr-lg">{{
                            trans('lang.actions') }}
                        </th>
                    </tr>
                </thead>
                <tbody class="divide-y divide-slate-200" x-ref="sortableBody">
                    <template x-for="(item, index) in filteredItems" :key="`${item.id}-${item.order}`">
                        <tr :data-id="item.id"
                            class="draggable-row hover:bg-gradient-to-r from-blue-50 via-blue-100 to-blue-50 transition-colors duration-200">
                            {{-- Przycisk do przeciÄ…gania wiersza --}}
                            <td class="px-2 py-3 text-center align-middle"><i
                                    class="fa-solid fa-grip-vertical text-slate-400 cursor-grab drag-handle"></i>
                            </td>
                            {{-- Nazwa kategorii --}}
                            <td class="pl-2 pr-2 py-3 text-left" x-text="item.name"></td>
                            {{-- Status publikacji --}}
                            <td class="px-2 py-3 text-center">
                                <label class="inline-flex items-center cursor-pointer">
                                    <input type="checkbox" class="sr-only peer" @change="togglePublish(item)"
                                        :checked="item.publish">
                                    <div
                                        class="relative h-6 w-11 rounded-full bg-slate-300 peer-checked:bg-blue-500 transition-colors">
                                        <div class="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white transition-transform"
                                            :class="{ 'translate-x-5': item.publish }"></div>
                                    </div>
                                </label>
                            </td>
                            {{-- Akcje --}}
                            <td class="px-2 py-3 text-center">
                                <div class="flex justify-center gap-4">
                                    {{-- Przycisk do edycji kategorii z tooltipem --}}
                                    <div x-data="{ tooltipVisible: false }" class="relative">
                                        <a :href="editUrl(item.id)"
                                            @mouseenter="tooltipVisible = true" @mouseleave="tooltipVisible = false"
                                            class="flex h-10 w-10 items-center justify-center rounded-lg text-slate-400 hover:bg-blue-100 hover:text-blue-500 transition focus:outline-none focus:ring-0 focus:shadow-none hover:no-underline">
                                            <i class="fa fa-pen"></i>
                                        </a>
                                        <div x-show="tooltipVisible"
                                            x-transition:enter="transition ease-out duration-300"
                                            x-transition:enter-start="opacity-0 translate-y-2"
                                            x-transition:enter-end="opacity-100 translate-y-0"
                                            x-transition:leave="transition ease-in duration-200"
                                            x-transition:leave-start="opacity-100 translate-y-0"
                                            x-transition:leave-end="opacity-0 translate-y-2"
                                            class="absolute top-full left-1/2 -translate-x-1/2 mt-2 w-max max-w-xs bg-slate-800 text-white text-center text-xs rounded py-2 px-3 z-10 pointer-events-none"
                                            style="display: none;">
                                            {!! trans('lang.edit') !!}
                                            <div class="absolute left-1/2 -translate-x-1/2 bottom-full w-0 h-0 border-x-8 border-x-transparent border-b-8 border-b-slate-800"></div>
                                        </div>
                                    </div>
                                    {{-- Przycisk do usuwania kategorii z tooltipem --}}
                                    <div x-data="{ tooltipVisible: false }" class="relative">
                                        <button type="button" @click="openDeleteModal(item)"
                                            @mouseenter="tooltipVisible = true" @mouseleave="tooltipVisible = false"
                                            class="flex h-10 w-10 items-center justify-center rounded-lg text-slate-400 hover:bg-red-100 hover:text-red-600 transition focus:outline-none focus:ring-0 focus:shadow-none">
                                            <i class="fa-solid fa-trash"></i>
                                        </button>
                                        <div x-show="tooltipVisible"
                                            x-transition:enter="transition ease-out duration-300"
                                            x-transition:enter-start="opacity-0 translate-y-2"
                                            x-transition:enter-end="opacity-100 translate-y-0"
                                            x-transition:leave="transition ease-in duration-200"
                                            x-transition:leave-start="opacity-100 translate-y-0"
                                            x-transition:leave-end="opacity-0 translate-y-2"
                                            class="absolute top-full left-1/2 -translate-x-1/2 mt-2 w-max max-w-xs bg-slate-800 text-white text-center text-xs rounded py-2 px-3 z-10 pointer-events-none"
                                            style="display: none;">
                                            {!! trans('lang.delete') !!}
                                            <div class="absolute left-1/2 -translate-x-1/2 bottom-full w-0 h-0 border-x-8 border-x-transparent border-b-8 border-b-slate-800"></div>
                                        </div>
                                    </div>
                                </div>
                            </td>
                        </tr>
                    </template>
                    <template x-if="!filteredItems.length && !isLoading">
                        <tr>
                            <td colspan="4" class="text-center py-10 text-slate-500"
                                x-text="searchTerm ? '{{ trans('lang.no_results_found') }}' : '{{ trans('lang.no_items_to_display') }}'">
                            </td>
                        </tr>
                    </template>
                </tbody>
            </table>
        </div>
    </div>

    {{-- Loader, Modal i Powiadomienia --}}
    <div x-show="isLoading" class="fixed inset-0 bg-black bg-opacity-80 z-50 flex items-center justify-center"
        style="display: none;">
        <div class="text-white text-lg flex flex-col items-center gap-2"><i
                class="fa-solid fa-spinner fa-spin text-4xl"></i><span class="text-base">{{ trans('lang.processing')
                }}</span></div>
    </div>
    {{----------- MODAL USUWANIA -------------}}
    <div x-show="showDeleteModal" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0"
        x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-200"
        x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
        class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black bg-opacity-80" style="display: none;"
        x-cloak>
        <div @click.outside="showDeleteModal = false" x-transition:enter="transition ease-out duration-300"
            x-transition:enter-start="opacity-0 scale-95" x-transition:enter-end="opacity-100 scale-100"
            x-transition:leave="transition ease-in duration-200" x-transition:leave-start="opacity-100 scale-100"
            x-transition:leave-end="opacity-0 scale-95"
            class="bg-white rounded-lg text-left overflow-hidden shadow-xl w-full max-w-md flex flex-col">

            <div class="p-6 text-center">
                <div class="mx-auto flex items-center justify-center h-16 w-16 rounded-full bg-red-100">
                    <i class="fa-solid fa-triangle-exclamation text-3xl text-red-600"></i>
                </div>
                <h4 class="text-xl font-semibold text-gray-900 mt-4">{!! trans('lang.confirmation') !!}</h4>
                <p class="mt-2 text-sm text-gray-600">{!! trans('lang.delete_confirmation_desc') !!}</p>
            </div>

            <div class="bg-gray-50 px-4 py-4 border-t border-gray-200 flex flex-col gap-3">
                <button @click="deleteItem()" type="button" class="w-full h-12 flex items-center justify-center bg-red-600 text-white text-base font-semibold rounded-md shadow-md uppercase transition-colors hover:bg-red-700 focus:outline-none focus:ring-0 active:outline-none active:ring-0" style="box-shadow: 1px 1px 2px rgba(0,0,0,0.2);">{!! trans('lang.delete') !!}</button>
                <button @click="showDeleteModal=false" type="button" class="w-full h-12 flex items-center justify-center bg-white text-gray-700 border border-gray-300 text-base font-semibold rounded-md shadow-sm uppercase transition-colors hover:bg-gray-50 focus:outline-none focus:ring-0 active:outline-none active:ring-0">{!! trans('lang.cancel') !!}</button>
            </div>
        </div>
    </div>
    {{----------- POWIADOMIENIA TOAST -------------}}
    <div x-show="notification.show" x-transition
        class="fixed top-5 right-5 z-50 max-w-lg rounded-lg shadow-lg pointer-events-auto"
        :class="{ 'bg-green-100 border-l-4 border-green-500': notification.type === 'success', 'bg-red-100 border-l-4 border-red-500': notification.type === 'error' }"
        style="display: none;">
        <div class="p-4">
            <div class="grid grid-cols-[auto,1fr,auto] items-center gap-x-3">
                {{-- Kolumna 1: Ikona --}}
                <div class="flex-shrink-0">
                    <i x-show="notification.type === 'success'" class="fa-solid fa-check-circle text-green-500 text-xl"
                        style="display: none;"></i>
                    <i x-show="notification.type === 'error'" class="fa-solid fa-times-circle text-red-500 text-xl"
                        style="display: none;"></i>
                </div>
                {{-- Kolumna 2: Tekst (elastyczny) --}}
                <div>
                    <p class="text-sm font-medium break-words"
                        :class="{ 'text-green-800': notification.type === 'success', 'text-red-800': notification.type === 'error' }"
                        x-text="notification.message"></p>
                </div>
                {{-- Kolumna 3: Przycisk zamkniÄ™cia --}}
                <div class="flex-shrink-0">
                    <button @click="notification.show = false"
                        class="inline-flex text-slate-500 hover:text-slate-600 focus:outline-none">
                        <span class="sr-only">{{ trans('lang.close') }}</span>
                        <i class="fa-solid fa-times"></i>
                    </button>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

@section('scripts')

<script>
    window.appTranslations = {
        load_error:             "{!! trans('lang.load_error') !!}",
        order_saved_success:    "{!! trans('lang.order_saved_success') !!}",
        order_saved_error:      "{!! trans('lang.order_saved_error') !!}",
        status_updated_success: "{!! trans('lang.status_updated_success') !!}",
        status_updated_error:   "{!! trans('lang.status_updated_error') !!}",
        item_deleted_success:   "{!! trans('lang.item_deleted_success') !!}",
        item_deleted_error:     "{!! trans('lang.item_deleted_error') !!}",
    };

    const serverData = {
        items: @json($categoriesJson),
        csrfToken: '{{ csrf_token() }}',
        editRoute: '{{ route("category.edit", ":id") }}',
        apiBase:   '{{ url("/api/categories") }}',
        apiOrder:  '{{ route("api.categories.order") }}',
    };
</script>

<script>
    function categoriesPage() {
        return {
            // --- STATE ---
            isLoading: false,
            items: serverData.items,
            showDeleteModal: false,
            itemToDelete: null,
            notification: { show: false, type: 'success', message: '' },
            searchTerm: '',
            sortableInstance: null,
            saveTimeout: null,
            reinitTimeout: null,

            // --- INIT ---
            initCategories() {
                this.$nextTick(() => this.initSortable());

                this.$watch('searchTerm', () => {
                    this.$nextTick(() => {
                        if (this.sortableInstance && this.$refs.sortableBody) {
                            clearTimeout(this.reinitTimeout);
                            this.reinitTimeout = setTimeout(() => this.initSortable(), 100);
                        }
                    });
                });
            },

            initSortable() {
                if (!this.$refs.sortableBody) return;
                if (this.sortableInstance) this.sortableInstance.destroy();

                this.sortableInstance = new Sortable(this.$refs.sortableBody, {
                    handle: '.drag-handle',
                    animation: 200,
                    draggable: '.draggable-row',
                    ghostClass: 'sortable-ghost',
                    dragClass: 'sortable-drag',
                    forceFallback: true,
                    fallbackOnBody: true,
                    swapThreshold: 0.65,
                    invertSwap: true,
                    onStart: () => document.body.classList.add('dragging'),
                    onEnd: (evt) => {
                        document.body.classList.remove('dragging');
                        if (evt.oldIndex !== evt.newIndex) {
                            const reorderedIds = Array.from(evt.target.children)
                                .filter(row => row.classList.contains('draggable-row'))
                                .map(row => parseInt(row.dataset.id, 10));
                            clearTimeout(this.saveTimeout);
                            this.saveTimeout = setTimeout(() => this.saveNewOrder(reorderedIds), 100);
                        }
                    }
                });
            },

            // --- API METHODS ---
            async saveNewOrder(reorderedIds) {
                this.isLoading = true;
                try {
                    const res = await fetch(serverData.apiOrder, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRF-TOKEN': serverData.csrfToken,
                            'Accept': 'application/json',
                        },
                        body: JSON.stringify({ categoryIds: reorderedIds }),
                    });
                    if (!res.ok) throw new Error('Server error');

                    // Update local order â€” no re-fetch needed
                    reorderedIds.forEach((id, index) => {
                        const item = this.items.find(i => i.id === id);
                        if (item) item.order = index;
                    });
                    this.items = [...this.items].sort((a, b) => a.order - b.order);
                    this.$nextTick(() => this.initSortable());
                    this.showNotification(window.appTranslations.order_saved_success, 'success');
                } catch (error) {
                    this.showNotification(window.appTranslations.order_saved_error, 'error');
                } finally {
                    this.isLoading = false;
                }
            },

            async togglePublish(item) {
                this.isLoading = true;
                const originalStatus = item.publish;
                item.publish = !originalStatus;
                try {
                    const res = await fetch(`${serverData.apiBase}/${item.id}/publish`, {
                        method: 'PATCH',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRF-TOKEN': serverData.csrfToken,
                            'Accept': 'application/json',
                        },
                        body: JSON.stringify({ publish: item.publish }),
                    });
                    if (!res.ok) throw new Error('Server error');
                    this.showNotification(window.appTranslations.status_updated_success, 'success');
                } catch (error) {
                    item.publish = originalStatus;
                    this.showNotification(window.appTranslations.status_updated_error, 'error');
                } finally {
                    this.isLoading = false;
                }
            },

            async deleteItem() {
                if (!this.itemToDelete) return;
                this.isLoading = true;
                this.showDeleteModal = false;
                const idToDelete = this.itemToDelete.id;
                try {
                    const res = await fetch(`${serverData.apiBase}/${idToDelete}`, {
                        method: 'DELETE',
                        headers: {
                            'X-CSRF-TOKEN': serverData.csrfToken,
                            'Accept': 'application/json',
                        },
                    });
                    if (!res.ok) throw new Error('Server error');
                    this.items = this.items.filter(i => i.id !== idToDelete);
                    this.showNotification(window.appTranslations.item_deleted_success, 'success');
                } catch (error) {
                    this.showNotification(window.appTranslations.item_deleted_error, 'error');
                } finally {
                    this.isLoading = false;
                    this.itemToDelete = null;
                }
            },

            // --- HELPERS ---
            showNotification(message, type = 'success', duration = 4000) {
                this.notification.message = message;
                this.notification.type = type;
                this.notification.show = true;
                setTimeout(() => { this.notification.show = false; }, duration);
            },

            editUrl(id) { return serverData.editRoute.replace(':id', id); },

            openDeleteModal(item) { this.itemToDelete = item; this.showDeleteModal = true; },

            destroy() {
                if (this.sortableInstance) { this.sortableInstance.destroy(); this.sortableInstance = null; }
                if (this.saveTimeout) { clearTimeout(this.saveTimeout); this.saveTimeout = null; }
                if (this.reinitTimeout) { clearTimeout(this.reinitTimeout); this.reinitTimeout = null; }
                document.body.classList.remove('dragging');
            },

            get filteredItems() {
                let arr = [...this.items];
                if (this.searchTerm.trim()) {
                    const st = this.searchTerm.toLowerCase();
                    arr = arr.filter(item => item.name.toLowerCase().includes(st));
                }
                return arr;
            },
        };
    }
</script>
@endsection
