document.addEventListener('DOMContentLoaded', function() {

    let jsBaseUrl = '';
    if (typeof BASE_URL !== 'undefined' && BASE_URL) { jsBaseUrl = BASE_URL; }
    else { console.error("Admin JS FATAL ERROR: BASE_URL JS variable is not defined!"); return; }

    function escapeHTML(str) { if (typeof str !== 'string') return str; const map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' }; return str.replace(/[&<>"']/g, function(m) { return map[m]; }); }
    function displayFieldError(fieldId, message) { const errorSpan = document.getElementById(fieldId + '-error'); const inputField = document.getElementById(fieldId); if (errorSpan) { errorSpan.textContent = message || ''; } if (inputField) { const choicesParent = inputField.closest('.choices'); const targetElement = choicesParent || inputField; if (message) { targetElement.classList.add('border-red-500'); targetElement.classList.remove('border-gray-300'); if (choicesParent) { const innerElement = choicesParent.querySelector('.choices__inner'); if (innerElement) { innerElement.classList.add('border-red-500'); innerElement.classList.remove('border-gray-300'); } } } else { targetElement.classList.remove('border-red-500'); targetElement.classList.add('border-gray-300'); if (choicesParent) { const innerElement = choicesParent.querySelector('.choices__inner'); if (innerElement) { innerElement.classList.remove('border-red-500'); innerElement.classList.add('border-gray-300'); } } } } }
    function clearFieldErrors(formElement) { if(!formElement) return; formElement.querySelectorAll('.input-field').forEach(input => { displayFieldError(input.id, ''); }); formElement.querySelectorAll('.choices').forEach(choicesElement => { const innerElement = choicesElement.querySelector('.choices__inner'); if (innerElement) { innerElement.classList.remove('border-red-500'); innerElement.classList.add('border-gray-300'); } const selectId = choicesElement.querySelector('select')?.id; if (selectId) { const errorSpan = document.getElementById(selectId + '-error'); if (errorSpan) errorSpan.textContent = ''; } }); }
    function displayGeneralMessage(containerId, message, type = 'error', autoDismiss = 0) { const messageDiv = document.getElementById(containerId); if (messageDiv) { messageDiv.innerHTML = ''; if (message) { const alertClass = type === 'success' ? 'bg-green-100 border-green-300 text-green-700' : 'bg-red-100 border-red-300 text-red-700'; messageDiv.className = 'mb-4 p-4 border rounded-lg text-sm ' + alertClass + ' transition-all duration-300 ease-in-out opacity-100 scale-100 flex items-center shadow-md'; const iconClass = type === 'success' ? 'fas fa-check-circle' : 'fas fa-exclamation-triangle'; messageDiv.innerHTML = `<i class="${iconClass} mr-3 text-lg"></i> <span>${escapeHTML(message)}</span>`; if (autoDismiss > 0) { setTimeout(() => { messageDiv.style.opacity = '0'; messageDiv.style.transform = 'scale(0.9)'; setTimeout(() => { messageDiv.innerHTML = ''; messageDiv.className = 'mb-4 text-sm'; messageDiv.style.opacity = '1'; messageDiv.style.transform = 'scale(1)'; }, 300); }, autoDismiss); } } else { messageDiv.className = 'mb-4 text-sm'; } } }
    function setButtonLoading(buttonId, textId, spinnerHTMLId, isLoading, loadingText = 'Memproses...') { const button = document.getElementById(buttonId); const textSpan = document.getElementById(textId); const spinner = document.getElementById(spinnerHTMLId); if (button && textSpan && spinner) { const originalText = button.dataset.originalText || textSpan.textContent; if (!button.dataset.originalText) button.dataset.originalText = originalText; if (isLoading) { button.disabled = true; button.classList.add('opacity-75', 'cursor-not-allowed'); textSpan.textContent = loadingText; spinner.classList.remove('hidden'); } else { button.disabled = false; button.classList.remove('opacity-75', 'cursor-not-allowed'); textSpan.textContent = originalText; spinner.classList.add('hidden'); } } }
    function setupPasswordToggle(inputId, buttonId) { const passwordInput = document.getElementById(inputId); const toggleButton = document.getElementById(buttonId); if (passwordInput && toggleButton) { const toggleIcon = toggleButton.querySelector('i'); if(toggleIcon){ toggleButton.addEventListener('click', function () { const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password'; passwordInput.setAttribute('type', type); toggleIcon.classList.toggle('fa-eye', type === 'password'); toggleIcon.classList.toggle('fa-eye-slash', type === 'text'); }); } } }
    function formatLocalDate(dateString) { if (!dateString) return 'N/A'; try { const date = new Date(dateString); if (isNaN(date.getTime())) { return dateString; } const options = { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }; let formatted = date.toLocaleDateString('id-ID', options); formatted = formatted.replace(/\./g, ':'); formatted = formatted.replace(',', ''); return formatted; } catch (e) { console.error("formatLocalDate Error:", e, "Input:", dateString); return dateString; } }
    function getStatusBadgeClass(status) { status = status ? status.toLowerCase() : ''; switch (status) { case 'success': return 'bg-green-100 text-green-800 border border-green-200'; case 'processing': case 'in progress': return 'bg-blue-100 text-blue-800 border border-blue-200'; case 'pending': return 'bg-yellow-100 text-yellow-800 border border-yellow-200'; case 'partial': return 'bg-orange-100 text-orange-800 border border-orange-200'; case 'error': case 'canceled': return 'bg-red-100 text-red-800 border border-red-200'; default: return 'bg-gray-100 text-gray-800 border border-gray-200'; } }
    function getTicketStatusBadgeClass(status) { status = status ? status.toLowerCase() : ''; switch (status) { case 'open': return 'bg-blue-100 text-blue-800'; case 'answered': return 'bg-green-100 text-green-800'; case 'user_reply': return 'bg-yellow-100 text-yellow-800'; case 'closed': return 'bg-gray-100 text-gray-800'; default: return 'bg-gray-100 text-gray-800'; } }
    function openModal(modalElement, modalContentElement) { if (!modalElement || !modalContentElement) return; modalElement.classList.remove('hidden'); modalElement.classList.add('flex'); setTimeout(() => { modalElement.classList.add('opacity-100'); modalContentElement.classList.remove('scale-95', 'opacity-0'); }, 10); }
    function closeModal(modalElement, modalContentElement) { if (!modalElement || !modalContentElement) return; modalContentElement.classList.add('scale-95', 'opacity-0'); modalElement.classList.remove('opacity-100'); setTimeout(() => { modalElement.classList.add('hidden'); modalElement.classList.remove('flex'); }, 300); }

    const profileButton = document.getElementById('profile-button');
    const profileDropdown = document.getElementById('profile-dropdown');
    const hamburgerButton = document.getElementById('hamburger-button');
    const sidebar = document.getElementById('sidebar');
    const sidebarOverlay = document.getElementById('sidebar-overlay');
    const sidebarCloseButton = document.getElementById('sidebar-close-button');
    const mainContent = document.getElementById('main-content'); 

    function closeSidebar() {
        if (sidebar && sidebar.classList.contains('open')) {
            sidebar.classList.remove('open');
            if (sidebarOverlay) {
                sidebarOverlay.classList.remove('opacity-50'); 
                sidebarOverlay.classList.remove('pointer-events-auto');
            }
            if (window.innerWidth < 1024) {
                document.body.classList.remove('overflow-hidden');
            }
        }
    }

    // Fungsi untuk membuka sidebar
    function openSidebar() {
        if (sidebar && !sidebar.classList.contains('open')) {
            sidebar.classList.add('open');
            if (sidebarOverlay) {
                sidebarOverlay.classList.add('opacity-50');
                sidebarOverlay.classList.add('pointer-events-auto');
            }
            if (window.innerWidth < 1024) { // Sesuaikan breakpoint
                document.body.classList.add('overflow-hidden');
            }
        }
    }

    if (hamburgerButton && sidebar && sidebarOverlay) {
        hamburgerButton.addEventListener('click', function(e) {
            e.stopPropagation(); // Mencegah event bubbling
            if (sidebar.classList.contains('open')) {
                closeSidebar();
            } else {
                openSidebar();
            }
        });
    }

    if (sidebarCloseButton) {
        sidebarCloseButton.addEventListener('click', function(e) {
            e.stopPropagation();
            closeSidebar();
        });
    }

    if (sidebarOverlay) {
        sidebarOverlay.addEventListener('click', function() {
            closeSidebar();
        });
    }

    if (sidebar && hamburgerButton) {
        document.addEventListener('click', function(event) {
            if (sidebar.classList.contains('open')) {
                const isClickInsideSidebar = sidebar.contains(event.target);
                const isClickOnHamburger = hamburgerButton.contains(event.target);

                if (!isClickInsideSidebar && !isClickOnHamburger) {
                    if (window.innerWidth < 1024) {
                         closeSidebar();
                    }
                }
            }
        });
    }

    const allSidebarLinks = document.querySelectorAll('#sidebar a'); 
    allSidebarLinks.forEach(link => {
        link.addEventListener('click', function() {
            if (window.innerWidth < 1024 && sidebar && sidebar.classList.contains('open')) {
                closeSidebar();
            }
        });
    });

    const submenuToggles = [
        { buttonId: 'pesanan-menu-toggle', submenuId: 'pesanan-submenu' },
        { buttonId: 'deposit-menu-toggle', submenuId: 'deposit-submenu' },
        { buttonId: 'layanan-menu-toggle', submenuId: 'layanan-submenu' },
        { buttonId: 'tiket-menu-toggle', submenuId: 'tiket-submenu' },
        { buttonId: 'sitemap-menu-toggle', submenuId: 'sitemap-submenu' },
        { buttonId: 'admin-manage-menu-toggle', submenuId: 'admin-manage-submenu' }
    ];

    submenuToggles.forEach(item => {
        const toggleButton = document.getElementById(item.buttonId);
        const submenu = document.getElementById(item.submenuId);

        if (toggleButton && submenu) {
            const arrow = toggleButton.querySelector('.submenu-arrow');
            toggleButton.addEventListener('click', (e) => {
                e.preventDefault(); 
                const isCurrentlyOpen = submenu.classList.contains('open');

                submenu.classList.toggle('open');
                if (arrow) arrow.classList.toggle('rotate-180', !isCurrentlyOpen);
                toggleButton.classList.toggle('active', !isCurrentlyOpen);
            });
        }
    });

    if (profileButton && profileDropdown) {
        profileButton.addEventListener('click', (e) => {
            e.stopPropagation();
            profileDropdown.classList.toggle('open');
        });
        document.addEventListener('click', (event) => {
            if (profileDropdown.classList.contains('open') &&
                !profileButton.contains(event.target) &&
                !profileDropdown.contains(event.target)) {
                profileDropdown.classList.remove('open');
            }
        });
    }

    const carousel = document.getElementById('dashboard-carousel'); if (carousel) { const carouselWrapper = document.getElementById('carousel-wrapper'); const carouselSlides = carouselWrapper ? carouselWrapper.querySelectorAll('.carousel-slide') : []; const prevButton = document.getElementById('carousel-prev'); const nextButton = document.getElementById('carousel-next'); const indicatorsContainer = document.getElementById('carousel-indicators'); let currentSlide = 0; let slideInterval; const autoplayDelay = 5000; if (carouselWrapper && carouselSlides.length > 0 && prevButton && nextButton && indicatorsContainer) { indicatorsContainer.innerHTML = ''; carouselSlides.forEach((_, index) => { const indicator = document.createElement('button'); indicator.classList.add('carousel-indicator'); indicator.setAttribute('aria-label', `Go to slide ${index + 1}`); indicator.addEventListener('click', () => { goToSlide(index); resetAutoplay(); }); indicatorsContainer.appendChild(indicator); }); const indicators = indicatorsContainer.querySelectorAll('.carousel-indicator'); function goToSlide(index) { const newSlideIndex = (index + carouselSlides.length) % carouselSlides.length; currentSlide = newSlideIndex; const firstSlide = carouselSlides[0]; const slideStyle = window.getComputedStyle(firstSlide); const slideMarginLeft = parseFloat(slideStyle.marginLeft); const slideMarginRight = parseFloat(slideStyle.marginRight); const slideMargin = slideMarginLeft + slideMarginRight; const slideWidth = firstSlide.offsetWidth; const containerWidth = carousel.offsetWidth; const centerPointContainer = containerWidth / 2; const centerPointActiveSlide = (currentSlide * (slideWidth + slideMargin)) + (slideWidth / 2); const totalOffset = centerPointContainer - centerPointActiveSlide; carouselWrapper.style.transform = `translateX(${totalOffset}px)`; indicators.forEach((indicator, i) => { indicator.classList.toggle('active', i === currentSlide); }); carouselSlides.forEach((slide, i) => { slide.classList.toggle('active-slide', i === currentSlide); }); } function nextSlide() { goToSlide(currentSlide + 1); } function prevSlide() { goToSlide(currentSlide - 1); } function startAutoplay() { clearInterval(slideInterval); slideInterval = setInterval(nextSlide, autoplayDelay); } function stopAutoplay() { clearInterval(slideInterval); } function resetAutoplay() { stopAutoplay(); startAutoplay(); } prevButton.addEventListener('click', () => { prevSlide(); resetAutoplay(); }); nextButton.addEventListener('click', () => { nextSlide(); resetAutoplay(); }); carousel.addEventListener('mouseenter', stopAutoplay); carousel.addEventListener('mouseleave', startAutoplay); function initializeCarousel() { if (carouselSlides.length > 0 && carousel.offsetWidth > 0 && carouselSlides[0].offsetWidth > 0) { goToSlide(0); startAutoplay(); } else { setTimeout(initializeCarousel, 150); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeCarousel); } else { setTimeout(initializeCarousel, 50); } let resizeTimeout; window.addEventListener('resize', () => { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(() => { if (carouselSlides.length > 0) { carouselWrapper.style.transition = 'none'; goToSlide(currentSlide); setTimeout(() => { carouselWrapper.style.transition = 'transform 0.5s ease-in-out'; }, 50); } }, 250); }); } }

    const orderPageContainer = document.getElementById('order-form');
    if (orderPageContainer && jsBaseUrl) {
        const categoryFilterButtonsContainer = document.getElementById('category-filter-buttons'); const categorySelectElement = document.getElementById('category'); const serviceSelectElement = document.getElementById('service'); const serviceDetailsContainer = document.getElementById('service-details-container'); const serviceNotesDiv = document.getElementById('service-notes'); const targetInput = document.getElementById('target'); const quantityInput = document.getElementById('quantity'); const minMaxInfoDiv = document.getElementById('min-max-info'); const pricePer1000Span = document.getElementById('price-per-1000'); const totalPriceDiv = document.getElementById('total-price'); const orderForm = document.getElementById('order-form'); const orderButton = document.getElementById('order-button'); const orderMessageDiv = document.getElementById('order-message'); let currentServiceDetails = null; let allCategoriesData = []; let mainCategories = {}; let categoryChoicesInstance = null; let serviceChoicesInstance = null; if (categorySelectElement) { categoryChoicesInstance = new Choices(categorySelectElement, { searchEnabled: true, itemSelectText: 'Pilih', noResultsText: 'Tidak ada hasil', noChoicesText: 'Tidak ada pilihan', placeholderValue: '-- Pilih Kategori --', removeItemButton: false, shouldSort: false, searchPlaceholderValue: "Cari kategori..." }); } if (serviceSelectElement) { serviceChoicesInstance = new Choices(serviceSelectElement, { searchEnabled: true, itemSelectText: 'Pilih', noResultsText: 'Tidak ada hasil', noChoicesText: 'Pilih kategori dahulu', placeholderValue: '-- Pilih Layanan --', removeItemButton: false, shouldSort: false, searchPlaceholderValue: "Cari layanan..." }); serviceChoicesInstance.disable(); } function getMainPlatform(categoryName) { if (!categoryName) return 'Lainnya'; const nameLower = categoryName.toLowerCase(); if (nameLower.includes('instagram')) return 'Instagram'; if (nameLower.includes('facebook')) return 'Facebook'; if (nameLower.includes('tiktok')) return 'TikTok'; if (nameLower.includes('youtube')) return 'YouTube'; if (nameLower.includes('telegram')) return 'Telegram'; if (nameLower.includes('shopee')) return 'Shopee'; if (nameLower.includes('spotify')) return 'Spotify'; if (nameLower.includes('twitter')) return 'Twitter'; return 'Lainnya'; } function loadAndProcessCategories(filterPlatform = 'all') { const loadingSpan = document.getElementById('category-filter-loading'); if (loadingSpan) loadingSpan.classList.remove('hidden'); if (categoryChoicesInstance) { categoryChoicesInstance.clearStore(); categoryChoicesInstance.setChoices([{ value: '', label: '-- Memuat Kategori --', disabled: true, selected: true }], 'value', 'label', true); categoryChoicesInstance.disable(); } if (allCategoriesData.length === 0) { const url = jsBaseUrl + '/ajax/get_categories'; fetch(url) .then(response => { if (!response.ok) throw new Error(`HTTP error ${response.status}`); return response.json(); }) .then(data => { if (data.success && Array.isArray(data.categories)) { allCategoriesData = data.categories; mainCategories = {}; allCategoriesData.forEach(cat => { if (cat && typeof cat === 'object' && cat.id !== null && typeof cat.name === 'string' && cat.name.trim() !== '') { const platform = getMainPlatform(cat.name); if (!mainCategories[platform]) { mainCategories[platform] = []; } mainCategories[platform].push(cat); } }); populatePlatformFilterButtons(); populateCategorySelect(filterPlatform); } else { if (categoryChoicesInstance) categoryChoicesInstance.setChoices([{ value: '', label: 'Gagal memuat data', disabled: true, selected: true }], 'value', 'label', true); } }) .catch(error => { if (categoryChoicesInstance) categoryChoicesInstance.setChoices([{ value: '', label: 'Error koneksi', disabled: true, selected: true }], 'value', 'label', true); }) .finally(() => { if (loadingSpan) loadingSpan.classList.add('hidden'); }); } else { populateCategorySelect(filterPlatform); updateActiveFilterButton(filterPlatform); if (loadingSpan) loadingSpan.classList.add('hidden'); } } function populatePlatformFilterButtons() { if (!categoryFilterButtonsContainer || Object.keys(mainCategories).length === 0) { return; } categoryFilterButtonsContainer.querySelectorAll('.category-filter-btn:not([data-category-id="all"])').forEach(btn => btn.remove()); const platforms = Object.keys(mainCategories).sort(); platforms.forEach(platform => { const button = document.createElement('button'); const filterId = platform.toLowerCase(); button.dataset.categoryId = filterId; button.type = 'button'; button.classList.add('category-filter-btn', 'px-4', 'py-1.5', 'text-sm', 'font-medium', 'bg-gray-200', 'text-gray-700', 'rounded-full', 'hover:bg-gray-300', 'transition'); let iconClass = 'fas fa-star'; if (platform === 'Instagram') iconClass = 'fab fa-instagram'; else if (platform === 'Facebook') iconClass = 'fab fa-facebook'; else if (platform === 'TikTok') iconClass = 'fab fa-tiktok'; else if (platform === 'YouTube') iconClass = 'fab fa-youtube'; else if (platform === 'Telegram') iconClass = 'fab fa-telegram-plane'; else if (platform === 'Shopee') iconClass = 'fas fa-shopping-bag'; const icon = document.createElement('i'); icon.className = `${escapeHTML(iconClass)} mr-1.5`; button.appendChild(icon); button.appendChild(document.createTextNode(escapeHTML(platform))); categoryFilterButtonsContainer.appendChild(button); }); } function populateCategorySelect(filterPlatform = 'all') { if (!categoryChoicesInstance) { return; } let choices = []; let categoryCount = 0; let firstCategoryId = null; if (!Array.isArray(allCategoriesData)) { choices = [{ value: '', label: 'Error data', disabled: true }]; } else { const sortedAllCategories = [...allCategoriesData].sort((a, b) => (a?.name ?? '').localeCompare(b?.name ?? '')); sortedAllCategories.forEach((cat, index) => { if (cat && typeof cat === 'object' && typeof cat.id !== 'undefined' && cat.id !== null && typeof cat.name === 'string' && cat.name.trim() !== '') { const platformOfThisCat = getMainPlatform(cat.name).toLowerCase(); if (filterPlatform === 'all' || filterPlatform === platformOfThisCat) { choices.push({ value: cat.id.toString(), label: escapeHTML(cat.name), selected: false, disabled: false }); categoryCount++; if (categoryCount === 1) { firstCategoryId = cat.id.toString(); } } } }); } choices.unshift({ value: '', label: '-- Pilih Kategori --', selected: true, disabled: true }); categoryChoicesInstance.clearStore(); categoryChoicesInstance.setChoices(choices, 'value', 'label', true); if (categoryCount === 0) { categoryChoicesInstance.setChoices([{ value: '', label: '-- Tidak ada kategori --', selected: true, disabled: true }], 'value', 'label', true); categoryChoicesInstance.disable(); resetServiceSelection(); } else { categoryChoicesInstance.enable(); resetServiceSelection(); } } function loadServices(categoryId) { resetServiceSelection(); if (!categoryId || !serviceChoicesInstance) { return; } serviceChoicesInstance.clearStore(); serviceChoicesInstance.setChoices([{ value: '', label: '-- Memuat Layanan --', disabled: true, selected: true }], 'value', 'label', true); serviceChoicesInstance.disable(); const url = jsBaseUrl + `/ajax/get_services_by_category?category_id=${categoryId}`; fetch(url) .then(response => { if (!response.ok) throw new Error(`HTTP error ${response.status}`); return response.json(); }) .then(data => { let serviceChoices = []; if (data && data.success && Array.isArray(data.services) && data.services.length > 0) { data.services.forEach(service => { if (service && typeof service.id !== 'undefined' && typeof service.name !== 'undefined') { serviceChoices.push({ value: service.id.toString(), label: escapeHTML(service.name), selected: false, disabled: false }); } }); } if (serviceChoices.length > 0) { serviceChoices.unshift({ value: '', label: '-- Pilih Layanan --', selected: true, disabled: true }); serviceChoicesInstance.setChoices(serviceChoices, 'value', 'label', true); serviceChoicesInstance.enable(); } else { serviceChoicesInstance.setChoices([{ value: '', label: '-- Tidak ada layanan --', selected: true, disabled: true }], 'value', 'label', true); serviceChoicesInstance.disable(); } }) .catch(error => { serviceChoicesInstance.setChoices([{ value: '', label: '-- Error Koneksi --', selected: true, disabled: true }], 'value', 'label', true); serviceChoicesInstance.disable(); console.error('Fetch Error (Services):', error); }); } function loadServiceDetails(serviceId) { resetServiceDetails(); if (!serviceId || !serviceDetailsContainer || !serviceNotesDiv || !minMaxInfoDiv || !pricePer1000Span || !quantityInput || !orderButton) { return; } serviceNotesDiv.textContent = 'Memuat detail...'; serviceDetailsContainer.classList.remove('hidden'); const url = jsBaseUrl + `/ajax/get_service_details?service_id=${serviceId}`; fetch(url) .then(response => { if (!response.ok) throw new Error(`HTTP error ${response.status}`); return response.json(); }) .then(data => { if (data.success && data.details) { currentServiceDetails = data.details; serviceNotesDiv.innerHTML = data.details.note ? escapeHTML(data.details.note).replace(/\n/g, '<br>') : '<i>Tidak ada catatan khusus.</i>'; minMaxInfoDiv.innerHTML = `Min: <span class="font-medium">${escapeHTML(data.details.min_order ?? 'N/A')}</span> / Max: <span class="font-medium">${escapeHTML(data.details.max_order ?? 'N/A')}</span>`; pricePer1000Span.textContent = escapeHTML(data.details.price_formatted) || 'Rp 0'; quantityInput.disabled = false; quantityInput.min = data.details.min_order ?? 0; quantityInput.max = data.details.max_order ?? ''; quantityInput.placeholder = `Jumlah (min ${escapeHTML(data.details.min_order ?? '?')})`; quantityInput.classList.remove('bg-gray-100'); orderButton.disabled = false; calculateTotalPrice(); } else { serviceNotesDiv.textContent = 'Gagal memuat detail.'; resetServiceSelection(); } }) .catch(error => { serviceNotesDiv.textContent = 'Error koneksi saat memuat detail.'; resetServiceSelection(); }); } function calculateTotalPrice() { if (!quantityInput || !totalPriceDiv || !currentServiceDetails) { if(totalPriceDiv) totalPriceDiv.textContent = 'Rp 0'; return; } const quantity = parseInt(quantityInput.value) || 0; const pricePer1000 = parseFloat(currentServiceDetails.price_per_1000) || 0; let totalPrice = 0; if (quantity > 0 && pricePer1000 > 0) { totalPrice = (quantity / 1000) * pricePer1000; } totalPriceDiv.textContent = 'Rp ' + totalPrice.toLocaleString('id-ID', { minimumFractionDigits: 0, maximumFractionDigits: 2 }); } function resetServiceSelection() { if (serviceChoicesInstance) { serviceChoicesInstance.clearStore(); serviceChoicesInstance.setChoices([{ value: '', label: '-- Pilih Kategori Dahulu --', selected: true, disabled: true }], 'value', 'label', true); serviceChoicesInstance.disable(); } resetServiceDetails(); } function resetServiceDetails() { currentServiceDetails = null; if (serviceDetailsContainer) serviceDetailsContainer.classList.add('hidden'); if (serviceNotesDiv) serviceNotesDiv.textContent = 'Pilih layanan untuk melihat catatan.'; if (minMaxInfoDiv) minMaxInfoDiv.textContent = ''; if (pricePer1000Span) pricePer1000Span.textContent = 'Rp 0'; if (quantityInput) { quantityInput.value = ''; quantityInput.disabled = true; quantityInput.placeholder = 'Jumlah'; quantityInput.classList.add('bg-gray-100'); displayFieldError('quantity', ''); } if (totalPriceDiv) totalPriceDiv.textContent = 'Rp 0'; if (orderButton) orderButton.disabled = true; displayFieldError('service', ''); } function updateActiveFilterButton(activeId) { if (!categoryFilterButtonsContainer) return; categoryFilterButtonsContainer.querySelectorAll('.category-filter-btn').forEach(btn => { const isActive = btn.dataset.categoryId == activeId; btn.classList.toggle('bg-blue-600', isActive); btn.classList.toggle('text-white', isActive); btn.classList.toggle('bg-gray-200', !isActive); btn.classList.toggle('text-gray-700', !isActive); btn.classList.toggle('hover:bg-gray-300', !isActive); }); } function handlePlatformFilterClick(event) { const button = event.target.closest('.category-filter-btn'); if (!button) return; const platformFilterId = button.dataset.categoryId; if (typeof platformFilterId !== 'undefined' && platformFilterId !== null) { updateActiveFilterButton(platformFilterId); populateCategorySelect(platformFilterId); resetServiceSelection(); } else { console.error("Clicked filter button missing valid data-category-id!", button); } } function displaySuccessOrderAlert(containerId, details) { const messageDiv = document.getElementById(containerId); if (!messageDiv || !details) return; messageDiv.innerHTML = ''; messageDiv.className = 'mb-4 p-4 border rounded-lg text-sm bg-emerald-900 border-emerald-700 text-gray-100 shadow-lg transition-all duration-300 ease-in-out opacity-100 scale-100'; const appName = typeof APP_NAME !== 'undefined' ? APP_NAME : 'Layanan Kami'; const content = ` <div class="flex items-start"> <div class="flex-shrink-0 pt-0.5"><i class="fas fa-check-circle text-emerald-400 text-xl"></i></div> <div class="ml-3 flex-1"> <h3 class="text-base font-semibold text-white">Pesanan Diterima !</h3> <div class="mt-2 text-xs text-gray-300 space-y-1.5"> <p>Terima kasih sudah menggunakan ${escapeHTML(appName)} - Pusat Panel SMM Indonesia Termurah.</p> <p>Pesanan Anda telah kami terima dan akan segera diproses.</p> <div class="pt-2 space-y-1"> <p><strong class="font-medium text-gray-100">ID Pesanan:</strong> #${escapeHTML(details.orderId)}</p> <p><strong class="font-medium text-gray-100">Layanan:</strong> ${escapeHTML(details.service)}</p> <p><strong class="font-medium text-gray-100">Target:</strong> <span class="break-all font-mono bg-emerald-800 px-1 py-0.5 rounded text-emerald-100">${escapeHTML(details.target)}</span></p> <p><strong class="font-medium text-gray-100">Jumlah:</strong> ${escapeHTML(details.quantity?.toLocaleString('id-ID') ?? 'N/A')}</p> <p><strong class="font-medium text-gray-100">Harga:</strong> <span class="font-semibold text-emerald-300">${escapeHTML(details.priceFormatted ?? 'N/A')}</span></p> </div> </div> </div> <div class="ml-4 flex-shrink-0"> <button type="button" class="close-alert-btn inline-flex bg-emerald-900 rounded-md p-1.5 text-emerald-300 hover:bg-emerald-800 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-emerald-900 focus:ring-emerald-600"> <span class="sr-only">Tutup</span> <i class="fas fa-times h-4 w-4"></i> </button> </div> </div> `; messageDiv.innerHTML = content; const closeButton = messageDiv.querySelector('.close-alert-btn'); if (closeButton) { closeButton.addEventListener('click', () => { messageDiv.style.opacity = '0'; messageDiv.style.transform = 'scale(0.9)'; setTimeout(() => { messageDiv.innerHTML = ''; messageDiv.className = 'mb-4 text-sm'; messageDiv.style.opacity = '1'; messageDiv.style.transform = 'scale(1)'; }, 300); }); } }
        if (categoryFilterButtonsContainer || categorySelectElement) { loadAndProcessCategories('all'); } if (categoryFilterButtonsContainer) { categoryFilterButtonsContainer.addEventListener('click', handlePlatformFilterClick); } if (categorySelectElement) { categorySelectElement.addEventListener('change', function(event) { loadServices(event.detail.value); }); } if (serviceSelectElement) { serviceSelectElement.addEventListener('change', function(event) { loadServiceDetails(event.detail.value); }); } if (quantityInput) { quantityInput.addEventListener('input', calculateTotalPrice); } if (orderForm && orderButton) { const orderButtonTextEl = document.getElementById('order-button-text'); if(orderButtonTextEl) orderButton.dataset.originalText = orderButtonTextEl.textContent; orderForm.addEventListener('submit', function(event) { event.preventDefault(); clearFieldErrors(orderForm); displayGeneralMessage('order-message', ''); let isValid = true; const formData = new FormData(orderForm); const serviceId = formData.get('service'); const target = formData.get('target')?.trim() ?? ''; const quantity = parseInt(formData.get('quantity')) || 0; if (!serviceId) { isValid = false; displayFieldError('service', 'Layanan wajib dipilih.'); } if (!target) { isValid = false; displayFieldError('target', 'Target wajib diisi.'); } if (!quantity || quantity <= 0) { isValid = false; displayFieldError('quantity', 'Jumlah pesanan tidak valid.'); } else if (currentServiceDetails) { if (quantity < currentServiceDetails.min_order) { isValid = false; displayFieldError('quantity', `Jumlah minimal ${currentServiceDetails.min_order}.`); } if (quantity > currentServiceDetails.max_order) { isValid = false; displayFieldError('quantity', `Jumlah maksimal ${currentServiceDetails.max_order}.`); } } if (!isValid) return; setButtonLoading('order-button', 'order-button-text', 'order-spinner', true, 'Memproses...'); const ajaxUrl = jsBaseUrl + '/ajax/place_order'; fetch(ajaxUrl, { method: 'POST', body: formData }) .then(response => { if (!response.ok) { throw new Error(`Server error: ${response.status} ${response.statusText}`); } return response.json().catch(e => { throw new Error("Respons server tidak valid (bukan JSON)."); }); }) .then(data => { if (data.success && data.orderDetails) { displaySuccessOrderAlert('order-message', data.orderDetails); orderForm.reset(); resetServiceSelection(); if (categoryChoicesInstance) { categoryChoicesInstance.setValue(['']); } updateActiveFilterButton('all'); populateCategorySelect('all'); } else { if (data.errors && data.errors.general) { displayGeneralMessage('order-message', data.errors.general, 'error'); } else { displayGeneralMessage('order-message', 'Gagal membuat pesanan.', 'error'); } if (data.errors) { for (const field in data.errors) { if (field !== 'general') { displayFieldError(field, data.errors[field]); } } } } }) .catch(error => { console.error('Fetch Error (Place Order):', error); displayGeneralMessage('order-message', `Terjadi masalah koneksi: ${error.message}.`, 'error'); }) .finally(() => { setButtonLoading('order-button', 'order-button-text', 'order-spinner', false); }); }); }
    }

    // ========================================================
    // Logika untuk Halaman Riwayat Pesanan (Order History)
    // ========================================================
    const historyTableBody = document.getElementById('order-history-table-body');
    const filterModalButton = document.getElementById('filter-modal-button');
    const filterModal = document.getElementById('filter-modal');
    const filterModalContent = document.getElementById('filter-modal-content');
    const closeFilterModalButton = document.getElementById('close-filter-modal');
    const filterForm = document.getElementById('filter-form');
    const resetFilterButton = document.getElementById('reset-filter-button');
    const paginationContainer = document.getElementById('pagination-container');
    const paginationInfo = document.getElementById('pagination-info');
    const paginationControls = document.getElementById('pagination-controls');
    const historyMessageDiv = document.getElementById('order-history-message');
    const orderDetailModal = document.getElementById('order-detail-modal');
    const orderDetailModalContent = document.getElementById('order-detail-modal-content');
    const closeOrderDetailModalButton = document.getElementById('close-order-detail-modal');
    const closeOrderDetailModalFooterButton = document.getElementById('close-order-detail-modal-footer');
    const orderDetailModalBody = document.getElementById('order-detail-modal-body');
    const detailOrderIdSpan = document.getElementById('detail-order-id');

    if (historyTableBody && filterModalButton && filterModal && filterForm && paginationContainer && jsBaseUrl && orderDetailModal) {
        let currentHistoryParams = { page: 1, limit: 10, status: 'all', sort_by: 'o.created_at', sort_type: 'DESC', search_column: 'o.id', search_keyword: '', date_start: '', date_end: '' };
        let currentOrdersData = [];
        function loadOrderHistory(params = {}) { historyTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data...</td></tr>`; if(paginationInfo) paginationInfo.textContent = 'Memuat...'; if(paginationControls) paginationControls.innerHTML = ''; if(historyMessageDiv) historyMessageDiv.innerHTML = ''; currentHistoryParams = { ...currentHistoryParams, ...params }; const queryParams = new URLSearchParams(currentHistoryParams).toString(); const url = `${jsBaseUrl}/ajax/get_order_history?${queryParams}`; fetch(url) .then(response => { if (!response.ok) throw new Error(`HTTP error ${response.status}`); return response.json(); }) .then(data => { if (data.success && data.orders && data.pagination) { currentOrdersData = data.orders; renderOrderTable(data.orders); renderPagination(data.pagination); } else { currentOrdersData = []; historyTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data.')}</td></tr>`; if(paginationInfo) paginationInfo.textContent = 'Gagal memuat data.'; if(paginationControls) paginationControls.innerHTML = ''; displayGeneralMessage('order-history-message', data.message || 'Gagal memuat data.', 'error'); } }) .catch(error => { currentOrdersData = []; console.error('Fetch Error (Order History):', error); historyTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat riwayat.</td></tr>`; if(paginationInfo) paginationInfo.textContent = 'Error koneksi.'; if(paginationControls) paginationControls.innerHTML = ''; displayGeneralMessage('order-history-message', 'Error koneksi saat memuat riwayat.', 'error'); }); }
        function renderOrderTable(orders) { historyTableBody.innerHTML = ''; if (orders.length === 0) { historyTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada riwayat pesanan yang cocok.</td></tr>`; return; } orders.forEach((order, index) => { const row = document.createElement('tr'); row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-sm'); const formattedDateTime = formatLocalDate(order.created_at); row.innerHTML = `<td class="px-4 py-3 whitespace-nowrap text-gray-700 font-medium">#${escapeHTML(order.id)}</td> <td class="px-4 py-3 whitespace-nowrap text-gray-500 text-xs">${escapeHTML(formattedDateTime)}</td> <td class="px-6 py-3 text-gray-700 max-w-xs truncate" title="${escapeHTML(order.service_name)}">${escapeHTML(order.service_name)}</td> <td class="px-4 py-3 whitespace-nowrap text-gray-600 max-w-[150px] truncate" title="${escapeHTML(order.target)}">${escapeHTML(order.target)}</td> <td class="px-4 py-3 whitespace-nowrap text-right text-gray-600">${escapeHTML(order.quantity?.toLocaleString('id-ID') ?? 'N/A')}</td> <td class="px-4 py-3 whitespace-nowrap text-right text-gray-800 font-medium">Rp ${escapeHTML(order.price?.toLocaleString('id-ID', {minimumFractionDigits: 0, maximumFractionDigits: 0}) ?? 'N/A')}</td> <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2.5 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${getStatusBadgeClass(order.status)}">${escapeHTML(order.status ? order.status.charAt(0).toUpperCase() + order.status.slice(1) : 'N/A')}</span></td> <td class="px-4 py-3 whitespace-nowrap text-center"><button type="button" class="open-detail-modal-btn text-blue-600 hover:text-blue-800 text-base" data-order-index="${index}" title="Lihat Detail"><i class="far fa-eye"></i></button></td>`; historyTableBody.appendChild(row); }); }
        function renderPagination(pagination) { if (!paginationControls) { return; } if (!pagination || typeof pagination.totalItems === 'undefined' || typeof pagination.totalPages === 'undefined' || typeof pagination.currentPage === 'undefined' || typeof pagination.limit === 'undefined' || typeof pagination.offset === 'undefined') { if(paginationInfo) paginationInfo.textContent = 'Informasi halaman tidak tersedia.'; paginationControls.innerHTML = ''; return; } if(paginationInfo) { paginationInfo.textContent = `Menampilkan ${pagination.totalItems > 0 ? pagination.offset + 1 : 0} sampai ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} hasil. (Halaman ${pagination.currentPage}/${pagination.totalPages})`; } paginationControls.innerHTML = ''; if (pagination.totalPages <= 1) { return; } let paginationHTML = ''; const currentPage = pagination.currentPage; const totalPages = pagination.totalPages; if (currentPage > 1) { paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="pagination-link px-3 py-1 border border-gray-300 rounded bg-white hover:bg-gray-100 text-gray-700 transition-colors">&laquo; Sebelumnya</button>`; } else { paginationHTML += `<span class="px-3 py-1 border border-gray-200 rounded bg-gray-100 text-gray-400 cursor-not-allowed">&laquo; Sebelumnya</span>`; } const maxPagesToShow = 5; let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2)); let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1); if(endPage === totalPages) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); } if (startPage > 1) { paginationHTML += `<button type="button" data-page="1" class="pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300">1</button>`; if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; } } for (let i = startPage; i <= endPage; i++) { const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300'; paginationHTML += `<button type="button" data-page="${i}" class="pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`; } if (endPage < totalPages) { if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; } paginationHTML += `<button type="button" data-page="${totalPages}" class="pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300">${totalPages}</button>`; } if (currentPage < totalPages) { paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="pagination-link px-3 py-1 border border-gray-300 rounded bg-white hover:bg-gray-100 text-gray-700 transition-colors">Berikutnya &raquo;</button>`; } else { paginationHTML += `<span class="px-3 py-1 border border-gray-200 rounded bg-gray-100 text-gray-400 cursor-not-allowed">Berikutnya &raquo;</span>`; } paginationControls.innerHTML = paginationHTML; }
        function openOrderDetailModal(orderIndex) { if (typeof orderIndex === 'undefined' || !currentOrdersData[orderIndex]) { return; } const order = currentOrdersData[orderIndex]; if (!orderDetailModal || !orderDetailModalBody || !detailOrderIdSpan) { return; } detailOrderIdSpan.textContent = escapeHTML(order.id); let refundStatus = 'Tidak'; const statusLower = order.status ? order.status.toLowerCase() : ''; if (statusLower === 'error' || statusLower === 'canceled' || statusLower === 'partial') { refundStatus = 'Ya'; } const lastUpdated = formatLocalDate(order.updated_at); orderDetailModalBody.innerHTML = `<div class="grid grid-cols-3 gap-x-4 gap-y-3"><div class="text-gray-400 font-medium col-span-1">Jumlah Awal</div><div class="text-gray-100 col-span-2 bg-gray-700 px-3 py-1.5 rounded">${escapeHTML(order.start_count?.toLocaleString('id-ID') ?? '-')}</div> <div class="text-gray-400 font-medium col-span-1">Jumlah Kurang</div><div class="text-gray-100 col-span-2 bg-gray-700 px-3 py-1.5 rounded">${escapeHTML(order.remains?.toLocaleString('id-ID') ?? '-')}</div> <div class="text-gray-400 font-medium col-span-1">Refund</div><div class="text-gray-100 col-span-2 bg-gray-700 px-3 py-1.5 rounded">${escapeHTML(refundStatus)}</div> <div class="text-gray-400 font-medium col-span-1">Asal</div><div class="text-gray-100 col-span-2 bg-gray-700 px-3 py-1.5 rounded">${escapeHTML(order.order_source ? order.order_source.toUpperCase() : 'WEB')}</div> <div class="text-gray-400 font-medium col-span-1">IP Address</div><div class="text-gray-100 col-span-2 bg-gray-700 px-3 py-1.5 rounded">${escapeHTML(order.ip_address || '-')}</div> <div class="text-gray-400 font-medium col-span-1">Pembaruan Terakhir</div><div class="text-gray-100 col-span-2 bg-gray-700 px-3 py-1.5 rounded">${escapeHTML(lastUpdated)}</div></div>`; openModal(orderDetailModal, orderDetailModalContent); }
        function closeOrderDetailModal() { closeModal(orderDetailModal, orderDetailModalContent); }
        if(filterModalButton && filterModal && closeFilterModalButton && filterModalContent) { filterModalButton.addEventListener('click', () => { openModal(filterModal, filterModalContent); }); closeFilterModalButton.addEventListener('click', () => { closeModal(filterModal, filterModalContent); }); filterModal.addEventListener('click', (event) => { if (event.target === filterModal) { closeModal(filterModal, filterModalContent); } }); }
        if(filterForm) { filterForm.addEventListener('submit', (event) => { event.preventDefault(); const formData = new FormData(filterForm); const newParams = {}; for (const [key, value] of formData.entries()) { newParams[key] = value; } newParams.page = 1; loadOrderHistory(newParams); closeModal(filterModal, filterModalContent); }); }
        if(resetFilterButton && filterForm) { resetFilterButton.addEventListener('click', () => { filterForm.reset(); document.getElementById('filter_limit').value = '10'; document.getElementById('filter_status').value = 'all'; document.getElementById('filter_sort_by').value = 'o.created_at'; document.getElementById('filter_sort_type').value = 'DESC'; document.getElementById('filter_search_column').value = 'o.id'; filterForm.dispatchEvent(new Event('submit', { cancelable: true })); }); }
        if(paginationControls) { paginationControls.addEventListener('click', (event) => { const targetButton = event.target.closest('.pagination-link'); if (targetButton && !targetButton.disabled && targetButton.dataset.page) { const pageToGo = parseInt(targetButton.dataset.page); if (!isNaN(pageToGo)) { loadOrderHistory({ page: pageToGo }); } } }); }
        historyTableBody.addEventListener('click', (event) => { const detailButton = event.target.closest('.open-detail-modal-btn'); if (detailButton && detailButton.dataset.orderIndex) { const orderIndex = parseInt(detailButton.dataset.orderIndex); openOrderDetailModal(orderIndex); } });
        if (closeOrderDetailModalButton) { closeOrderDetailModalButton.addEventListener('click', closeOrderDetailModal); } if (closeOrderDetailModalFooterButton) { closeOrderDetailModalFooterButton.addEventListener('click', closeOrderDetailModal); } if (orderDetailModal) { orderDetailModal.addEventListener('click', (event) => { if (event.target === orderDetailModal) { closeOrderDetailModal(); } }); }
        const initialUrlParams = new URLSearchParams(window.location.search); const initialParams = {}; initialUrlParams.forEach((value, key) => { initialParams[key] = value; if(filterForm && filterForm.elements[key]) filterForm.elements[key].value = value; }); currentHistoryParams = { ...currentHistoryParams, ...initialParams }; if(filterForm) { for (const key in currentHistoryParams) { if(filterForm.elements[key]) filterForm.elements[key].value = currentHistoryParams[key]; } } loadOrderHistory(currentHistoryParams);
    }

    // ========================================================
    // Logika untuk Halaman Laporan Pesanan (Order Report)
    // ========================================================
    const reportFilterForm = document.getElementById('report-filter-form');
    const orderChartCanvas = document.getElementById('orderChart');
    const statusSummaryContainer = document.getElementById('status-summary-container');
    const reportMessageDiv = document.getElementById('report-message');
    const chartLoadingPlaceholder = document.getElementById('chart-loading-placeholder');

    if (reportFilterForm && orderChartCanvas && statusSummaryContainer && jsBaseUrl) {
        let orderChartInstance = null;
        function loadOrderReport(startDate, endDate) { if(reportMessageDiv) reportMessageDiv.innerHTML = ''; if(chartLoadingPlaceholder) chartLoadingPlaceholder.style.display = 'flex'; if(statusSummaryContainer) statusSummaryContainer.innerHTML = `<div class="flex items-center justify-between p-3 bg-gray-100 rounded-lg text-sm text-gray-500 italic"><span>Memuat ringkasan status...</span><i class="fas fa-spinner fa-spin"></i></div>`; setButtonLoading('apply-report-filter', 'report-filter-btn-text', 'report-filter-spinner', true); const params = new URLSearchParams({ date_start: startDate, date_end: endDate }); const url = `${jsBaseUrl}/ajax/get_order_report?${params.toString()}`; fetch(url) .then(response => { if (!response.ok) throw new Error(`HTTP error ${response.status}`); return response.json(); }) .then(data => { if (data.success && data.chartData && data.statusSummary) { renderOrderChart(data.chartData); renderStatusSummary(data.statusSummary); } else { displayGeneralMessage('report-message', data.message || 'Gagal memuat data laporan.', 'error'); if (orderChartInstance) orderChartInstance.destroy(); if(statusSummaryContainer) statusSummaryContainer.innerHTML = `<p class="text-center text-red-500 italic">Gagal memuat ringkasan.</p>`; } }) .catch(error => { console.error('Fetch Error (Order Report):', error); displayGeneralMessage('report-message', 'Error koneksi saat memuat laporan.', 'error'); if (orderChartInstance) orderChartInstance.destroy(); if(statusSummaryContainer) statusSummaryContainer.innerHTML = `<p class="text-center text-red-500 italic">Error koneksi.</p>`; }) .finally(() => { if(chartLoadingPlaceholder) chartLoadingPlaceholder.style.display = 'none'; setButtonLoading('apply-report-filter', 'report-filter-btn-text', 'report-filter-spinner', false); }); }
        function renderOrderChart(chartData) { if (!orderChartCanvas) return; const ctx = orderChartCanvas.getContext('2d'); if (orderChartInstance) { orderChartInstance.destroy(); } orderChartInstance = new Chart(ctx, { type: 'line', data: { labels: chartData.labels, datasets: chartData.datasets.map(dataset => ({ ...dataset, tension: 0.3, pointBackgroundColor: dataset.borderColor || 'rgb(59, 130, 246)', pointBorderColor: '#fff', pointHoverRadius: 6, pointHoverBackgroundColor: dataset.borderColor || 'rgb(59, 130, 246)', pointHoverBorderColor: '#fff', })) }, options: { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'day', tooltipFormat: 'dd MMM yy', displayFormats: { day: 'dd MMM' } }, grid: { display: false }, ticks: { color: '#6b7280' } }, y: { beginAtZero: true, grid: { color: '#e5e7eb' }, ticks: { color: '#6b7280', callback: function(value) { if (Number.isInteger(value)) { return value; } } } } }, plugins: { legend: { display: false }, tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.7)', titleFont: { weight: 'bold' }, bodySpacing: 4, padding: 10, mode: 'index', intersect: false, } }, interaction: { mode: 'index', intersect: false, }, } }); }
        function renderStatusSummary(summaryData) { if (!statusSummaryContainer) return; statusSummaryContainer.innerHTML = ''; if (!Array.isArray(summaryData) || summaryData.length === 0) { statusSummaryContainer.innerHTML = `<p class="text-center text-gray-500 italic">Tidak ada data ringkasan.</p>`; return; } summaryData.forEach(item => { const div = document.createElement('div'); const badgeClass = getStatusBadgeClass(item.status_key); div.className = `flex items-center justify-between p-3 rounded-lg text-sm ${badgeClass.replace('border border-','bg-opacity-75 border-opacity-50 border-')} shadow-sm`; div.innerHTML = `<span class="font-medium">${escapeHTML(item.status)}</span> <span class="text-xs sm:text-sm">${escapeHTML(item.total_price_formatted)} dari ${escapeHTML(item.count.toLocaleString('id-ID'))} pesanan</span>`; statusSummaryContainer.appendChild(div); }); }
        reportFilterForm.addEventListener('submit', (event) => { event.preventDefault(); const startDate = document.getElementById('report_date_start').value; const endDate = document.getElementById('report_date_end').value; if (!startDate || !endDate) { displayGeneralMessage('report-message', 'Silakan pilih tanggal mulai dan tanggal akhir.', 'error', 3000); return; } if (new Date(endDate) < new Date(startDate)) { displayGeneralMessage('report-message', 'Tanggal akhir tidak boleh sebelum tanggal mulai.', 'error', 3000); return; } loadOrderReport(startDate, endDate); });
        const initialStartDate = document.getElementById('report_date_start').value; const initialEndDate = document.getElementById('report_date_end').value; if (initialStartDate && initialEndDate) { loadOrderReport(initialStartDate, initialEndDate); } else { if(chartLoadingPlaceholder) chartLoadingPlaceholder.style.display = 'none'; if(statusSummaryContainer) statusSummaryContainer.innerHTML = `<p class="text-center text-gray-500 italic">Silakan pilih rentang tanggal.</p>`; }
    }

    // ========================================================
    // Logika untuk Halaman Daftar Layanan (Services List - User Side)
    // ========================================================
    const serviceListContainer = document.getElementById('service-list-container');
    const serviceFilterModalButton = document.getElementById('service-filter-modal-button');
    const serviceFilterModal = document.getElementById('service-filter-modal');
    const serviceFilterModalContent = document.getElementById('service-filter-modal-content');
    const closeServiceFilterModalButton = document.getElementById('close-service-filter-modal');
    const serviceFilterForm = document.getElementById('service-filter-form');
    const resetServiceFilterButton = document.getElementById('reset-service-filter-button');
    const serviceListMessageDiv = document.getElementById('service-list-message');
    const serviceListLoading = document.getElementById('service-list-loading');
    const serviceDetailModal = document.getElementById('service-detail-modal');
    const serviceDetailModalContent = document.getElementById('service-detail-modal-content');
    const closeServiceDetailModalButton = document.getElementById('close-service-detail-modal');
    const closeServiceDetailModalFooterButton = document.getElementById('close-service-detail-modal-footer');
    const serviceDetailModalBody = document.getElementById('service-detail-modal-body');
    const serviceDetailModalTitleText = document.getElementById('service-detail-modal-title-text');


    if (serviceListContainer && serviceFilterModalButton && serviceFilterModal && serviceFilterForm && typeof jsBaseUrl !== 'undefined') {
        let currentServiceListParams = { search_keyword: '', sort_by: 's.name', sort_type: 'ASC' };
        let currentServiceListData = [];

        function loadServicesList(params = {}) {
            if(serviceListLoading) serviceListLoading.style.display = 'flex';
            serviceListContainer.innerHTML = '';
            if(serviceListMessageDiv) serviceListMessageDiv.innerHTML = '';

            currentServiceListParams = { ...currentServiceListParams, ...params };
            const queryParams = new URLSearchParams(currentServiceListParams).toString();
            const url = `${jsBaseUrl}/ajax/get_services_list?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && Array.isArray(data.categories)) {
                        currentServiceListData = data.categories;
                        renderServiceList(data.categories);
                    } else {
                        currentServiceListData = [];
                        serviceListContainer.innerHTML = `<div class="text-center py-10"><i class="fas fa-exclamation-circle text-4xl text-red-400 mb-3"></i><p class="text-red-600 font-medium">${escapeHTML(data.message || 'Gagal memuat daftar layanan.')}</p><p class="text-sm text-gray-500 mt-1">Silakan coba lagi nanti.</p></div>`;
                        displayGeneralMessage('service-list-message', data.message || 'Gagal memuat daftar layanan.', 'error');
                    }
                })
                .catch(error => {
                    currentServiceListData = [];
                    console.error('Fetch Error (Service List):', error);
                    serviceListContainer.innerHTML = `<div class="text-center py-10"><i class="fas fa-wifi-slash text-4xl text-orange-400 mb-3"></i><p class="text-orange-600 font-medium">Error koneksi saat memuat layanan.</p><p class="text-sm text-gray-500 mt-1">Periksa koneksi internet Anda dan coba lagi.</p></div>`;
                    displayGeneralMessage('service-list-message', 'Error koneksi saat memuat layanan.', 'error');
                })
                .finally(() => {
                    if(serviceListLoading) serviceListLoading.style.display = 'none';
                });
        }

        function renderServiceList(categories) {
            serviceListContainer.innerHTML = '';
            if (categories.length === 0) {
                serviceListContainer.innerHTML = `<div class="text-center py-10"><i class="fas fa-box-open text-4xl text-gray-400 mb-3"></i><p class="text-gray-600 font-medium">Tidak ada layanan yang ditemukan.</p><p class="text-sm text-gray-500 mt-1">Coba ubah filter atau kata kunci pencarian Anda.</p></div>`;
                return;
            }

            categories.forEach(category => {
                if (!category || !Array.isArray(category.services) || category.services.length === 0) {
                    return;
                }

                const categorySection = document.createElement('section');
                categorySection.className = 'mb-10 bg-white rounded-xl shadow-lg border border-gray-200 overflow-hidden transform hover:shadow-indigo-500/20 transition-all duration-300 ease-in-out hover:-translate-y-1';
                categorySection.setAttribute('aria-labelledby', `category-title-${category.id}`);

                categorySection.innerHTML = `
                    <header class="bg-gradient-to-r from-indigo-600 to-purple-600 px-5 py-4 rounded-t-lg">
                        <h3 id="category-title-${category.id}" class="text-lg font-semibold text-white flex items-center">
                            <i class="${escapeHTML(category.icon_class || 'fas fa-tags')} mr-3 opacity-80"></i>
                            ${escapeHTML(category.name)}
                            <span class="ml-auto text-xs font-normal bg-white/20 text-indigo-100 px-2.5 py-1 rounded-full">${category.services.length} Layanan</span>
                        </h3>
                    </header>
                    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 p-5">
                        ${category.services.map(service => `
                            <div class="service-card flex flex-col justify-between bg-slate-50 rounded-lg shadow-md hover:shadow-xl border border-slate-200 transition-all duration-300 ease-in-out transform hover:scale-[1.02]">
                                <div class="p-4">
                                    <h4 class="text-sm font-semibold text-indigo-700 mb-1.5 truncate" title="${escapeHTML(service.name)}">${escapeHTML(service.name)}</h4>
                                    <p class="text-xs text-gray-500 mb-2">ID: <span class="font-medium text-gray-700">${escapeHTML(service.id)}</span></p>
                                    <div class="text-xs text-gray-600 space-y-1 mb-3">
                                        <p><i class="fas fa-tag fa-fw mr-1.5 text-indigo-500"></i>Harga/1k: <strong class="text-indigo-800 font-bold">Rp ${escapeHTML(service.price_per_1000?.toLocaleString('id-ID', {minimumFractionDigits: 0, maximumFractionDigits: 0}) ?? 'N/A')}</strong></p>
                                        <p><i class="fas fa-arrow-down fa-fw mr-1.5 text-green-500"></i>Min: <span class="font-medium">${escapeHTML(service.min_order?.toLocaleString('id-ID') ?? '-')}</span></p>
                                        <p><i class="fas fa-arrow-up fa-fw mr-1.5 text-red-500"></i>Max: <span class="font-medium">${escapeHTML(service.max_order?.toLocaleString('id-ID') ?? '-')}</span></p>
                                    </div>
                                </div>
                                <div class="px-4 py-3 bg-slate-100 border-t border-slate-200 rounded-b-lg flex items-center justify-end space-x-2">
                                    <button type="button" class="open-service-detail-modal-btn text-xs font-medium text-indigo-600 hover:text-indigo-800 py-1.5 px-3 rounded-md hover:bg-indigo-100 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-indigo-400" data-service-id="${escapeHTML(service.id)}" title="Lihat Detail Layanan">
                                        <i class="far fa-eye mr-1.5"></i>Detail
                                    </button>
                                </div>
                            </div>
                        `).join('')}
                    </div>
                `;
                serviceListContainer.appendChild(categorySection);
            });
        }

        function openServiceDetailModal(serviceId) {
            if (!serviceId || !serviceDetailModal || !serviceDetailModalBody || !serviceDetailModalTitleText) return;

            let serviceData = null;
            for (const category of currentServiceListData) {
                serviceData = category.services.find(s => s.id == serviceId);
                if (serviceData) break;
            }

            if (!serviceData) {
                serviceDetailModalBody.innerHTML = '<p class="text-red-400 p-6">Gagal memuat detail layanan. Data tidak ditemukan.</p>';
                openModal(serviceDetailModal, serviceDetailModalContent);
                return;
            }

            serviceDetailModalTitleText.innerHTML = `<i class="fas fa-info-circle mr-3 text-indigo-400"></i> ${escapeHTML(serviceData.name)}`;
            
            let noteHTML = '<p class="italic text-gray-400">Tidak ada deskripsi atau catatan tambahan untuk layanan ini.</p>';
            if (serviceData.note) {
                noteHTML = escapeHTML(serviceData.note)
                    .replace(/\n/g, '<br>')
                    .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') 
                    .replace(/__(.*?)__/g, '<strong>$1</strong>')   
                    .replace(/\*(.*?)\*/g, '<em>$1</em>')     
                    .replace(/_(.*?)_/g, '<em>$1</em>');       
            }

            serviceDetailModalBody.innerHTML = `
                <div class="prose prose-sm prose-invert max-w-none text-gray-300 leading-relaxed">
                    ${noteHTML}
                </div>
                <div class="mt-5 pt-4 border-t border-gray-700 grid grid-cols-2 gap-x-4 gap-y-2 text-xs">
                    <div><strong class="text-gray-400 font-medium">ID Layanan:</strong> <span class="text-indigo-300">${escapeHTML(serviceData.id)}</span></div>
                    <div><strong class="text-gray-400 font-medium">Harga / 1000:</strong> <span class="text-emerald-400 font-bold">Rp ${escapeHTML(serviceData.price_per_1000?.toLocaleString('id-ID', {minimumFractionDigits: 0, maximumFractionDigits: 0}) ?? 'N/A')}</span></div>
                    <div><strong class="text-gray-400 font-medium">Minimal Pesan:</strong> ${escapeHTML(serviceData.min_order?.toLocaleString('id-ID') ?? '-')}</div>
                    <div><strong class="text-gray-400 font-medium">Maksimal Pesan:</strong> ${escapeHTML(serviceData.max_order?.toLocaleString('id-ID') ?? '-')}</div>
                </div>
            `;
            openModal(serviceDetailModal, serviceDetailModalContent);
        }

        function closeServiceDetailModal() {
            closeModal(serviceDetailModal, serviceDetailModalContent);
        }

        if(serviceFilterModalButton && serviceFilterModal && closeServiceFilterModalButton && serviceFilterModalContent) {
            serviceFilterModalButton.addEventListener('click', () => openModal(serviceFilterModal, serviceFilterModalContent));
            closeServiceFilterModalButton.addEventListener('click', () => closeModal(serviceFilterModal, serviceFilterModalContent));
            serviceFilterModal.addEventListener('click', (event) => { if (event.target === serviceFilterModal) closeModal(serviceFilterModal, serviceFilterModalContent); });
        }

        if(serviceFilterForm) {
            serviceFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(serviceFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                loadServicesList(newParams);
                closeModal(serviceFilterModal, serviceFilterModalContent);
            });
        }

        if(resetServiceFilterButton && serviceFilterForm) {
            resetServiceFilterButton.addEventListener('click', () => {
                serviceFilterForm.reset();
                const defaultSortBy = 's.name';
                const defaultSortType = 'ASC';
                const sortBySelect = document.getElementById('filter_sort_by');
                const sortTypeSelect = document.getElementById('filter_sort_type');
                if(sortBySelect) sortBySelect.value = defaultSortBy;
                if(sortTypeSelect) sortTypeSelect.value = defaultSortType;

                serviceFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        serviceListContainer.addEventListener('click', (event) => {
            const detailButton = event.target.closest('.open-service-detail-modal-btn');
            if (detailButton && detailButton.dataset.serviceId) {
                openServiceDetailModal(detailButton.dataset.serviceId);
            }
        });

        if (closeServiceDetailModalButton) closeServiceDetailModalButton.addEventListener('click', closeServiceDetailModal);
        if (closeServiceDetailModalFooterButton) closeServiceDetailModalFooterButton.addEventListener('click', closeServiceDetailModal);
        if (serviceDetailModal) {
            serviceDetailModal.addEventListener('click', (event) => {
                if (event.target === serviceDetailModal) closeServiceDetailModal();
            });
        }
        
        const initialUrlParamsServiceList = new URLSearchParams(window.location.search);
        const initialParamsServiceList = {};
        initialUrlParamsServiceList.forEach((value, key) => {
            initialParamsServiceList[key] = value;
            if(serviceFilterForm && serviceFilterForm.elements[key]) {
                serviceFilterForm.elements[key].value = value;
            }
        });
        currentServiceListParams = { ...currentServiceListParams, ...initialParamsServiceList };
        if(serviceFilterForm) {
            for (const key in currentServiceListParams) {
                if(serviceFilterForm.elements[key]) {
                    serviceFilterForm.elements[key].value = currentServiceListParams[key];
                }
            }
        }
        loadServicesList(currentServiceListParams);
    }
    
    const adminDepositsTableBody = document.getElementById('admin-deposits-table-body');
    const adminDepositFilterModalButton = document.getElementById('admin-deposit-filter-modal-button');
    const adminDepositFilterModal = document.getElementById('admin-deposit-filter-modal');
    const adminDepositFilterModalContent = document.getElementById('admin-deposit-filter-modal-content');
    const closeAdminDepositFilterModalButton = document.getElementById('close-admin-deposit-filter-modal');
    const adminDepositFilterForm = document.getElementById('admin-deposit-filter-form');
    const resetAdminDepositFilterButton = document.getElementById('reset-admin-deposit-filter-button');
    const adminDepositsPaginationInfo = document.getElementById('admin-deposits-pagination-info');
    const adminDepositsPaginationControls = document.getElementById('admin-deposits-pagination-controls');
    const adminDepositsMessageDiv = document.getElementById('admin-deposits-message');

    const editDepositModal = document.getElementById('edit-deposit-modal');
    const editDepositModalContent = document.getElementById('edit-deposit-modal-content');
    const editDepositForm = document.getElementById('edit-deposit-form');
    const editDepositIdSpan = document.getElementById('edit-deposit-id-span');
    const closeEditDepositModalButton = document.getElementById('close-edit-deposit-modal');
    const cancelEditDepositButton = document.getElementById('cancel-edit-deposit-button');
    const saveEditDepositButton = document.getElementById('save-edit-deposit-button');
    const editDepositMessageDiv = document.getElementById('edit-deposit-message');

    if (adminDepositsTableBody && adminDepositFilterModalButton && adminDepositFilterForm && typeof jsBaseUrl !== 'undefined') {
        let currentAdminDepositsParams = {
            page: 1,
            limit: 15,
            status: 'all',
            user_id: '',
            method_id: '',
            date_start: '',
            date_end: '',
            sort_by: 'd.created_at',
            sort_type: 'DESC',
            search_column: 'd.deposit_id',
            search_keyword: ''
        };
        let currentAdminDepositsData = [];

        function loadAdminDeposits(params = {}) {
            adminDepositsTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data deposit...</td></tr>`;
            if(adminDepositsPaginationInfo) adminDepositsPaginationInfo.textContent = 'Memuat...';
            if(adminDepositsPaginationControls) adminDepositsPaginationControls.innerHTML = '';
            if(adminDepositsMessageDiv && !adminDepositsMessageDiv.innerHTML.includes('success')) {
                adminDepositsMessageDiv.innerHTML = '';
                adminDepositsMessageDiv.className = 'mb-4 text-sm';
            }

            currentAdminDepositsParams = { ...currentAdminDepositsParams, ...params };
            const queryParams = new URLSearchParams(currentAdminDepositsParams).toString();
            const url = `${jsBaseUrl}/ajax/admin/get_admin_deposits?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.deposits && data.pagination) {
                        currentAdminDepositsData = data.deposits;
                        renderAdminDepositTable(data.deposits);
                        renderAdminDepositPagination(data.pagination);
                        if (adminDepositsMessageDiv && !adminDepositsMessageDiv.innerHTML.includes('success')) {
                            adminDepositsMessageDiv.innerHTML = '';
                            adminDepositsMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        currentAdminDepositsData = [];
                        adminDepositsTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data deposit.')}</td></tr>`;
                        if(adminDepositsPaginationInfo) adminDepositsPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminDepositsPaginationControls) adminDepositsPaginationControls.innerHTML = '';
                        if (!adminDepositsMessageDiv || !adminDepositsMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('admin-deposits-message', data.message || 'Gagal memuat data deposit.', 'error');
                        }
                    }
                })
                .catch(error => {
                    currentAdminDepositsData = [];
                    console.error('Fetch Error (Admin Deposits):', error);
                    adminDepositsTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat deposit.</td></tr>`;
                    if(adminDepositsPaginationInfo) adminDepositsPaginationInfo.textContent = 'Error koneksi.';
                    if(adminDepositsPaginationControls) adminDepositsPaginationControls.innerHTML = '';
                     if (!adminDepositsMessageDiv || !adminDepositsMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('admin-deposits-message', 'Error koneksi saat memuat deposit.', 'error');
                     }
                });
        }

        function renderAdminDepositTable(deposits) {
            adminDepositsTableBody.innerHTML = '';
            if (deposits.length === 0) {
                adminDepositsTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada deposit yang cocok dengan filter.</td></tr>`;
                return;
            }
            deposits.forEach((deposit, index) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-xs');
                const formattedDateTime = formatLocalDate(deposit.created_at);
                const statusBadgeClass = getStatusBadgeClass(deposit.status);
                const methodLogoHtml = deposit.method_logo ? `<img src="${escapeHTML(deposit.method_logo)}" alt="${escapeHTML(deposit.method_name)}" class="h-5 w-auto mr-1.5 inline-block bg-white p-0.5 rounded-sm object-contain">` : `<i class="fas fa-credit-card text-gray-400 mr-1.5"></i>`;

                row.innerHTML = `
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-700 font-medium">${escapeHTML(deposit.deposit_id)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-600" title="${escapeHTML(deposit.user_username)}">${escapeHTML(deposit.user_username)} (ID: ${escapeHTML(deposit.user_id)})</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-500">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-6 py-2.5 text-gray-700 max-w-xs truncate flex items-center" title="${escapeHTML(deposit.method_name)}">${methodLogoHtml} ${escapeHTML(deposit.method_name)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-right text-gray-600">Rp ${escapeHTML(parseFloat(deposit.amount).toLocaleString('id-ID'))}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-right text-green-600">+Rp ${escapeHTML(parseFloat(deposit.bonus).toLocaleString('id-ID'))}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-right text-blue-600 font-semibold">Rp ${escapeHTML(parseFloat(deposit.received_amount).toLocaleString('id-ID'))}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-center"><span class="px-2 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusBadgeClass}">${escapeHTML(deposit.status ? deposit.status.charAt(0).toUpperCase() + deposit.status.slice(1) : 'N/A')}</span></td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-center text-sm space-x-1">
                        <button type="button" class="admin-edit-deposit-btn text-blue-600 hover:text-blue-800 p-1 hover:bg-blue-100 rounded" data-deposit-index="${index}" title="Edit Deposit"><i class="far fa-edit"></i></button>
                    </td>
                `;
                adminDepositsTableBody.appendChild(row);
            });
        }

        function renderAdminDepositPagination(pagination) {
            if (!adminDepositsPaginationControls || !adminDepositsPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                adminDepositsPaginationInfo.textContent = 'Tidak ada data.';
                adminDepositsPaginationControls.innerHTML = '';
                return;
            }
            adminDepositsPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} deposit. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminDepositsPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;

            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;

            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-deposit-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;
            
            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages && totalPages >= maxPagesToShow) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }

            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="admin-deposit-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="admin-deposit-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }
             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-deposit-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-deposit-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
            
            adminDepositsPaginationControls.innerHTML = paginationHTML;
        }

        if(adminDepositFilterModalButton && adminDepositFilterModal && closeAdminDepositFilterModalButton && adminDepositFilterModalContent) {
            adminDepositFilterModalButton.addEventListener('click', () => openModal(adminDepositFilterModal, adminDepositFilterModalContent));
            closeAdminDepositFilterModalButton.addEventListener('click', () => closeModal(adminDepositFilterModal, adminDepositFilterModalContent));
            adminDepositFilterModal.addEventListener('click', (event) => { if (event.target === adminDepositFilterModal) closeModal(adminDepositFilterModal, adminDepositFilterModalContent); });
        }

        if(adminDepositFilterForm) {
            adminDepositFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(adminDepositFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                newParams.page = 1;
                loadAdminDeposits(newParams);
                closeModal(adminDepositFilterModal, adminDepositFilterModalContent);
            });
        }

        if(resetAdminDepositFilterButton && adminDepositFilterForm) {
            resetAdminDepositFilterButton.addEventListener('click', () => {
                adminDepositFilterForm.reset();
                document.getElementById('filter_limit_admin_deposit').value = '15';
                document.getElementById('filter_status_admin_deposit').value = 'all';
                document.getElementById('filter_user_id_admin_deposit').value = '';
                document.getElementById('filter_method_id_admin_deposit').value = '';
                document.getElementById('filter_date_start_admin_deposit').value = '';
                document.getElementById('filter_date_end_admin_deposit').value = '';
                document.getElementById('filter_search_column_admin_deposit').value = 'd.deposit_id';
                document.getElementById('filter_search_keyword_admin_deposit').value = '';
                document.getElementById('filter_sort_by_admin_deposit').value = 'd.created_at';
                document.getElementById('filter_sort_type_admin_deposit').value = 'DESC';
                adminDepositFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        if(adminDepositsPaginationControls) {
            adminDepositsPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-deposit-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) { loadAdminDeposits({ page: pageToGo }); }
                }
            });
        }

        adminDepositsTableBody.addEventListener('click', (event) => {
             const editButton = event.target.closest('.admin-edit-deposit-btn');
             if (editButton && editButton.dataset.depositIndex) {
                 const depositIndex = parseInt(editButton.dataset.depositIndex);
                 openEditDepositModal(depositIndex);
             }
        });

        function openEditDepositModal(depositIndex) {
             if (typeof depositIndex === 'undefined' || !currentAdminDepositsData[depositIndex]) {
                 console.error("Index deposit tidak valid atau data tidak ditemukan.");
                 return;
             }
             const deposit = currentAdminDepositsData[depositIndex];
             if (!editDepositModal || !editDepositModalContent || !editDepositForm || !editDepositIdSpan) {
                 console.error("Elemen modal edit deposit tidak ditemukan.");
                 return;
             }

             editDepositIdSpan.textContent = escapeHTML(deposit.deposit_id);
             editDepositForm.elements['deposit_id'].value = deposit.id;
             editDepositForm.elements['user_id'].value = deposit.user_id;
             editDepositForm.elements['received_amount'].value = deposit.received_amount;
             editDepositForm.elements['current_status'].value = deposit.status;
             editDepositForm.elements['status'].value = deposit.status || 'pending';
             
             if(editDepositMessageDiv) editDepositMessageDiv.innerHTML = '';
             clearFieldErrors(editDepositForm);
             openModal(editDepositModal, editDepositModalContent);
        }

        if(closeEditDepositModalButton) {
             closeEditDepositModalButton.addEventListener('click', () => closeModal(editDepositModal, editDepositModalContent));
        }
        if(cancelEditDepositButton) {
             cancelEditDepositButton.addEventListener('click', () => closeModal(editDepositModal, editDepositModalContent));
        }
        if(editDepositModal) {
             editDepositModal.addEventListener('click', (event) => {
                 if (event.target === editDepositModal) {
                     closeModal(editDepositModal, editDepositModalContent);
                 }
             });
        }

        if(editDepositForm && saveEditDepositButton) {
             editDepositForm.addEventListener('submit', (event) => {
                 event.preventDefault();
                 clearFieldErrors(editDepositForm);
                 if(editDepositMessageDiv) editDepositMessageDiv.innerHTML = '';
                 const formData = new FormData(editDepositForm);
                 const originalButtonText = saveEditDepositButton.textContent;
                 saveEditDepositButton.textContent = 'Menyimpan...';
                 saveEditDepositButton.disabled = true;

                 fetch(`${jsBaseUrl}/ajax/admin/update_deposit`, {
                     method: 'POST',
                     body: formData
                 })
                 .then(response => response.json())
                 .then(data => {
                     if (data.success) {
                         closeModal(editDepositModal, editDepositModalContent);
                         displayGeneralMessage('admin-deposits-message', data.message || 'Status deposit berhasil diperbarui.', 'success', 3000);
                         loadAdminDeposits(currentAdminDepositsParams);
                     } else {
                         if(editDepositMessageDiv) displayGeneralMessage('edit-deposit-message', data.message || 'Gagal memperbarui status deposit.', 'error');
                         if (data.errors) {
                             for (const field in data.errors) {
                                 displayFieldError(`edit_deposit_${field}`, data.errors[field]);
                             }
                         }
                     }
                 })
                 .catch(error => {
                     console.error('Fetch Error (Update Deposit):', error);
                     if(editDepositMessageDiv) displayGeneralMessage('edit-deposit-message', 'Terjadi masalah koneksi.', 'error');
                 })
                 .finally(() => {
                     saveEditDepositButton.textContent = originalButtonText;
                     saveEditDepositButton.disabled = false;
                 });
             });
        }

        const initialAdminDepositUrlParams = new URLSearchParams(window.location.search);
        const initialAdminDepositParams = {};
        initialAdminDepositUrlParams.forEach((value, key) => {
             initialAdminDepositParams[key] = value;
             if(adminDepositFilterForm && adminDepositFilterForm.elements[key]) {
                 adminDepositFilterForm.elements[key].value = value;
             }
        });
        currentAdminDepositsParams = { ...currentAdminDepositsParams, ...initialAdminDepositParams };
         if(adminDepositFilterForm) {
             for (const key in currentAdminDepositsParams) {
                 if(adminDepositFilterForm.elements[key]) {
                     adminDepositFilterForm.elements[key].value = currentAdminDepositsParams[key];
                 }
             }
         }
        loadAdminDeposits(currentAdminDepositsParams);
    }

    // ========================================================
    // Logika untuk Halaman Deposit Baru (Deposit New)
    // ========================================================
    const depositForm = document.getElementById('deposit-form');
    const paymentTypeSelect = document.getElementById('payment_type');
    const depositMethodsGrid = document.getElementById('deposit-methods-grid');
    const depositAmountInput = document.getElementById('deposit_amount');
    const minDepositInfo = document.getElementById('min_deposit_info');
    const bonusInfo = document.getElementById('bonus_info');
    const receivedBalance = document.getElementById('received_balance');
    const selectedMethodCodeInput = document.getElementById('selected_method_code');
    const selectedMethodMinInput = document.getElementById('selected_method_min');
    const selectedMethodBonusInput = document.getElementById('selected_method_bonus');
    const selectedMethodRateInput = document.getElementById('selected_method_rate');
    const submitDepositButton = document.getElementById('submit-deposit');
    const depositMessageDiv = document.getElementById('deposit-message');
    const depositPaymentDetailsDiv = document.getElementById('deposit-payment-details');

    if (depositForm && paymentTypeSelect && depositMethodsGrid && depositAmountInput && jsBaseUrl) {
        let allDepositMethods = []; let selectedMethod = null;

        function adjustMethodDisplay() {
            const screenWidth = window.innerWidth;
            if (screenWidth < 768 && allDepositMethods.length > 4) { // md breakpoint, lebih dari 4 item
                depositMethodsGrid.classList.add('scroll-x');
                depositMethodsGrid.classList.remove('grid', 'grid-cols-2', 'sm:grid-cols-2', 'md:grid-cols-3', 'lg:grid-cols-4', 'gap-3');
            } else {
                depositMethodsGrid.classList.remove('scroll-x');
                depositMethodsGrid.classList.add('grid', 'grid-cols-2', 'sm:grid-cols-2', 'md:grid-cols-3', 'lg:grid-cols-4', 'gap-3');
            }
        }

        function loadDepositMethods(type = 'all') {
            depositMethodsGrid.innerHTML = `<div class="col-span-full text-center py-10 text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat metode...</div>`;
            resetSelection();
            const params = new URLSearchParams({ type: type });
            const url = `${jsBaseUrl}/ajax/get_deposit_methods?${params.toString()}`;
            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && Array.isArray(data.methods)) {
                        allDepositMethods = data.methods;
                        renderDepositMethods(allDepositMethods);
                        adjustMethodDisplay(); // Panggil setelah render
                    } else {
                        depositMethodsGrid.innerHTML = `<div class="col-span-full text-center py-10 text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat metode.')}</div>`;
                        displayGeneralMessage('deposit-message', data.message || 'Gagal memuat metode.', 'error');
                    }
                })
                .catch(error => {
                    console.error("Fetch Error (Deposit Methods):", error);
                    depositMethodsGrid.innerHTML = `<div class="col-span-full text-center py-10 text-red-500 italic">Error koneksi saat memuat metode.</div>`;
                    displayGeneralMessage('deposit-message', 'Error koneksi saat memuat metode.', 'error');
                });
        }
        function renderDepositMethods(methods) {
            depositMethodsGrid.innerHTML = '';
            if (methods.length === 0) {
                depositMethodsGrid.innerHTML = `<div class="col-span-full text-center py-10 text-gray-500 italic">Tidak ada metode pembayaran yang tersedia untuk jenis ini.</div>`;
                return;
            }
            methods.forEach(method => {
                const card = document.createElement('button');
                card.type = 'button';
                card.className = 'deposit-method-card relative flex flex-col items-center justify-center p-3 sm:p-4 border border-gray-200 rounded-lg shadow-sm hover:shadow-md hover:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1 transition duration-150 ease-in-out cursor-pointer space-y-1.5 bg-white';
                card.dataset.methodCode = method.code;
                card.dataset.minDeposit = method.min_deposit;
                card.dataset.bonus = method.bonus_percentage;
                card.dataset.rate = method.rate;
                card.dataset.name = method.name;

                let logoHtml = '';
                if (method.logo_url) {
                    logoHtml = `<img src="${escapeHTML(method.logo_url)}" alt="${escapeHTML(method.name)}" class="h-7 sm:h-8 mb-1.5 object-contain" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
                                <div class="h-7 sm:h-8 mb-1.5 items-center justify-center text-gray-400 hidden"><i class="fas fa-credit-card text-2xl"></i></div>`;
                } else {
                    logoHtml = `<div class="h-7 sm:h-8 mb-1.5 flex items-center justify-center text-gray-400"><i class="fas fa-credit-card text-2xl"></i></div>`;
                }
                card.innerHTML += logoHtml;
                card.innerHTML += `<span class="text-xs sm:text-sm font-semibold text-gray-800 text-center leading-tight">${escapeHTML(method.name)}</span>`;
                if (method.bonus_percentage > 0) {
                    card.innerHTML += `<span class='text-xxs sm:text-xs text-green-600 font-bold'>(Bonus ${escapeHTML(method.bonus_percentage)}%)</span>`;
                }
                const autoCheckText = method.is_auto_check ? 'Otomatis' : 'Manual';
                const autoCheckClass = method.is_auto_check ? 'text-green-600' : 'text-yellow-600';
                card.innerHTML += `<span class="text-xxs sm:text-xs ${autoCheckClass}"><i class="fas ${method.is_auto_check ? 'fa-check-circle' : 'fa-clock'} mr-1"></i>${autoCheckText}</span>`;

                card.addEventListener('click', handleMethodSelection);
                depositMethodsGrid.appendChild(card);
            });
        }
        function handleMethodSelection(event) {
            const selectedCard = event.currentTarget;
            const methodCode = selectedCard.dataset.methodCode;
            depositMethodsGrid.querySelectorAll('.deposit-method-card').forEach(card => {
                card.classList.remove('border-blue-500', 'ring-2', 'ring-blue-500', 'ring-offset-1', 'bg-blue-50');
                card.classList.add('border-gray-200');
            });
            selectedCard.classList.add('border-blue-500', 'ring-2', 'ring-blue-500', 'ring-offset-1', 'bg-blue-50');
            selectedCard.classList.remove('border-gray-200');

            selectedMethod = {
                code: methodCode,
                min: parseFloat(selectedCard.dataset.minDeposit) || 10000,
                bonus: parseFloat(selectedCard.dataset.bonus) || 0,
                rate: parseFloat(selectedCard.dataset.rate) || 1,
                name: selectedCard.dataset.name || methodCode
            };

            if(minDepositInfo) minDepositInfo.textContent = `Rp ${selectedMethod.min.toLocaleString('id-ID')}`;
            if(bonusInfo) bonusInfo.textContent = `${selectedMethod.bonus}%`;
            if(depositAmountInput) depositAmountInput.min = selectedMethod.min;
            if(selectedMethodCodeInput) selectedMethodCodeInput.value = selectedMethod.code;
            if(selectedMethodMinInput) selectedMethodMinInput.value = selectedMethod.min;
            if(selectedMethodBonusInput) selectedMethodBonusInput.value = selectedMethod.bonus;
            if(selectedMethodRateInput) selectedMethodRateInput.value = selectedMethod.rate;

            calculateReceivedBalance();
            if(submitDepositButton) {
                submitDepositButton.disabled = false;
                const btnText = document.getElementById('deposit-btn-text');
                if(btnText) btnText.textContent = `Deposit via ${selectedMethod.name}`;
            }
        }
        function calculateReceivedBalance() {
            if (!depositAmountInput || !receivedBalance || !selectedMethod) {
                if(receivedBalance) receivedBalance.textContent = 'Rp 0';
                return;
            }
            const amount = parseFloat(depositAmountInput.value) || 0;
            let received = 0;
            if (amount >= selectedMethod.min) {
                const bonus = amount * (selectedMethod.bonus / 100);
                received = (amount + bonus) * selectedMethod.rate;
            }
            receivedBalance.textContent = 'Rp ' + received.toLocaleString('id-ID', { minimumFractionDigits: 0, maximumFractionDigits: 2 });
        }
        function resetSelection() {
            selectedMethod = null;
            if(selectedMethodCodeInput) selectedMethodCodeInput.value = '';
            if(minDepositInfo) minDepositInfo.textContent = 'Rp 10.000';
            if(bonusInfo) bonusInfo.textContent = '0%';
            if(depositAmountInput) depositAmountInput.min = '10000';
            if(selectedMethodMinInput) selectedMethodMinInput.value = '10000';
            if(selectedMethodBonusInput) selectedMethodBonusInput.value = '0';
            if(selectedMethodRateInput) selectedMethodRateInput.value = '1';
            if(submitDepositButton) {
                submitDepositButton.disabled = true;
                const btnText = document.getElementById('deposit-btn-text');
                if(btnText) btnText.textContent = 'Pilih Metode';
            }
            depositMethodsGrid.querySelectorAll('.deposit-method-card').forEach(card => {
                card.classList.remove('border-blue-500', 'ring-2', 'ring-blue-500', 'ring-offset-1', 'bg-blue-50');
                card.classList.add('border-gray-200');
            });
            calculateReceivedBalance();
            if(depositPaymentDetailsDiv) depositPaymentDetailsDiv.innerHTML = '';
        }

        loadDepositMethods('all');
        if(paymentTypeSelect) {
            paymentTypeSelect.addEventListener('change', function() {
                loadDepositMethods(this.value);
            });
        }
        if(depositAmountInput) {
            depositAmountInput.addEventListener('input', calculateReceivedBalance);
        }

        if(depositForm && submitDepositButton) {
            const btnTextEl = document.getElementById('deposit-btn-text');
            if(btnTextEl) submitDepositButton.dataset.originalText = btnTextEl.textContent;

            depositForm.addEventListener('submit', function(event) {
                event.preventDefault();
                if (!selectedMethod) {
                    displayGeneralMessage('deposit-message', 'Silakan pilih metode pembayaran terlebih dahulu.', 'error', 3000);
                    return;
                }
                const amount = parseFloat(depositAmountInput.value) || 0;
                if (amount < selectedMethod.min) {
                    displayFieldError('deposit_amount', `Jumlah minimal deposit untuk metode ini adalah Rp ${selectedMethod.min.toLocaleString('id-ID')}.`);
                    return;
                } else {
                    displayFieldError('deposit_amount', '');
                }
                clearFieldErrors(depositForm);
                displayGeneralMessage('deposit-message', '');
                if(depositPaymentDetailsDiv) depositPaymentDetailsDiv.innerHTML = '';
                setButtonLoading('submit-deposit', 'deposit-btn-text', 'deposit-spinner', true, 'Memproses...');

                const formData = new FormData(depositForm);
                const ajaxUrl = depositForm.action;

                fetch(ajaxUrl, {
                    method: 'POST',
                    body: formData
                })
                .then(response => {
                    if (!response.ok) {
                         return response.json().then(errData => { throw new Error(errData.message || `Server error: ${response.status}`); });
                    }
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.paydisini_unique_code) {
                        displayGeneralMessage('deposit-message', data.message || 'Permintaan deposit berhasil, mengalihkan ke invoice...', 'success');
                        depositForm.reset();
                        resetSelection();

                        const invoiceUrl = `${jsBaseUrl}/deposit/invoice/${data.paydisini_unique_code}`;
                        setTimeout(() => {
                            window.location.href = invoiceUrl;
                        }, 1500);

                    } else {
                        displayGeneralMessage('deposit-message', data.message || 'Gagal memproses deposit.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(field, data.errors[field]);
                            }
                        }
                         setButtonLoading('submit-deposit', 'deposit-btn-text', 'deposit-spinner', false);
                    }
                })
                .catch(error => {
                    console.error("Fetch Error (Request Deposit):", error);
                    displayGeneralMessage('deposit-message', `Terjadi masalah: ${error.message}.`, 'error');
                    setButtonLoading('submit-deposit', 'deposit-btn-text', 'deposit-spinner', false);
                });
            });
        }
        window.addEventListener('resize', adjustMethodDisplay); // Panggil saat resize
    }

    // ========================================================
    // Logika untuk Halaman Tiket (Tickets Index & View)
    // ========================================================
    const ticketListTableBody = document.getElementById('ticket-list-table-body');
    const ticketPaginationInfo = document.getElementById('ticket-pagination-info');
    const ticketPaginationControls = document.getElementById('ticket-pagination-controls');
    const ticketListMessageDiv = document.getElementById('ticket-list-message');
    const createTicketForm = document.getElementById('create-ticket-form');
    const createTicketMessageDiv = document.getElementById('create-ticket-message');
    const submitTicketButton = document.getElementById('submit-ticket');
    const ticketViewContainer = document.getElementById('ticket-replies-container');
    const ticketSubjectTitle = document.getElementById('ticket-subject-title');
    const ticketViewIdSpan = document.getElementById('ticket-view-id');
    const ticketViewStatusSpan = document.getElementById('ticket-view-status');
    const ticketViewCreatedSpan = document.getElementById('ticket-view-created');
    const ticketViewUpdatedSpan = document.getElementById('ticket-view-updated');
    const ticketRepliesContainer = document.getElementById('ticket-replies-container');
    const ticketReplyFormContainer = document.getElementById('ticket-reply-form-container');
    const ticketReplyForm = document.getElementById('ticket-reply-form');
    const replyTicketIdInput = document.getElementById('reply_ticket_id');
    const replyMessageTextarea = document.getElementById('reply_message');
    const submitReplyButton = document.getElementById('submit-reply');
    const closeTicketButton = document.getElementById('close-ticket-button');
    const ticketClosedMessage = document.getElementById('ticket-closed-message');
    const ticketViewMessageDiv = document.getElementById('ticket-view-message');
    const createAttachmentInput = document.getElementById('attachment');
    const replyAttachmentInput = document.getElementById('reply_attachment'); 

    // Logika Daftar Tiket
    if (ticketListTableBody && ticketPaginationInfo && ticketPaginationControls && jsBaseUrl) {
        let currentTicketListParams = { page: 1, limit: 15, status: 'all' }; 

        function loadTicketsList(params = {}) {
            ticketListTableBody.innerHTML = `<tr><td colspan="5" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat tiket...</td></tr>`;
            ticketPaginationInfo.textContent = 'Memuat...';
            ticketPaginationControls.innerHTML = '';
            if(ticketListMessageDiv) ticketListMessageDiv.innerHTML = '';

            currentTicketListParams = { ...currentTicketListParams, ...params };
            const queryParams = new URLSearchParams(currentTicketListParams).toString();
            const url = `${jsBaseUrl}/ajax/get_tickets_list?${queryParams}`; 

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.tickets && data.pagination) {
                        renderTicketTable(data.tickets);
                        renderTicketPagination(data.pagination);
                    } else {
                        ticketListTableBody.innerHTML = `<tr><td colspan="5" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat tiket.')}</td></tr>`;
                        ticketPaginationInfo.textContent = 'Gagal memuat data.';
                        ticketPaginationControls.innerHTML = '';
                        displayGeneralMessage('ticket-list-message', data.message || 'Gagal memuat tiket.', 'error');
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (User Ticket List):', error);
                    ticketListTableBody.innerHTML = `<tr><td colspan="5" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat tiket.</td></tr>`;
                    ticketPaginationInfo.textContent = 'Error koneksi.';
                    ticketPaginationControls.innerHTML = '';
                    displayGeneralMessage('ticket-list-message', 'Error koneksi saat memuat tiket.', 'error');
                });
        }

        function renderTicketTable(tickets) {
            ticketListTableBody.innerHTML = '';
            if (tickets.length === 0) {
                ticketListTableBody.innerHTML = `<tr><td colspan="5" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada tiket ditemukan.</td></tr>`;
                return;
            }
            tickets.forEach(ticket => {
                const row = document.createElement('tr');
                row.className = 'hover:bg-gray-50 transition-colors text-sm';
                const statusClass = getTicketStatusBadgeClass(ticket.status);
                const formattedDate = formatLocalDate(ticket.updated_at);

                row.innerHTML = `
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500">${escapeHTML(ticket.ticket_id)}</td>
                    <td class="px-6 py-3 text-gray-800 font-medium max-w-xs truncate" title="${escapeHTML(ticket.subject)}">${escapeHTML(ticket.subject)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center">
                        <span class="px-2.5 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass}">
                            ${escapeHTML(ticket.status.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase()))}
                        </span>
                    </td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500 text-xs">${escapeHTML(formattedDate)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center">
                        <a href="${jsBaseUrl}/tickets/view/${escapeHTML(ticket.ticket_id)}" class="text-blue-600 hover:text-blue-800 hover:underline text-xs font-medium">Lihat Detail</a>
                    </td>
                `;
                ticketListTableBody.appendChild(row);
            });
        }

        function renderTicketPagination(pagination) {
            if (!ticketPaginationControls || !ticketPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                 ticketPaginationInfo.textContent = 'Tidak ada data.';
                 ticketPaginationControls.innerHTML = '';
                 return;
             }

            ticketPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} tiket.`;
            ticketPaginationControls.innerHTML = '';

            if (pagination.totalPages <= 1) {
                return;
            }

            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;

            paginationHTML += `
                <button type="button" data-page="${currentPage - 1}"
                        class="ticket-pagination-link px-3 py-1 border rounded transition-colors
                               ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}"
                        ${currentPage <= 1 ? 'disabled' : ''}>
                    &laquo; Sebelumnya
                </button>`;

            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);

            if (endPage === totalPages && totalPages >= maxPagesToShow) {
                startPage = Math.max(1, totalPages - maxPagesToShow + 1);
            }

            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="ticket-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) {
                    paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`;
                }
            }

            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `
                    <button type="button" data-page="${i}"
                            class="ticket-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">
                        ${i}
                    </button>`;
            }

            if (endPage < totalPages) {
                if (endPage < totalPages - 1) {
                    paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`;
                }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="ticket-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }

            paginationHTML += `
                <button type="button" data-page="${currentPage + 1}"
                        class="ticket-pagination-link px-3 py-1 border rounded transition-colors
                               ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}"
                        ${currentPage >= totalPages ? 'disabled' : ''}>
                    Berikutnya &raquo;
                </button>`;

            ticketPaginationControls.innerHTML = paginationHTML;
        }

        if(ticketPaginationControls) {
            ticketPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.ticket-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) {
                        loadTicketsList({ page: pageToGo });
                    }
                }
            });
        }

        loadTicketsList(); 
    }

    // Logika Buat Tiket
    if (createTicketForm && submitTicketButton && jsBaseUrl) {
        const btnTextEl = document.getElementById('ticket-btn-text');
        if(btnTextEl) submitTicketButton.dataset.originalText = btnTextEl.textContent;

        createTicketForm.addEventListener('submit', function(event) {
            event.preventDefault();
            clearFieldErrors(createTicketForm);
            displayGeneralMessage('create-ticket-message', '');
            let isValid = true;
            const subject = document.getElementById('subject').value.trim();
            const message = document.getElementById('message').value.trim();
            const attachmentFile = createAttachmentInput ? createAttachmentInput.files[0] : null;

            if (!subject) { isValid = false; displayFieldError('subject', 'Subjek wajib diisi.'); }
            if (!message) { isValid = false; displayFieldError('message', 'Pesan wajib diisi.'); }

            if (attachmentFile) {
                const maxSize = 2 * 1024 * 1024; // 2MB
                const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
                if (attachmentFile.size > maxSize) {
                    isValid = false;
                    displayFieldError('attachment', 'Ukuran file maksimal 2MB.');
                } else if (!allowedTypes.includes(attachmentFile.type)) {
                    isValid = false;
                    displayFieldError('attachment', 'Format file tidak valid (JPG, PNG, GIF, WEBP).');
                }
            }

            if (!isValid) return;

            setButtonLoading('submit-ticket', 'ticket-btn-text', 'ticket-spinner', true);

            const formData = new FormData();
            formData.append('subject', subject);
            formData.append('message', message);
            if (attachmentFile) {
                formData.append('attachment', attachmentFile, attachmentFile.name);
            }

            const ajaxUrl = createTicketForm.action;

            fetch(ajaxUrl, {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                if (data.success && data.ticket_id) {
                    displayGeneralMessage('create-ticket-message', data.message || 'Tiket berhasil dibuat.', 'success');
                    createTicketForm.reset();
                    setTimeout(() => {
                        window.location.href = `${jsBaseUrl}/tickets/view/${data.ticket_id}`;
                    }, 1500);
                } else {
                    displayGeneralMessage('create-ticket-message', data.message || 'Gagal membuat tiket.', 'error');
                    if (data.errors) {
                        for (const field in data.errors) {
                            displayFieldError(field, data.errors[field]);
                        }
                    }
                }
            })
            .catch(error => {
                console.error('Fetch Error (Create Ticket):', error);
                displayGeneralMessage('create-ticket-message', 'Terjadi masalah koneksi.', 'error');
            })
            .finally(() => {
                setButtonLoading('submit-ticket', 'ticket-btn-text', 'ticket-spinner', false);
            });
        });
    }

    // Logika Lihat Tiket
    if (ticketViewContainer && jsBaseUrl) {
        let currentTicketData = null;
        let currentTicketId = null;
        const pathSegments = window.location.pathname.split('/');
        const ticketIdFromUrl = pathSegments[pathSegments.length - 1];

        if (ticketIdFromUrl && ticketIdFromUrl !== 'view') {
            currentTicketId = ticketIdFromUrl;
            if(replyTicketIdInput) replyTicketIdInput.value = currentTicketId;
            loadTicketDetails(currentTicketId);
        } else {
            if(ticketRepliesContainer) ticketRepliesContainer.innerHTML = '<p class="text-center text-red-500 italic py-10">ID Tiket tidak valid.</p>';
        }

        function loadTicketDetails(ticketId) {
            if(ticketRepliesContainer) ticketRepliesContainer.innerHTML = `<div class="text-center py-10 text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat percakapan...</div>`;

            const url = `${jsBaseUrl}/ajax/get_ticket_details?ticket_id=${ticketId}`;
            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.ticket && data.replies) {
                        currentTicketData = data.ticket;
                        updateTicketHeader(data.ticket);
                        renderTicketReplies(data.replies, data.current_user_id);
                        updateReplyFormVisibility(data.ticket.status);
                    } else {
                         if(ticketRepliesContainer) ticketRepliesContainer.innerHTML = `<p class="text-center text-red-500 italic py-10">${escapeHTML(data.message || 'Gagal memuat detail tiket.')}</p>`;
                         displayGeneralMessage('ticket-view-message', data.message || 'Gagal memuat detail tiket.', 'error');
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Ticket Details):', error);
                    if(ticketRepliesContainer) ticketRepliesContainer.innerHTML = `<p class="text-center text-red-500 italic py-10">Error koneksi saat memuat detail tiket.</p>`;
                    displayGeneralMessage('ticket-view-message', 'Error koneksi saat memuat detail tiket.', 'error');
                });
        }

        function updateTicketHeader(ticket) {
             if(ticketSubjectTitle) ticketSubjectTitle.innerHTML = `<i class="fas fa-ticket-alt mr-2 text-orange-500"></i> ${escapeHTML(ticket.subject)}`;
             if(ticketViewIdSpan) ticketViewIdSpan.textContent = escapeHTML(ticket.ticket_id);
             if(ticketViewStatusSpan) {
                 const statusClass = getTicketStatusBadgeClass(ticket.status);
                 ticketViewStatusSpan.className = `px-2 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass}`;
                 ticketViewStatusSpan.textContent = escapeHTML(ticket.status.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase()));
             }
             if(ticketViewCreatedSpan) ticketViewCreatedSpan.textContent = formatLocalDate(ticket.created_at);
             if(ticketViewUpdatedSpan) ticketViewUpdatedSpan.textContent = formatLocalDate(ticket.updated_at);
        }

        function renderTicketReplies(replies, currentUserId) {
            if (!ticketRepliesContainer) return;
            ticketRepliesContainer.innerHTML = '';
            if (!replies || replies.length === 0) {
                ticketRepliesContainer.innerHTML = '<p class="text-center text-gray-500 italic py-5">Belum ada balasan.</p>';
                return;
            }

            replies.forEach(reply => {
                const isOwnMessage = reply.user_id == currentUserId;
                const isAdminReply = reply.user_role === 'admin';

                const alignmentClass = isOwnMessage ? 'flex justify-end' : 'flex justify-start';

                let bubbleClasses = 'p-3 rounded-lg shadow-md max-w-xs md:max-w-md lg:max-w-lg break-words'; 
                if (isOwnMessage) {
                    bubbleClasses += ' bg-blue-600 text-white rounded-br-none';
                } else if (isAdminReply) {
                    bubbleClasses += ' bg-gray-700 text-gray-100 rounded-bl-none';
                } else {
                    bubbleClasses += ' bg-gray-200 text-gray-800 rounded-bl-none'; 
                }

                const senderName = isOwnMessage
                    ? 'Anda'
                    : (isAdminReply ? `<i class="fas fa-shield-alt text-yellow-400 mr-1"></i> ${escapeHTML(reply.sender_name || 'Admin')}` : escapeHTML(reply.sender_name || 'Pengguna'));

                let attachmentHTML = '';
                if (reply.attachment_url) {
                    attachmentHTML = `
                        <div class="mt-2 border-t ${isOwnMessage ? 'border-blue-500' : (isAdminReply ? 'border-gray-600' : 'border-gray-300')} pt-2">
                            <a href="${escapeHTML(reply.attachment_url)}" target="_blank" rel="noopener noreferrer" class="block relative group overflow-hidden rounded border ${isOwnMessage ? 'border-blue-400' : (isAdminReply ? 'border-gray-500' : 'border-gray-300')} hover:shadow-lg transition-shadow">
                                <img src="${escapeHTML(reply.attachment_url)}" alt="Lampiran" class="max-w-full h-auto max-h-48 object-contain rounded transition-transform duration-300 group-hover:scale-105">
                                <div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-40 transition-opacity duration-300 flex items-center justify-center">
                                    <i class="fas fa-external-link-alt text-white text-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></i>
                                </div>
                            </a>
                        </div>
                    `;
                }

                const replyWrapperDiv = document.createElement('div');
                replyWrapperDiv.className = `mb-4 ${alignmentClass}`;

                replyWrapperDiv.innerHTML = `
                    <div class="flex flex-col ${isOwnMessage ? 'items-end' : 'items-start'}">
                        <div class="${bubbleClasses}">
                            <p class="text-sm leading-relaxed">${escapeHTML(reply.message).replace(/\n/g, '<br>')}</p>
                            ${attachmentHTML}
                        </div>
                        <div class="text-xs text-gray-400 mt-1 px-1">
                            ${senderName} - ${formatLocalDate(reply.created_at)}
                        </div>
                    </div>
                `;
                ticketRepliesContainer.appendChild(replyWrapperDiv);
            });
            ticketRepliesContainer.scrollTop = ticketRepliesContainer.scrollHeight;
        }

        function updateReplyFormVisibility(status) {
            const isClosed = status === 'closed';
            if(ticketReplyFormContainer) ticketReplyFormContainer.style.display = isClosed ? 'none' : 'block';
            if(ticketClosedMessage) ticketClosedMessage.style.display = isClosed ? 'block' : 'none';
            if(closeTicketButton) closeTicketButton.style.display = isClosed ? 'none' : 'inline-flex';
        }

        if(ticketReplyForm && submitReplyButton) {
            const btnTextEl = document.getElementById('reply-btn-text');
            if(btnTextEl) submitReplyButton.dataset.originalText = btnTextEl.textContent;

            ticketReplyForm.addEventListener('submit', function(event) {
                event.preventDefault();
                clearFieldErrors(ticketReplyForm);
                displayGeneralMessage('ticket-view-message', '');
                const message = replyMessageTextarea.value.trim();
                const attachmentFile = replyAttachmentInput ? replyAttachmentInput.files[0] : null;

                let isValid = true;
                if (!message) {
                    isValid = false;
                    displayFieldError('reply_message', 'Balasan tidak boleh kosong.');
                }

                if (attachmentFile) {
                    const maxSize = 2 * 1024 * 1024; // 2MB
                    const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
                    if (attachmentFile.size > maxSize) {
                        isValid = false;
                        displayFieldError('reply_attachment', 'Ukuran file maksimal 2MB.');
                    } else if (!allowedTypes.includes(attachmentFile.type)) {
                        isValid = false;
                        displayFieldError('reply_attachment', 'Format file tidak valid (JPG, PNG, GIF, WEBP).');
                    }
                }

                if (!isValid) return;

                setButtonLoading('submit-reply', 'reply-btn-text', 'reply-spinner', true);

                const formData = new FormData();
                formData.append('ticket_id', currentTicketId);
                formData.append('message', message);
                if (attachmentFile) {
                    formData.append('attachment', attachmentFile, attachmentFile.name);
                }

                const ajaxUrl = ticketReplyForm.action;

                fetch(ajaxUrl, {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        loadTicketDetails(currentTicketId);
                        replyMessageTextarea.value = '';
                        if (replyAttachmentInput) replyAttachmentInput.value = '';
                    } else {
                        displayGeneralMessage('ticket-view-message', data.message || 'Gagal mengirim balasan.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(field === 'message' ? 'reply_message' : field, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Reply Ticket):', error);
                    displayGeneralMessage('ticket-view-message', 'Terjadi masalah koneksi.', 'error');
                })
                .finally(() => {
                    setButtonLoading('submit-reply', 'reply-btn-text', 'reply-spinner', false);
                });
            });
        }
        if(closeTicketButton) { closeTicketButton.addEventListener('click', function() { const ticketId = currentTicketId; showCloseTicketConfirmationModal(ticketId); }); }
    }

    // ========================================================
    // Fungsi Modal Konfirmasi Kustom
    // ========================================================
    function createConfirmationModalHTML(id, title, message, confirmText = 'Ya, Lanjutkan', cancelText = 'Batal') {
        const modalId = `confirm-modal-${id}`;
        const modalContentId = `confirm-modal-content-${id}`;
        const confirmBtnId = `confirm-modal-confirm-btn-${id}`;
        const cancelBtnId = `confirm-modal-cancel-btn-${id}`;
        const closeBtnId = `confirm-modal-close-btn-${id}`;

        return `
            <div id="${modalId}" class="fixed inset-0 z-50 hidden items-center justify-center bg-black bg-opacity-60 transition-opacity duration-300 ease-in-out" aria-labelledby="${modalId}-title" role="dialog" aria-modal="true">
                <div id="${modalContentId}" class="relative bg-white rounded-lg shadow-xl w-full max-w-md mx-4 transform transition-all duration-300 ease-in-out scale-95 opacity-0">
                    <div class="flex items-start justify-between p-5 border-b rounded-t">
                        <h3 id="${modalId}-title" class="text-xl font-semibold text-gray-900 flex items-center">
                           <i class="fas fa-exclamation-triangle text-yellow-400 mr-3"></i> ${escapeHTML(title)}
                        </h3>
                        <button type="button" id="${closeBtnId}" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center">
                            <i class="fas fa-times text-xl"></i>
                            <span class="sr-only">Tutup modal</span>
                        </button>
                    </div>
                    <div class="p-6 space-y-4">
                        <p class="text-base leading-relaxed text-gray-600">${escapeHTML(message)}</p>
                    </div>
                    <div class="flex items-center justify-end p-6 space-x-3 border-t border-gray-200 rounded-b">
                        <button id="${cancelBtnId}" type="button" class="px-5 py-2.5 text-sm font-medium text-gray-500 bg-white rounded-lg border border-gray-200 hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-blue-300 hover:text-gray-900 focus:z-10">${escapeHTML(cancelText)}</button>
                        <button id="${confirmBtnId}" type="button" class="px-5 py-2.5 text-sm font-medium text-white bg-red-600 hover:bg-red-700 focus:ring-4 focus:outline-none focus:ring-red-300 rounded-lg text-center">${escapeHTML(confirmText)}</button>
                    </div>
                </div>
            </div>
        `;
    }

    function showCloseTicketConfirmationModal(ticketIdToClose) {
        const uniqueModalIdSuffix = 'close-ticket-modal';
        const modalId = `confirm-modal-${uniqueModalIdSuffix}`;
        const modalContentId = `confirm-modal-content-${uniqueModalIdSuffix}`;
        const confirmBtnId = `confirm-modal-confirm-btn-${uniqueModalIdSuffix}`;
        const cancelBtnId = `confirm-modal-cancel-btn-${uniqueModalIdSuffix}`;
        const closeBtnId = `confirm-modal-close-btn-${uniqueModalIdSuffix}`;

        let modalElement = document.getElementById(modalId);
        let confirmClickHandler = null;
        let cancelClickHandler = null;
        let closeClickHandler = null;
        let overlayClickHandler = null;

        const setupModalEventListeners = (modalElem, contentElem) => {
            const confirmBtn = document.getElementById(confirmBtnId);
            const cancelBtn = document.getElementById(cancelBtnId);
            const closeBtn = document.getElementById(closeBtnId);

            if (confirmBtn && confirmClickHandler) confirmBtn.removeEventListener('click', confirmClickHandler);
            if (cancelBtn && cancelClickHandler) cancelBtn.removeEventListener('click', cancelClickHandler);
            if (closeBtn && closeClickHandler) closeBtn.removeEventListener('click', closeClickHandler);
            if (modalElem && overlayClickHandler) modalElem.removeEventListener('click', overlayClickHandler);

            confirmClickHandler = () => {
                const ajaxUrl = `${jsBaseUrl}/ajax/close_ticket`;
                const formData = new FormData();
                formData.append('ticket_id', ticketIdToClose);
                fetch(ajaxUrl, { method: 'POST', body: formData })
                    .then(response => response.json())
                    .then(data => {
                        if (data.success) {
                            displayGeneralMessage('ticket-view-message', data.message || 'Tiket berhasil ditutup.', 'success', 3000);
                            loadTicketDetails(ticketIdToClose);
                        } else {
                            displayGeneralMessage('ticket-view-message', data.message || 'Gagal menutup tiket.', 'error');
                        }
                    })
                    .catch(error => {
                        console.error('Fetch Error (Close Ticket):', error);
                        displayGeneralMessage('ticket-view-message', 'Terjadi masalah koneksi.', 'error');
                    })
                    .finally(() => {
                         closeModal(modalElem, contentElem);
                    });
            };
            cancelClickHandler = () => closeModal(modalElem, contentElem);
            closeClickHandler = () => closeModal(modalElem, contentElem);
            overlayClickHandler = (event) => { if (event.target === modalElem) { closeModal(modalElem, contentElem); } };

            if (confirmBtn) confirmBtn.addEventListener('click', confirmClickHandler);
            else console.error(`Button with ID ${confirmBtnId} not found.`);
            if (cancelBtn) cancelBtn.addEventListener('click', cancelClickHandler);
            else console.error(`Button with ID ${cancelBtnId} not found.`);
            if (closeBtn) closeBtn.addEventListener('click', closeClickHandler);
            else console.error(`Button with ID ${closeBtnId} not found.`);
            if (modalElem) modalElem.addEventListener('click', overlayClickHandler);
        };

        if (!modalElement) {
            const modalHTML = createConfirmationModalHTML(
                uniqueModalIdSuffix,
                'Konfirmasi Penutupan Tiket',
                'Apakah Anda yakin ingin menutup tiket ini? Tiket yang ditutup tidak dapat dibalas lagi.',
                'Ya, Tutup Tiket',
                'Batal'
            );
            document.body.insertAdjacentHTML('beforeend', modalHTML);
            modalElement = document.getElementById(modalId);
            const modalContentElement = document.getElementById(modalContentId);
            if(modalElement && modalContentElement){
                 setupModalEventListeners(modalElement, modalContentElement);
                 openModal(modalElement, modalContentElement);
            } else {
                 console.error("Failed to find modal elements immediately after creation.");
            }
        } else {
             const modalContentElement = document.getElementById(modalContentId);
             if(modalElement && modalContentElement){
                 setupModalEventListeners(modalElement, modalContentElement);
                 openModal(modalElement, modalContentElement);
             } else {
                 console.error("Failed to find existing modal elements.");
             }
        }
    }
    // ========================================================
    // Logika untuk Halaman Pengaturan Profil
    // ========================================================
    const profileInfoForm = document.getElementById('profile-info-form');
    const passwordChangeForm = document.getElementById('password-change-form');
    const updateInfoButton = document.getElementById('update-info-button');
    const changePasswordButton = document.getElementById('change-password-button');
    const profileInfoMessageDiv = document.getElementById('profile-info-message');
    const passwordChangeMessageDiv = document.getElementById('password-change-message');

    function setupPasswordToggleProfile(button) {
        const targetInputId = button.dataset.target;
        if (!targetInputId) return;
        const passwordInput = document.getElementById(targetInputId);
        if (!passwordInput) return;

        const toggleIcon = button.querySelector('i');
        if (!toggleIcon) return;

        button.addEventListener('click', function () {
            const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password';
            passwordInput.setAttribute('type', type);
            toggleIcon.classList.toggle('fa-eye', type === 'password');
            toggleIcon.classList.toggle('fa-eye-slash', type === 'text');
        });
    }

    document.querySelectorAll('.password-toggle-btn').forEach(button => {
        setupPasswordToggleProfile(button);
    });

    if (profileInfoForm && updateInfoButton && profileInfoMessageDiv && jsBaseUrl) {
        const btnTextEl = document.getElementById('update-info-button-text');
        if(btnTextEl) updateInfoButton.dataset.originalText = btnTextEl.textContent;

        profileInfoForm.addEventListener('submit', function(event) {
            event.preventDefault();
            clearFieldErrors(profileInfoForm);
            displayGeneralMessage('profile-info-message', ''); 
            let isValid = true;
            const formData = new FormData(profileInfoForm);
            const phoneNumber = formData.get('phone_number')?.trim() ?? '';

            if (phoneNumber && !/^[0-9]{10,15}$/.test(phoneNumber)) {
                 isValid = false;
                 displayFieldError('phone_number', 'Format nomor handphone tidak valid (10-15 digit angka).');
            }

            if (!isValid) return;

            setButtonLoading('update-info-button', 'update-info-button-text', 'update-info-spinner', true, 'Menyimpan...');
            const ajaxUrl = `${jsBaseUrl}/ajax/update_profile_settings`;

            fetch(ajaxUrl, { method: 'POST', body: formData })
                .then(response => response.json()) 
                .then(data => {
                    if (data.success) {
                        displayGeneralMessage('profile-info-message', data.message || 'Informasi berhasil diperbarui.', 'success', 3000); 
                        const newFullName = formData.get('full_name');
                        const headerUserNameSpan = document.querySelector('#profile-button span');
                        if(headerUserNameSpan && newFullName !== null) {
                             headerUserNameSpan.textContent = newFullName || 'Pengguna';
                             const dropdownNameP = document.querySelector('#profile-dropdown .p-4 p.text-white');
                             if(dropdownNameP) dropdownNameP.textContent = newFullName || 'Pengguna';
                        }

                    } else {
                        displayGeneralMessage('profile-info-message', data.message || 'Gagal memperbarui informasi.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(field, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Update Info):', error);
                    displayGeneralMessage('profile-info-message', 'Terjadi masalah koneksi.', 'error');
                })
                .finally(() => {
                    setButtonLoading('update-info-button', 'update-info-button-text', 'update-info-spinner', false);
                });
        });
    }

    if (passwordChangeForm && changePasswordButton && passwordChangeMessageDiv && jsBaseUrl) {
         const btnTextEl = document.getElementById('change-password-button-text');
         if(btnTextEl) changePasswordButton.dataset.originalText = btnTextEl.textContent;

        passwordChangeForm.addEventListener('submit', function(event) {
            event.preventDefault();
            clearFieldErrors(passwordChangeForm);
            displayGeneralMessage('password-change-message', ''); 
            let isValid = true;
            const formData = new FormData(passwordChangeForm);
            const currentPassword = formData.get('current_password') ?? '';
            const newPassword = formData.get('new_password') ?? '';
            const confirmNewPassword = formData.get('confirm_new_password') ?? '';

            if (!currentPassword) { isValid = false; displayFieldError('current_password', 'Password saat ini wajib diisi.'); }
            if (!newPassword) { isValid = false; displayFieldError('new_password', 'Password baru wajib diisi.'); }
            else if (newPassword.length < 6) { isValid = false; displayFieldError('new_password', 'Password baru minimal 6 karakter.'); }
            if (!confirmNewPassword) { isValid = false; displayFieldError('confirm_new_password', 'Konfirmasi password baru wajib diisi.'); }
            else if (newPassword !== confirmNewPassword) { isValid = false; displayFieldError('confirm_new_password', 'Konfirmasi password baru tidak cocok.'); }

            if (!isValid) return;

            setButtonLoading('change-password-button', 'change-password-button-text', 'change-password-spinner', true, 'Mengganti...');
            const ajaxUrl = `${jsBaseUrl}/ajax/update_profile_settings`;

             fetch(ajaxUrl, { method: 'POST', body: formData })
                .then(response => response.json()) // Asumsikan server selalu return JSON
                .then(data => {
                    if (data.success) {
                        displayGeneralMessage('password-change-message', data.message || 'Password berhasil diganti.', 'success', 3000);
                        passwordChangeForm.reset(); // Kosongkan form setelah sukses
                    } else {
                        displayGeneralMessage('password-change-message', data.message || 'Gagal mengganti password.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(field, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Change Password):', error);
                    displayGeneralMessage('password-change-message', 'Terjadi masalah koneksi.', 'error');
                })
                .finally(() => {
                    setButtonLoading('change-password-button', 'change-password-button-text', 'change-password-spinner', false);
                });
        });
    }
    // ========================================================
    // Logika untuk Halaman Kelola Pengguna (Admin)
    // ========================================================
    const adminUsersTableBody = document.getElementById('admin-users-table-body');
    const adminUserFilterModalButton = document.getElementById('admin-user-filter-modal-button');
    const adminUserFilterModal = document.getElementById('admin-user-filter-modal');
    const adminUserFilterModalContent = document.getElementById('admin-user-filter-modal-content');
    const closeAdminUserFilterModalButton = document.getElementById('close-admin-user-filter-modal');
    const adminUserFilterForm = document.getElementById('admin-user-filter-form');
    const resetAdminUserFilterButton = document.getElementById('reset-admin-user-filter-button');
    const adminUsersPaginationInfo = document.getElementById('admin-users-pagination-info');
    const adminUsersPaginationControls = document.getElementById('admin-users-pagination-controls');
    const adminUsersMessageDiv = document.getElementById('admin-users-message');
    const addUserButton = document.getElementById('add-user-button');
    const editUserModal = document.getElementById('edit-user-modal');
    const deleteUserConfirmModal = document.getElementById('delete-user-confirm-modal');
    const deleteUserConfirmModalContent = document.getElementById('delete-user-confirm-modal-content');
    const deleteUserConfirmModalMessage = document.getElementById('delete-user-confirm-modal-message');
    const confirmDeleteUserButton = document.getElementById('confirm-delete-user-btn');
    const cancelDeleteUserButtons = document.querySelectorAll('.close-confirm-delete-btn');
    const addUserModal = document.getElementById('add-user-modal');
    const addUserModalContent = document.getElementById('add-user-modal-content');
    const closeAddUserModalButton = document.getElementById('close-add-user-modal');
    const cancelAddUserButton = document.getElementById('cancel-add-user-button');
    const addUserForm = document.getElementById('add-user-form');
    const saveAddUserButton = document.getElementById('save-add-user-button');
    const addUserMessageDiv = document.getElementById('add-user-message');
    const loginAsConfirmModal = document.getElementById('login-as-confirm-modal');
    const loginAsConfirmModalContent = document.getElementById('login-as-confirm-modal-content');
    const loginAsConfirmModalMessage = document.getElementById('login-as-confirm-modal-message');
    const confirmLoginAsButton = document.getElementById('confirm-login-as-btn');
    const cancelLoginAsButtons = document.querySelectorAll('.close-login-as-btn');
   

    if (adminUsersTableBody && adminUserFilterModalButton && adminUserFilterForm && jsBaseUrl) {
        let currentAdminUsersParams = { page: 1, limit: 10, status: 'all', role: 'all', sort_by: 'u.created_at', sort_type: 'DESC', search_column: 'u.id', search_keyword: '' };
        let currentAdminUsersData = [];

        function loadAdminUsers(params = {}) {
            adminUsersTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data pengguna...</td></tr>`;
            if(adminUsersPaginationInfo) adminUsersPaginationInfo.textContent = 'Memuat...';
            if(adminUsersPaginationControls) adminUsersPaginationControls.innerHTML = '';

            currentAdminUsersParams = { ...currentAdminUsersParams, ...params };
            const queryParams = new URLSearchParams(currentAdminUsersParams).toString();
            const url = `${jsBaseUrl}/ajax/get_admin_users?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.users && data.pagination) {
                        currentAdminUsersData = data.users;
                        renderAdminUserTable(data.users);
                        renderAdminUserPagination(data.pagination);
                         if (adminUsersMessageDiv && !adminUsersMessageDiv.innerHTML.includes('success')) {
                            adminUsersMessageDiv.innerHTML = '';
                            adminUsersMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        currentAdminUsersData = [];
                        adminUsersTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data pengguna.')}</td></tr>`;
                        if(adminUsersPaginationInfo) adminUsersPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminUsersPaginationControls) adminUsersPaginationControls.innerHTML = '';
                        if (!adminUsersMessageDiv || !adminUsersMessageDiv.innerHTML.includes('success')) {
                             displayGeneralMessage('admin-users-message', data.message || 'Gagal memuat data pengguna.', 'error');
                        }
                    }
                })
                .catch(error => {
                    currentAdminUsersData = [];
                    console.error('Fetch Error (Admin Users):', error);
                    adminUsersTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat pengguna.</td></tr>`;
                    if(adminUsersPaginationInfo) adminUsersPaginationInfo.textContent = 'Error koneksi.';
                    if(adminUsersPaginationControls) adminUsersPaginationControls.innerHTML = '';
                     if (!adminUsersMessageDiv || !adminUsersMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('admin-users-message', 'Error koneksi saat memuat pengguna.', 'error');
                     }
                });
        }

        function renderAdminUserTable(users) {
            adminUsersTableBody.innerHTML = '';
            if (users.length === 0) {
                adminUsersTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada pengguna yang cocok dengan filter.</td></tr>`;
                return;
            }
            users.forEach((user, index) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-sm');
                const formattedDateTime = formatLocalDate(user.created_at);
                let statusBadgeClass = 'bg-gray-100 text-gray-800';
                if (user.status === 'active') statusBadgeClass = 'bg-green-100 text-green-800';
                else if (user.status === 'inactive') statusBadgeClass = 'bg-yellow-100 text-yellow-800';
                else if (user.status === 'banned') statusBadgeClass = 'bg-red-100 text-red-800';

                let roleBadgeClass = 'bg-blue-100 text-blue-800';
                if (user.role === 'admin') roleBadgeClass = 'bg-purple-100 text-purple-800';

                row.innerHTML = `
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500">${escapeHTML(user.id)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-700 font-medium">${escapeHTML(user.username)}</td>
                    <td class="px-6 py-3 text-gray-600 max-w-xs truncate" title="${escapeHTML(user.email)}">${escapeHTML(user.email)}</td>
                    <td class="px-4 py-3 text-gray-600 max-w-xs truncate" title="${escapeHTML(user.full_name || '-')}">${escapeHTML(user.full_name || '-')}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-right text-green-700 font-semibold">Rp ${escapeHTML(user.balance?.toLocaleString('id-ID', {minimumFractionDigits: 0, maximumFractionDigits: 0}) ?? '0')}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${roleBadgeClass}">${escapeHTML(user.role ? user.role.charAt(0).toUpperCase() + user.role.slice(1) : 'N/A')}</span></td>
                    <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusBadgeClass}">${escapeHTML(user.status ? user.status.charAt(0).toUpperCase() + user.status.slice(1) : 'N/A')}</span></td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500 text-xs">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center text-base space-x-1">
                        <button type="button" class="admin-edit-user-btn text-blue-600 hover:text-blue-800 p-1 hover:bg-blue-100 rounded" data-user-index="${index}" title="Edit Pengguna"><i class="far fa-edit"></i></button>
                        <button type="button" class="admin-delete-user-btn text-red-600 hover:text-red-800 p-1 hover:bg-red-100 rounded" data-user-id="${escapeHTML(user.id)}" data-username="${escapeHTML(user.username)}" title="Hapus Pengguna"><i class="far fa-trash-alt"></i></button>
                        <button type="button" class="admin-login-as-btn text-green-600 hover:text-green-800 p-1 hover:bg-green-100 rounded" data-user-id="${escapeHTML(user.id)}" data-username="${escapeHTML(user.username)}" title="Login Sebagai User"><i class="fas fa-sign-in-alt"></i></button>
                    </td>
                `;
                adminUsersTableBody.appendChild(row);
            });
        }

        function renderAdminUserPagination(pagination) {
            if (!adminUsersPaginationControls || !adminUsersPaginationInfo) return;

            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                adminUsersPaginationInfo.textContent = 'Tidak ada data.';
                adminUsersPaginationControls.innerHTML = '';
                return;
            }

            adminUsersPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} pengguna. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminUsersPaginationControls.innerHTML = '';

            if (pagination.totalPages <= 1) return;

            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;

            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-user-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;

            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }

            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="admin-user-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }

            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="admin-user-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }

             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-user-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }

            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-user-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;

            adminUsersPaginationControls.innerHTML = paginationHTML;
        }

        if(adminUserFilterModalButton && adminUserFilterModal && closeAdminUserFilterModalButton && adminUserFilterModalContent) {
            adminUserFilterModalButton.addEventListener('click', () => {
                openModal(adminUserFilterModal, adminUserFilterModalContent);
            });
            closeAdminUserFilterModalButton.addEventListener('click', () => {
                closeModal(adminUserFilterModal, adminUserFilterModalContent);
            });
            adminUserFilterModal.addEventListener('click', (event) => {
                if (event.target === adminUserFilterModal) {
                    closeModal(adminUserFilterModal, adminUserFilterModalContent);
                }
            });
        }

        if(adminUserFilterForm) {
            adminUserFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(adminUserFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) {
                    newParams[key] = value;
                }
                newParams.page = 1;
                loadAdminUsers(newParams);
                closeModal(adminUserFilterModal, adminUserFilterModalContent);
            });
        }

        if(resetAdminUserFilterButton && adminUserFilterForm) {
            resetAdminUserFilterButton.addEventListener('click', () => {
                adminUserFilterForm.reset();
                document.getElementById('filter_limit_admin').value = '15';
                document.getElementById('filter_status_admin').value = 'all';
                document.getElementById('filter_role_admin').value = 'all';
                document.getElementById('filter_search_column_admin').value = 'u.id';
                document.getElementById('filter_sort_by_admin').value = 'u.created_at';
                document.getElementById('filter_sort_type_admin').value = 'DESC';
                adminUserFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        if(adminUsersPaginationControls) {
            adminUsersPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-user-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) {
                        loadAdminUsers({ page: pageToGo });
                    }
                }
            });
        }

        adminUsersTableBody.addEventListener('click', (event) => {
            const editButton = event.target.closest('.admin-edit-user-btn');
            const deleteButton = event.target.closest('.admin-delete-user-btn');
            const loginAsButton = event.target.closest('.admin-login-as-btn');

            if (editButton && editButton.dataset.userIndex) {
                const userIndex = parseInt(editButton.dataset.userIndex);
                openEditUserModal(userIndex);
            } else if (deleteButton && deleteButton.dataset.userId && deleteButton.dataset.username) {
                const userId = deleteButton.dataset.userId;
                const username = deleteButton.dataset.username;
                showDeleteUserConfirmationModal(userId, username);
            } else if (loginAsButton && loginAsButton.dataset.userId && loginAsButton.dataset.username) { 
                const userId = loginAsButton.dataset.userId;
                const username = loginAsButton.dataset.username; 
                showLoginAsConfirmationModal(userId, username); 
            }
        });

        function openEditUserModal(userIndex) {
            if (typeof userIndex === 'undefined' || !currentAdminUsersData[userIndex]) {
                console.error("Index pengguna tidak valid atau data tidak ditemukan.");
                return;
            }
            const user = currentAdminUsersData[userIndex];
            const editModalContent = document.getElementById('edit-user-modal-content');
            const editForm = document.getElementById('edit-user-form');

            if (!editUserModal || !editModalContent || !editForm) {
                 console.error("Elemen modal edit tidak ditemukan.");
                 return;
            }

            editForm.innerHTML = `
                <input type="hidden" id="edit_user_id" name="user_id" value="${escapeHTML(user.id)}">
                <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div>
                        <label for="edit_username" class="block text-sm font-medium text-gray-700 mb-1">Username</label>
                        <input type="text" id="edit_username" name="username" value="${escapeHTML(user.username)}" readonly disabled class="input-field w-full px-3 py-2 border border-gray-200 bg-gray-100 text-gray-500 rounded-lg sm:text-sm cursor-not-allowed">
                        <p class="text-xs text-gray-400 mt-1">Tidak dapat diubah</p>
                    </div>
                    <div>
                        <label for="edit_email" class="block text-sm font-medium text-gray-700 mb-1">Email</label>
                        <input type="email" id="edit_email" name="email" value="${escapeHTML(user.email)}" readonly disabled class="input-field w-full px-3 py-2 border border-gray-200 bg-gray-100 text-gray-500 rounded-lg sm:text-sm cursor-not-allowed">
                         <p class="text-xs text-gray-400 mt-1">Tidak dapat diubah</p>
                    </div>
                </div>
                 <div>
                    <label for="edit_full_name" class="block text-sm font-medium text-gray-700 mb-1">Nama Lengkap</label>
                    <input type="text" id="edit_full_name" name="full_name" value="${escapeHTML(user.full_name || '')}" class="input-field w-full px-3 py-2 border border-gray-300 rounded-lg sm:text-sm">
                </div>
                 <div>
                    <label for="edit_phone_number" class="block text-sm font-medium text-gray-700 mb-1">Nomor HP</label>
                    <input type="tel" id="edit_phone_number" name="phone_number" value="${escapeHTML(user.phone_number || '')}" class="input-field w-full px-3 py-2 border border-gray-300 rounded-lg sm:text-sm">
                </div>
                 <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div>
                        <label for="edit_balance" class="block text-sm font-medium text-gray-700 mb-1">Saldo</label>
                        <input type="number" step="0.01" id="edit_balance" name="balance" value="${escapeHTML(user.balance)}" class="input-field w-full px-3 py-2 border border-gray-300 rounded-lg sm:text-sm">
                    </div>
                     <div>
                        <label for="edit_role" class="block text-sm font-medium text-gray-700 mb-1">Peran</label>
                        <select id="edit_role" name="role" class="input-field w-full px-3 py-2 border border-gray-300 rounded-lg sm:text-sm bg-white">
                            <option value="member" ${user.role === 'member' ? 'selected' : ''}>Member</option>
                            <option value="admin" ${user.role === 'admin' ? 'selected' : ''}>Admin</option>
                            </select>
                    </div>
                </div>
                 <div>
                    <label for="edit_status" class="block text-sm font-medium text-gray-700 mb-1">Status</label>
                    <select id="edit_status" name="status" class="input-field w-full px-3 py-2 border border-gray-300 rounded-lg sm:text-sm bg-white">
                        <option value="active" ${user.status === 'active' ? 'selected' : ''}>Aktif</option>
                        <option value="inactive" ${user.status === 'inactive' ? 'selected' : ''}>Nonaktif</option>
                        <option value="banned" ${user.status === 'banned' ? 'selected' : ''}>Diblokir</option>
                    </select>
                </div>
                 <div>
                     <label for="edit_new_password" class="block text-sm font-medium text-gray-700 mb-1">Password Baru (Opsional)</label>
                     <input type="password" id="edit_new_password" name="new_password" placeholder="Kosongkan jika tidak ingin ganti" class="input-field w-full px-3 py-2 border border-gray-300 rounded-lg sm:text-sm">
                     <p class="text-xs text-gray-400 mt-1">Isi hanya jika Anda ingin mengubah password pengguna ini.</p>
                 </div>
                 <div id="edit-user-message" class="text-sm"></div>
            `;

            const cancelBtn = document.getElementById('cancel-edit-user-button');
            const closeBtn = document.getElementById('close-edit-user-modal');
            if(cancelBtn) cancelBtn.onclick = () => closeModal(editUserModal, editModalContent);
            if(closeBtn) closeBtn.onclick = () => closeModal(editUserModal, editModalContent);

            editForm.onsubmit = handleEditUserFormSubmit;

            openModal(editUserModal, editModalContent);
        }

        function handleEditUserFormSubmit(event) {
             event.preventDefault();
             const form = event.target;
             const formData = new FormData(form);
             const userId = formData.get('user_id');
             const messageDiv = document.getElementById('edit-user-message');
             const saveButton = document.getElementById('save-edit-user-button');

             if(messageDiv) messageDiv.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Menyimpan...';
             if(saveButton) saveButton.disabled = true;

             fetch(`${jsBaseUrl}/ajax/admin/update_user`, {
                 method: 'POST',
                 body: formData
             })
             .then(response => response.json())
             .then(data => {
                 if (data.success) {
                     displayGeneralMessage('admin-users-message', data.message || 'Pengguna berhasil diperbarui.', 'success', 3000);
                     closeModal(editUserModal, document.getElementById('edit-user-modal-content'));
                     loadAdminUsers(currentAdminUsersParams);
                 } else {
                      if(messageDiv) displayGeneralMessage('edit-user-message', data.message || 'Gagal menyimpan.', 'error');
                      if(data.errors){
                           for(const field in data.errors){
                               displayFieldError(`edit_${field}`, data.errors[field]);
                           }
                      }
                 }
             })
             .catch(error => {
                 if(messageDiv) displayGeneralMessage('edit-user-message', 'Error koneksi.', 'error');
                 console.error("Fetch error (Update User):", error);
             })
             .finally(() => {
                  if(saveButton) saveButton.disabled = false;
                  if(messageDiv && messageDiv.innerHTML.includes('spinner')) messageDiv.innerHTML = '';
             });
        }


        function showDeleteUserConfirmationModal(userId, username) {
            const modal = document.getElementById('delete-user-confirm-modal');
            const modalContent = document.getElementById('delete-user-confirm-modal-content');
            const modalMessage = document.getElementById('delete-user-confirm-modal-message');
            const confirmBtn = document.getElementById('confirm-delete-user-btn');
            const cancelBtns = document.querySelectorAll('.close-confirm-delete-btn');

            if (!modal || !modalContent || !modalMessage || !confirmBtn || cancelBtns.length === 0) {
                console.error("Elemen modal konfirmasi hapus atau tombolnya tidak ditemukan.");
                return;
            }

            modalMessage.innerHTML = `Apakah Anda yakin ingin menghapus pengguna <strong class="font-semibold text-gray-800">${escapeHTML(username)}</strong> (ID: ${escapeHTML(userId)})? <br><span class="text-red-600 font-medium">Tindakan ini tidak dapat diurungkan!</span>`;

            let confirmHandler;
            let cancelHandler;
            let overlayClickHandler;

            confirmHandler = () => {
                const idToDelete = userId;
                const nameToDelete = username;
                const confirmButtonOriginalHTML = confirmBtn.innerHTML;
                confirmBtn.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i> Menghapus...`;
                confirmBtn.disabled = true;
                cancelBtns.forEach(btn => btn.disabled = true);

                fetch(`${jsBaseUrl}/ajax/admin/delete_user`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({ user_id: idToDelete })
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        const successMessage = data.message || `Pengguna ${nameToDelete} berhasil dihapus.`;
                        loadAdminUsers(currentAdminUsersParams);
                        displayGeneralMessage('admin-users-message', successMessage, 'success', 4000);
                    } else {
                        displayGeneralMessage('admin-users-message', data.message || 'Gagal menghapus pengguna.', 'error');
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Delete User):', error);
                    displayGeneralMessage('admin-users-message', 'Error koneksi saat menghapus.', 'error');
                })
                .finally(() => {
                    confirmBtn.innerHTML = confirmButtonOriginalHTML;
                    confirmBtn.disabled = false;
                    cancelBtns.forEach(btn => btn.disabled = false);
                    closeModal(modal, modalContent);
                    confirmBtn.removeEventListener('click', confirmHandler);
                });
            };

            cancelHandler = () => {
                closeModal(modal, modalContent);
                confirmBtn.removeEventListener('click', confirmHandler);
                cancelBtns.forEach(btn => btn.removeEventListener('click', cancelHandler));
                modal.removeEventListener('click', overlayClickHandler);
            };

            overlayClickHandler = (event) => {
                 if (event.target === modal) {
                     cancelHandler();
                 }
             };

            const newConfirmBtn = confirmBtn.cloneNode(true);
            confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
            const confirmBtnUpdated = document.getElementById('confirm-delete-user-btn');
            confirmBtnUpdated.addEventListener('click', confirmHandler, { once: true });

            cancelBtns.forEach(btn => {
                const newCancelBtn = btn.cloneNode(true);
                btn.parentNode.replaceChild(newCancelBtn, btn);
                newCancelBtn.addEventListener('click', cancelHandler, { once: true });
            });

            modal.removeEventListener('click', overlayClickHandler);
            modal.addEventListener('click', overlayClickHandler);

            openModal(modal, modalContent);
        }

        function showLoginAsConfirmationModal(targetUserId, targetUsername) {
            const modal = document.getElementById('login-as-confirm-modal');
            const modalContent = document.getElementById('login-as-confirm-modal-content');
            const modalMessage = document.getElementById('login-as-confirm-modal-message');
            const confirmBtn = document.getElementById('confirm-login-as-btn');
            const cancelBtns = document.querySelectorAll('.close-login-as-btn');

            if (!modal || !modalContent || !modalMessage || !confirmBtn || cancelBtns.length === 0) {
                console.error("Elemen modal konfirmasi login as atau tombolnya tidak ditemukan.");
                alert("Terjadi kesalahan internal. Silakan coba lagi.");
                return;
            }

            modalMessage.innerHTML = `Anda akan login sebagai <strong class="font-semibold text-gray-800">${escapeHTML(targetUsername)}</strong> (ID: ${escapeHTML(targetUserId)}). Lanjutkan?`;

            let confirmHandler;
            let cancelHandler;
            let overlayClickHandler;

            confirmHandler = () => {
                const confirmButtonOriginalHTML = confirmBtn.innerHTML;
                confirmBtn.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i> Memproses...`;
                confirmBtn.disabled = true;
                cancelBtns.forEach(btn => btn.disabled = true);

                fetch(`${jsBaseUrl}/ajax/admin/login_as_user`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({ user_id: targetUserId })
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success && data.redirect_url) {
                        window.location.href = data.redirect_url; 
                    } else {
                        displayGeneralMessage('admin-users-message', data.message || 'Gagal login sebagai pengguna.', 'error');
                        closeModal(modal, modalContent); 
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Login As User):', error);
                    displayGeneralMessage('admin-users-message', 'Error koneksi saat mencoba login sebagai pengguna.', 'error');
                    closeModal(modal, modalContent);
                })
                .finally(() => {
                    if (!(confirmBtn.disabled && window.location.href !== data.redirect_url)) { 
                         confirmBtn.innerHTML = confirmButtonOriginalHTML;
                         confirmBtn.disabled = false;
                         cancelBtns.forEach(btn => btn.disabled = false);
                    }
                    confirmBtn.removeEventListener('click', confirmHandler);
                });
            };

            cancelHandler = () => {
                closeModal(modal, modalContent);
                confirmBtn.removeEventListener('click', confirmHandler);
                cancelBtns.forEach(btn => btn.removeEventListener('click', cancelHandler));
                modal.removeEventListener('click', overlayClickHandler);
            };

             overlayClickHandler = (event) => {
                 if (event.target === modal) {
                     cancelHandler();
                 }
             };

            const newConfirmBtn = confirmBtn.cloneNode(true);
            confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
            const confirmBtnUpdated = document.getElementById('confirm-login-as-btn');
            confirmBtnUpdated.addEventListener('click', confirmHandler, { once: true });

            cancelBtns.forEach(btn => {
                const newCancelBtn = btn.cloneNode(true);
                btn.parentNode.replaceChild(newCancelBtn, btn);
                newCancelBtn.addEventListener('click', cancelHandler, { once: true });
            });

            modal.removeEventListener('click', overlayClickHandler);
            modal.addEventListener('click', overlayClickHandler);

            openModal(modal, modalContent);
        }
        // --- Akhir Fungsi Login As ---


        // --- Logika untuk Tambah Pengguna ---
        const addUserModal = document.getElementById('add-user-modal');
        const addUserModalContent = document.getElementById('add-user-modal-content');
        const closeAddUserModalButton = document.getElementById('close-add-user-modal');
        const cancelAddUserButton = document.getElementById('cancel-add-user-button');
        const addUserForm = document.getElementById('add-user-form');
        const saveAddUserButton = document.getElementById('save-add-user-button');
        const addUserMessageDiv = document.getElementById('add-user-message');

        if (addUserButton && addUserModal && addUserModalContent && closeAddUserModalButton && cancelAddUserButton && addUserForm && saveAddUserButton) {
            addUserButton.addEventListener('click', () => {
                addUserForm.reset();
                clearFieldErrors(addUserForm);
                if(addUserMessageDiv) addUserMessageDiv.innerHTML = '';
                openModal(addUserModal, addUserModalContent);
            });

            closeAddUserModalButton.addEventListener('click', () => {
                closeModal(addUserModal, addUserModalContent);
            });
            cancelAddUserButton.addEventListener('click', () => {
                 closeModal(addUserModal, addUserModalContent);
            });
             addUserModal.addEventListener('click', (event) => {
                 if (event.target === addUserModal) {
                     closeModal(addUserModal, addUserModalContent);
                 }
             });

            addUserForm.addEventListener('submit', (event) => {
                event.preventDefault();
                clearFieldErrors(addUserForm);
                if(addUserMessageDiv) addUserMessageDiv.innerHTML = '';
                const formData = new FormData(addUserForm);

                const saveButtonText = saveAddUserButton.querySelector('span'); // Asumsi ada span di dalam tombol
                const originalButtonText = saveButtonText ? saveButtonText.textContent : 'Tambah Pengguna';
                if(saveButtonText) saveButtonText.textContent = 'Menyimpan...';
                saveAddUserButton.disabled = true;


                fetch(`${jsBaseUrl}/ajax/admin/add_user`, {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        closeModal(addUserModal, addUserModalContent);
                        displayGeneralMessage('admin-users-message', data.message || 'Pengguna baru berhasil ditambahkan.', 'success', 4000);
                        loadAdminUsers({ page: 1 });
                    } else {
                        if(addUserMessageDiv) displayGeneralMessage('add-user-message', data.message || 'Gagal menambahkan pengguna.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(`add_${field}`, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Add User):', error);
                    if(addUserMessageDiv) displayGeneralMessage('add-user-message', 'Terjadi masalah koneksi.', 'error');
                })
                .finally(() => {
                    if(saveButtonText) saveButtonText.textContent = originalButtonText;
                    saveAddUserButton.disabled = false;
                });
            });
        }
        // --- Akhir Logika Tambah Pengguna ---


        loadAdminUsers(currentAdminUsersParams);
    }

    const adminOrdersTableBody = document.getElementById('admin-orders-table-body');
    const adminOrderFilterModalButton = document.getElementById('admin-order-filter-modal-button');
    const adminOrderFilterModal = document.getElementById('admin-order-filter-modal');
    const adminOrderFilterModalContent = document.getElementById('admin-order-filter-modal-content');
    const closeAdminOrderFilterModalButton = document.getElementById('close-admin-order-filter-modal');
    const adminOrderFilterForm = document.getElementById('admin-order-filter-form');
    const resetAdminOrderFilterButton = document.getElementById('reset-admin-order-filter-button');
    const adminOrdersPaginationInfo = document.getElementById('admin-orders-pagination-info');
    const adminOrdersPaginationControls = document.getElementById('admin-orders-pagination-controls');
    const adminOrdersMessageDiv = document.getElementById('admin-orders-message');
    const editOrderModal = document.getElementById('edit-order-modal');
    const editOrderModalContent = document.getElementById('edit-order-modal-content');
    const editOrderForm = document.getElementById('edit-order-form');
    const editOrderIdSpan = document.getElementById('edit-order-id-span');
    const closeEditOrderModalButton = document.getElementById('close-edit-order-modal');
    const cancelEditOrderButton = document.getElementById('cancel-edit-order-button');
    const saveEditOrderButton = document.getElementById('save-edit-order-button');
    const editOrderMessageDiv = document.getElementById('edit-order-message');

    const adminOrderDetailModal = document.getElementById('admin-order-detail-modal');
    const adminOrderDetailModalContent = document.getElementById('admin-order-detail-modal-content');
    const adminOrderDetailModalTitleText = document.getElementById('admin-order-detail-modal-title-text');
    const adminOrderDetailModalBody = document.getElementById('admin-order-detail-modal-body');
    const closeAdminOrderDetailModalButton = document.getElementById('close-admin-order-detail-modal');
    const closeAdminOrderDetailModalFooterButton = document.getElementById('close-admin-order-detail-modal-footer');


    if (adminOrdersTableBody && adminOrderFilterModalButton && adminOrderFilterForm && jsBaseUrl) {
        let currentAdminOrdersParams = { page: 1, limit: 15, status: 'all', sort_by: 'o.created_at', sort_type: 'DESC', search_column: 'o.id', search_keyword: '', date_start: '', date_end: '', user_id: '', service_id: '' };
        let currentAdminOrdersData = [];

        function loadAdminOrders(params = {}) {
            adminOrdersTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-24 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data pesanan...</td></tr>`;
            if(adminOrdersPaginationInfo) adminOrdersPaginationInfo.textContent = 'Memuat...';
            if(adminOrdersPaginationControls) adminOrdersPaginationControls.innerHTML = '';
            if(adminOrdersMessageDiv && !adminOrdersMessageDiv.innerHTML.includes('success')) {
                 adminOrdersMessageDiv.innerHTML = '';
                 adminOrdersMessageDiv.className = 'mb-4 text-sm';
            }

            currentAdminOrdersParams = { ...currentAdminOrdersParams, ...params };
            const queryParams = new URLSearchParams(currentAdminOrdersParams).toString();
            const url = `${jsBaseUrl}/ajax/admin/get_admin_orders?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.orders && data.pagination) {
                        currentAdminOrdersData = data.orders;
                        renderAdminOrderTable(data.orders);
                        renderAdminOrderPagination(data.pagination);
                         if (adminOrdersMessageDiv && !adminOrdersMessageDiv.innerHTML.includes('success')) {
                             adminOrdersMessageDiv.innerHTML = '';
                             adminOrdersMessageDiv.className = 'mb-4 text-sm';
                         }
                    } else {
                        currentAdminOrdersData = [];
                        adminOrdersTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-24 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data pesanan.')}</td></tr>`;
                        if(adminOrdersPaginationInfo) adminOrdersPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminOrdersPaginationControls) adminOrdersPaginationControls.innerHTML = '';
                        if (!adminOrdersMessageDiv || !adminOrdersMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('admin-orders-message', data.message || 'Gagal memuat data pesanan.', 'error');
                        }
                    }
                })
                .catch(error => {
                    currentAdminOrdersData = [];
                    console.error('Fetch Error (Admin Orders):', error);
                    adminOrdersTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-24 text-center text-sm text-red-500 italic">Error koneksi saat memuat pesanan.</td></tr>`;
                    if(adminOrdersPaginationInfo) adminOrdersPaginationInfo.textContent = 'Error koneksi.';
                    if(adminOrdersPaginationControls) adminOrdersPaginationControls.innerHTML = '';
                    if (!adminOrdersMessageDiv || !adminOrdersMessageDiv.innerHTML.includes('success')) {
                         displayGeneralMessage('admin-orders-message', 'Error koneksi saat memuat pesanan.', 'error');
                    }
                });
        }

        function renderAdminOrderTable(orders) {
            adminOrdersTableBody.innerHTML = '';
            if (orders.length === 0) {
                adminOrdersTableBody.innerHTML = `<tr><td colspan="9" class="px-6 py-24 text-center text-sm text-gray-500 italic">Tidak ada pesanan yang cocok dengan filter.</td></tr>`;
                return;
            }
            orders.forEach((order, index) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-sm');
                const formattedDateTime = formatLocalDate(order.created_at);
                const statusBadgeClass = getStatusBadgeClass(order.status);

                row.innerHTML = `
                    <td class="px-4 py-3 whitespace-nowrap text-gray-700 font-medium">#${escapeHTML(order.id)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-600" title="${escapeHTML(order.username)}">${escapeHTML(order.username)} (ID: ${escapeHTML(order.user_id)})</td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500 text-xs">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-6 py-3 text-gray-700 max-w-xs truncate" title="${escapeHTML(order.service_name)} (ID Layanan: ${escapeHTML(order.service_id)})">${escapeHTML(order.service_name)}</td>
                    <td class="px-4 py-3 text-gray-600 max-w-[150px] truncate" title="${escapeHTML(order.target)}">${escapeHTML(order.target)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-right text-gray-600">${escapeHTML(order.quantity?.toLocaleString('id-ID') ?? 'N/A')}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-right text-gray-800 font-medium">Rp ${escapeHTML(order.price?.toLocaleString('id-ID', {minimumFractionDigits: 0, maximumFractionDigits: 0}) ?? 'N/A')}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2.5 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusBadgeClass}">${escapeHTML(order.status ? order.status.charAt(0).toUpperCase() + order.status.slice(1) : 'N/A')}</span></td>
                    <td class="px-4 py-3 whitespace-nowrap text-center text-base space-x-2">
                         <button type="button" class="admin-order-detail-view-btn text-teal-600 hover:text-teal-800 p-1 hover:bg-teal-100 rounded" data-order-index="${index}" title="Lihat Detail Pesanan"><i class="far fa-eye"></i></button>
                         <button type="button" class="admin-edit-order-btn text-blue-600 hover:text-blue-800 p-1 hover:bg-blue-100 rounded" data-order-index="${index}" title="Edit Pesanan"><i class="far fa-edit"></i></button>
                    </td>
                `;
                adminOrdersTableBody.appendChild(row);
            });
        }

        function renderAdminOrderPagination(pagination) {
             if (!adminOrdersPaginationControls || !adminOrdersPaginationInfo) {
                 console.warn("Pagination controls or info element not found.");
                 return;
             }

            if (!pagination || typeof pagination.totalItems === 'undefined' || typeof pagination.totalPages === 'undefined' || typeof pagination.currentPage === 'undefined' || typeof pagination.limit === 'undefined' || typeof pagination.offset === 'undefined') {
                adminOrdersPaginationInfo.textContent = 'Informasi halaman tidak tersedia.';
                adminOrdersPaginationControls.innerHTML = '';
                return;
            }

            adminOrdersPaginationInfo.textContent = `Menampilkan ${pagination.totalItems > 0 ? pagination.offset + 1 : 0} sampai ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} pesanan. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminOrdersPaginationControls.innerHTML = '';

            if (pagination.totalPages <= 1) {
                return;
            }

            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;

            paginationHTML += `
                <button type="button" data-page="${currentPage - 1}"
                        class="admin-order-pagination-link px-3 py-1 border rounded transition-colors
                               ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}"
                        ${currentPage <= 1 ? 'disabled' : ''}>
                    &laquo; Sebelumnya
                </button>`;

            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);

            if (endPage === totalPages && totalPages >= maxPagesToShow) {
                startPage = Math.max(1, totalPages - maxPagesToShow + 1);
            }

            if (startPage > 1) {
                paginationHTML += `
                    <button type="button" data-page="1"
                            class="admin-order-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">
                        1
                    </button>`;
                if (startPage > 2) {
                    paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`;
                }
            }

            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `
                    <button type="button" data-page="${i}"
                            class="admin-order-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">
                        ${i}
                    </button>`;
            }

            if (endPage < totalPages) {
                if (endPage < totalPages - 1) {
                    paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`;
                }
                paginationHTML += `
                    <button type="button" data-page="${totalPages}"
                            class="admin-order-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">
                        ${totalPages}
                    </button>`;
            }

            paginationHTML += `
                <button type="button" data-page="${currentPage + 1}"
                        class="admin-order-pagination-link px-3 py-1 border rounded transition-colors
                               ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}"
                        ${currentPage >= totalPages ? 'disabled' : ''}>
                    Berikutnya &raquo;
                </button>`;

            adminOrdersPaginationControls.innerHTML = paginationHTML;
        }

        if(adminOrderFilterModalButton && adminOrderFilterModal && closeAdminOrderFilterModalButton && adminOrderFilterModalContent) {
            adminOrderFilterModalButton.addEventListener('click', () => { openModal(adminOrderFilterModal, adminOrderFilterModalContent); });
            closeAdminOrderFilterModalButton.addEventListener('click', () => { closeModal(adminOrderFilterModal, adminOrderFilterModalContent); });
            adminOrderFilterModal.addEventListener('click', (event) => { if (event.target === adminOrderFilterModal) { closeModal(adminOrderFilterModal, adminOrderFilterModalContent); } });
        }

        if(adminOrderFilterForm) {
            adminOrderFilterForm.addEventListener('submit', (event) => { event.preventDefault(); const formData = new FormData(adminOrderFilterForm); const newParams = {}; for (const [key, value] of formData.entries()) { newParams[key] = value; } newParams.page = 1; loadAdminOrders(newParams); closeModal(adminOrderFilterModal, adminOrderFilterModalContent); });
        }

        if(resetAdminOrderFilterButton && adminOrderFilterForm) {
            resetAdminOrderFilterButton.addEventListener('click', () => { adminOrderFilterForm.reset(); document.getElementById('filter_limit_admin_order').value = '15'; document.getElementById('filter_status_admin_order').value = 'all'; document.getElementById('filter_user_id_admin_order').value = ''; document.getElementById('filter_service_id_admin_order').value = ''; document.getElementById('filter_date_start_admin_order').value = ''; document.getElementById('filter_date_end_admin_order').value = ''; document.getElementById('filter_search_column_admin_order').value = 'o.id'; document.getElementById('filter_search_keyword_admin_order').value = ''; document.getElementById('filter_sort_by_admin_order').value = 'o.created_at'; document.getElementById('filter_sort_type_admin_order').value = 'DESC'; adminOrderFilterForm.dispatchEvent(new Event('submit', { cancelable: true })); });
        }

        if(adminOrdersPaginationControls) {
            adminOrdersPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-order-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) {
                        loadAdminOrders({ page: pageToGo });
                    }
                }
            });
        }

        function openAdminOrderDetailModal(orderIndex) {
            if (typeof orderIndex === 'undefined' || !currentAdminOrdersData[orderIndex]) {
                console.error("Indeks pesanan tidak valid atau data tidak ditemukan untuk detail.");
                return;
            }
            const order = currentAdminOrdersData[orderIndex];
            if (!adminOrderDetailModal || !adminOrderDetailModalBody || !adminOrderDetailModalTitleText) {
                console.error("Elemen modal detail pesanan admin tidak ditemukan.");
                return;
            }

            adminOrderDetailModalTitleText.querySelector('#detail-admin-order-id').textContent = escapeHTML(order.id);

            let detailHTML = '<div class="space-y-3">'; // Main container for all details

            // Helper function to create a detail item (label and value pair)
            function createDetailItem(label, value, isCode = false, fullWidthValue = false) {
                const valueClass = isCode ? 'font-mono bg-gray-700 px-2 py-1 rounded text-gray-200 break-all text-xs' : 'text-gray-100';
                const labelClass = 'text-gray-400 font-medium col-span-4 sm:col-span-1'; // Label takes 1/3 on sm and up
                const valueContainerClass = fullWidthValue ? 'col-span-4 sm:col-span-3' : 'col-span-4 sm:col-span-2'; // Value takes 2/3 or full on sm and up

                return `
                    <div class="grid grid-cols-4 sm:grid-cols-3 gap-x-2 items-start py-1.5 border-b border-gray-700 last:border-b-0">
                        <dt class="${labelClass}">${escapeHTML(label)}</dt>
                        <dd class="${valueContainerClass} ${valueClass}">${escapeHTML(value || '-')}</dd>
                    </div>`;
            }
            
            function createDetailItemRaw(label, valueHTML, fullWidthValue = false) {
                const labelClass = 'text-gray-400 font-medium col-span-4 sm:col-span-1';
                const valueContainerClass = fullWidthValue ? 'col-span-4 sm:col-span-3' : 'col-span-4 sm:col-span-2';
                 return `
                    <div class="grid grid-cols-4 sm:grid-cols-3 gap-x-2 items-center py-1.5 border-b border-gray-700 last:border-b-0">
                        <dt class="${labelClass}">${escapeHTML(label)}</dt>
                        <dd class="${valueContainerClass} text-gray-100">${valueHTML}</dd>
                    </div>`;
            }


            detailHTML += createDetailItem('ID Pesanan Lokal:', order.id);
            detailHTML += createDetailItem('Pengguna:', `${order.username} (ID: ${order.user_id})`);
            detailHTML += createDetailItem('Layanan:', `${order.service_name} (ID: ${order.service_id})`, false, true);
            detailHTML += createDetailItem('Kategori:', order.category_name);
            detailHTML += createDetailItem('Provider:', `${order.provider_name || 'N/A'} (ID: ${order.provider_id || 'N/A'})`);
            detailHTML += createDetailItem('ID Layanan Provider:', order.provider_service_id);
            detailHTML += createDetailItem('Target:', order.target, true, true);
            detailHTML += createDetailItem('Jumlah Dipesan:', order.quantity?.toLocaleString('id-ID'));
            detailHTML += createDetailItem('Harga:', `Rp ${order.price?.toLocaleString('id-ID', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`);
            detailHTML += createDetailItemRaw('Status:', `<span class="px-2 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${getStatusBadgeClass(order.status)}">${escapeHTML(order.status ? order.status.charAt(0).toUpperCase() + order.status.slice(1) : 'N/A')}</span>`);
            detailHTML += createDetailItem('Jumlah Awal:', order.start_count?.toLocaleString('id-ID'));
            detailHTML += createDetailItem('Sisa:', order.remains?.toLocaleString('id-ID'));
            detailHTML += createDetailItem('Sumber Pesanan:', order.order_source ? order.order_source.toUpperCase() : 'WEB');
            detailHTML += createDetailItem('ID Pesanan API:', order.api_order_id);
            detailHTML += createDetailItem('Tanggal Dibuat:', formatLocalDate(order.created_at));
            detailHTML += createDetailItem('Terakhir Diperbarui:', formatLocalDate(order.updated_at));

            detailHTML += '</div>'; // Close main container

            if (order.service_note) {
                detailHTML += `<div class="mt-4 pt-3 border-t border-gray-700"><h4 class="text-gray-400 font-medium mb-1.5 text-xs uppercase tracking-wider">Catatan Layanan:</h4><div class="prose prose-sm prose-invert max-w-none text-gray-300 bg-gray-750 p-3 rounded-md text-xs leading-relaxed">${escapeHTML(order.service_note).replace(/\n/g, '<br>')}</div></div>`;
            }
            if (order.api_response) {
                detailHTML += `<div class="mt-4 pt-3 border-t border-gray-700"><h4 class="text-gray-400 font-medium mb-1.5 text-xs uppercase tracking-wider">Respons API Terakhir:</h4><pre class="bg-gray-900 text-xs text-gray-300 p-3 rounded-md overflow-x-auto max-h-40 custom-scrollbar">${escapeHTML(order.api_response)}</pre></div>`;
            }


            adminOrderDetailModalBody.innerHTML = detailHTML;
            openModal(adminOrderDetailModal, adminOrderDetailModalContent);
        }


        adminOrdersTableBody.addEventListener('click', (event) => {
             const editButton = event.target.closest('.admin-edit-order-btn');
             const detailButton = event.target.closest('.admin-order-detail-view-btn');

             if (editButton && editButton.dataset.orderIndex) {
                 const orderIndex = parseInt(editButton.dataset.orderIndex);
                 openEditOrderModal(orderIndex);
             } else if (detailButton && detailButton.dataset.orderIndex) {
                const orderIndex = parseInt(detailButton.dataset.orderIndex);
                openAdminOrderDetailModal(orderIndex);
            }
        });

        function openEditOrderModal(orderIndex) {
             if (typeof orderIndex === 'undefined' || !currentAdminOrdersData[orderIndex]) { console.error("Index pesanan tidak valid atau data tidak ditemukan."); return; } const order = currentAdminOrdersData[orderIndex]; if (!editOrderModal || !editOrderModalContent || !editOrderForm || !editOrderIdSpan) { console.error("Elemen modal edit pesanan tidak ditemukan."); return; } editOrderIdSpan.textContent = escapeHTML(order.id); editOrderForm.elements['order_id'].value = order.id; editOrderForm.elements['status'].value = order.status || ''; editOrderForm.elements['start_count'].value = order.start_count ?? ''; editOrderForm.elements['remains'].value = order.remains ?? ''; if(editOrderMessageDiv) editOrderMessageDiv.innerHTML = ''; clearFieldErrors(editOrderForm); openModal(editOrderModal, editOrderModalContent);
        }

        if(closeEditOrderModalButton) {
             closeEditOrderModalButton.addEventListener('click', () => closeModal(editOrderModal, editOrderModalContent));
        }
        if(cancelEditOrderButton) {
             cancelEditOrderButton.addEventListener('click', () => closeModal(editOrderModal, editOrderModalContent));
        }
        if(editOrderModal) {
             editOrderModal.addEventListener('click', (event) => { if (event.target === editOrderModal) { closeModal(editOrderModal, editOrderModalContent); } });
        }

        if(closeAdminOrderDetailModalButton) {
            closeAdminOrderDetailModalButton.addEventListener('click', () => closeModal(adminOrderDetailModal, adminOrderDetailModalContent));
        }
        if(closeAdminOrderDetailModalFooterButton) {
            closeAdminOrderDetailModalFooterButton.addEventListener('click', () => closeModal(adminOrderDetailModal, adminOrderDetailModalContent));
        }
        if(adminOrderDetailModal) {
            adminOrderDetailModal.addEventListener('click', (event) => { if (event.target === adminOrderDetailModal) { closeModal(adminOrderDetailModal, adminOrderDetailModalContent); } });
        }


        if(editOrderForm && saveEditOrderButton) {
             editOrderForm.addEventListener('submit', (event) => { event.preventDefault(); clearFieldErrors(editOrderForm); if(editOrderMessageDiv) editOrderMessageDiv.innerHTML = ''; const formData = new FormData(editOrderForm); const saveButtonText = saveEditOrderButton.querySelector('span'); const originalButtonText = saveButtonText ? saveButtonText.textContent : saveEditOrderButton.textContent; if(saveButtonText) saveButtonText.textContent = 'Menyimpan...'; else saveEditOrderButton.textContent = 'Menyimpan...'; saveEditOrderButton.disabled = true; fetch(`${jsBaseUrl}/ajax/admin/update_order`, { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { closeModal(editOrderModal, editOrderModalContent); displayGeneralMessage('admin-orders-message', data.message || 'Pesanan berhasil diperbarui.', 'success', 3000); loadAdminOrders(currentAdminOrdersParams); } else { if(editOrderMessageDiv) displayGeneralMessage('edit-order-message', data.message || 'Gagal memperbarui pesanan.', 'error'); if (data.errors) { for (const field in data.errors) { displayFieldError(`edit_order_${field}`, data.errors[field]); } } } }) .catch(error => { console.error('Fetch Error (Update Order):', error); if(editOrderMessageDiv) displayGeneralMessage('edit-order-message', 'Terjadi masalah koneksi.', 'error'); }) .finally(() => { if(saveButtonText) saveButtonText.textContent = originalButtonText; else saveEditOrderButton.textContent = originalButtonText; saveEditOrderButton.disabled = false; }); });
        }

        const initialAdminOrderUrlParams = new URLSearchParams(window.location.search);
        const initialAdminOrderParams = {};
        initialAdminOrderUrlParams.forEach((value, key) => {
             initialAdminOrderParams[key] = value;
             if(adminOrderFilterForm && adminOrderFilterForm.elements[key]) {
                 adminOrderFilterForm.elements[key].value = value;
             }
        });
        currentAdminOrdersParams = { ...currentAdminOrdersParams, ...initialAdminOrderParams };
         if(adminOrderFilterForm) {
             for (const key in currentAdminOrdersParams) {
                 if(adminOrderFilterForm.elements[key]) {
                     adminOrderFilterForm.elements[key].value = currentAdminOrdersParams[key];
                 }
             }
         }
        loadAdminOrders(currentAdminOrdersParams);
    }

    const adminInformationsTableBody = document.getElementById('admin-informations-table-body');
    const adminInfoFilterModalButton = document.getElementById('admin-info-filter-modal-button');
    const adminInfoFilterModal = document.getElementById('admin-info-filter-modal');
    const adminInfoFilterModalContent = document.getElementById('admin-info-filter-modal-content');
    const closeAdminInfoFilterModalButton = document.getElementById('close-admin-info-filter-modal');
    const adminInfoFilterForm = document.getElementById('admin-info-filter-form');
    const resetAdminInfoFilterButton = document.getElementById('reset-admin-info-filter-button');
    const adminInformationsPaginationInfo = document.getElementById('admin-informations-pagination-info');
    const adminInformationsPaginationControls = document.getElementById('admin-informations-pagination-controls');
    const adminInformationsMessageDiv = document.getElementById('admin-informations-message');
    const addInfoButton = document.getElementById('add-info-button');
    const addEditInfoModal = document.getElementById('add-edit-info-modal');
    const addEditInfoModalContent = document.getElementById('add-edit-info-modal-content');
    const addEditInfoModalTitle = document.getElementById('add-edit-info-modal-title');
    const closeAddEditInfoModalButton = document.getElementById('close-add-edit-info-modal');
    const cancelAddEditInfoButton = document.getElementById('cancel-add-edit-info-button');
    const addEditInfoForm = document.getElementById('add-edit-info-form');
    const saveAddEditInfoButton = document.getElementById('save-add-edit-info-button');
    const addEditInfoMessageDiv = document.getElementById('add-edit-info-message');
    const deleteInfoConfirmModal = document.getElementById('delete-info-confirm-modal');
    const deleteInfoConfirmModalContent = document.getElementById('delete-info-confirm-modal-content');
    const deleteInfoConfirmModalMessage = document.getElementById('delete-info-confirm-modal-message');
    const confirmDeleteInfoButton = document.getElementById('confirm-delete-info-btn');
    const cancelDeleteInfoButtons = document.querySelectorAll('.close-confirm-delete-info-btn');
    const infoIdInput = document.getElementById('info_id');
    const infoTitleInput = document.getElementById('info_title');
    const infoContentInput = document.getElementById('info_content');
    const infoStatusSelect = document.getElementById('info_status');
    const infoImageInput = document.getElementById('info_image');
    const infoImagePreviewContainer = document.getElementById('info-image-preview-container');
    const infoImagePreview = document.getElementById('info-image-preview');
    const removeInfoImageBtn = document.getElementById('remove-info-image-btn');
    const removeImageFlagInput = document.getElementById('remove_image_flag');

    if (adminInformationsTableBody && adminInfoFilterModalButton && adminInfoFilterForm && jsBaseUrl) {
        let currentAdminInfoParams = { page: 1, limit: 15, status: 'all', sort_by: 'created_at', sort_type: 'DESC', search_column: 'id', search_keyword: '' };
        let currentAdminInfoData = [];

        function loadAdminInformations(params = {}) {
            adminInformationsTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data informasi...</td></tr>`;
            if(adminInformationsPaginationInfo) adminInformationsPaginationInfo.textContent = 'Memuat...';
            if(adminInformationsPaginationControls) adminInformationsPaginationControls.innerHTML = '';
            if(adminInformationsMessageDiv && !adminInformationsMessageDiv.innerHTML.includes('success')) {
                adminInformationsMessageDiv.innerHTML = '';
                adminInformationsMessageDiv.className = 'mb-4 text-sm';
            }

            currentAdminInfoParams = { ...currentAdminInfoParams, ...params };
            const queryParams = new URLSearchParams(currentAdminInfoParams).toString();
            const url = `${jsBaseUrl}/ajax/admin/get_admin_informations?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.informations && data.pagination) {
                        currentAdminInfoData = data.informations;
                        renderAdminInfoTable(data.informations);
                        renderAdminInfoPagination(data.pagination);
                        if (adminInformationsMessageDiv && !adminInformationsMessageDiv.innerHTML.includes('success')) {
                            adminInformationsMessageDiv.innerHTML = '';
                            adminInformationsMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        currentAdminInfoData = [];
                        adminInformationsTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data informasi.')}</td></tr>`;
                        if(adminInformationsPaginationInfo) adminInformationsPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminInformationsPaginationControls) adminInformationsPaginationControls.innerHTML = '';
                         if (!adminInformationsMessageDiv || !adminInformationsMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('admin-informations-message', data.message || 'Gagal memuat data informasi.', 'error');
                         }
                    }
                })
                .catch(error => {
                    currentAdminInfoData = [];
                    console.error('Fetch Error (Admin Informations):', error);
                    adminInformationsTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat informasi.</td></tr>`;
                    if(adminInformationsPaginationInfo) adminInformationsPaginationInfo.textContent = 'Error koneksi.';
                    if(adminInformationsPaginationControls) adminInformationsPaginationControls.innerHTML = '';
                     if (!adminInformationsMessageDiv || !adminInformationsMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('admin-informations-message', 'Error koneksi saat memuat informasi.', 'error');
                     }
                });
        }

        function renderAdminInfoTable(informations) {
            adminInformationsTableBody.innerHTML = '';
            if (informations.length === 0) {
                adminInformationsTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada informasi yang cocok dengan filter.</td></tr>`;
                return;
            }
            informations.forEach((info, index) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-sm');
                const formattedDateTime = formatLocalDate(info.created_at);
                let statusBadgeClass = 'bg-gray-100 text-gray-800';
                if (info.status === 'active') statusBadgeClass = 'bg-green-100 text-green-800';
                else if (info.status === 'inactive') statusBadgeClass = 'bg-yellow-100 text-yellow-800';
                const contentSnippet = info.content_snippet || (info.content ? info.content.substring(0, 100) + (info.content.length > 100 ? '...' : '') : '');

                row.innerHTML = `
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500">${escapeHTML(info.id)}</td>
                    <td class="px-6 py-3 text-gray-800 font-medium max-w-xs truncate" title="${escapeHTML(info.title)}">${escapeHTML(info.title)}</td>
                    <td class="px-6 py-3 text-gray-600 max-w-md truncate" title="${escapeHTML(info.content || '')}">${escapeHTML(contentSnippet)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2.5 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusBadgeClass}">${escapeHTML(info.status ? info.status.charAt(0).toUpperCase() + info.status.slice(1) : 'N/A')}</span></td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500 text-xs">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center text-base space-x-1">
                        <button type="button" class="admin-edit-info-btn text-blue-600 hover:text-blue-800 p-1 hover:bg-blue-100 rounded" data-info-index="${index}" title="Edit Informasi"><i class="far fa-edit"></i></button>
                        <button type="button" class="admin-delete-info-btn text-red-600 hover:text-red-800 p-1 hover:bg-red-100 rounded" data-info-id="${escapeHTML(info.id)}" data-info-title="${escapeHTML(info.title)}" title="Hapus Informasi"><i class="far fa-trash-alt"></i></button>
                    </td>
                `;
                adminInformationsTableBody.appendChild(row);
            });
        }

        function renderAdminInfoPagination(pagination) {
             if (!adminInformationsPaginationControls || !adminInformationsPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                adminInformationsPaginationInfo.textContent = 'Tidak ada data.';
                adminInformationsPaginationControls.innerHTML = '';
                return;
            }
            adminInformationsPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} informasi. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminInformationsPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;
            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;
            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-info-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;
            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }
            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="admin-info-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="admin-info-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }
             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-info-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-info-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
            adminInformationsPaginationControls.innerHTML = paginationHTML;
        }

        if(adminInfoFilterModalButton && adminInfoFilterModal && closeAdminInfoFilterModalButton && adminInfoFilterModalContent) {
            adminInfoFilterModalButton.addEventListener('click', () => { openModal(adminInfoFilterModal, adminInfoFilterModalContent); });
            closeAdminInfoFilterModalButton.addEventListener('click', () => { closeModal(adminInfoFilterModal, adminInfoFilterModalContent); });
            adminInfoFilterModal.addEventListener('click', (event) => { if (event.target === adminInfoFilterModal) { closeModal(adminInfoFilterModal, adminInfoFilterModalContent); } });
        }

        if(adminInfoFilterForm) {
            adminInfoFilterForm.addEventListener('submit', (event) => { event.preventDefault(); const formData = new FormData(adminInfoFilterForm); const newParams = {}; for (const [key, value] of formData.entries()) { newParams[key] = value; } newParams.page = 1; loadAdminInformations(newParams); closeModal(adminInfoFilterModal, adminInfoFilterModalContent); });
        }

        if(resetAdminInfoFilterButton && adminInfoFilterForm) {
            resetAdminInfoFilterButton.addEventListener('click', () => { adminInfoFilterForm.reset(); document.getElementById('filter_limit_admin_info').value = '15'; document.getElementById('filter_status_admin_info').value = 'all'; document.getElementById('filter_search_column_admin_info').value = 'id'; document.getElementById('filter_sort_by_admin_info').value = 'created_at'; document.getElementById('filter_sort_type_admin_info').value = 'DESC'; adminInfoFilterForm.dispatchEvent(new Event('submit', { cancelable: true })); });
        }

        if(adminInformationsPaginationControls) {
            adminInformationsPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-info-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) {
                        loadAdminInformations({ page: pageToGo });
                    }
                }
            });
        }

        adminInformationsTableBody.addEventListener('click', (event) => {
            const editButton = event.target.closest('.admin-edit-info-btn');
            const deleteButton = event.target.closest('.admin-delete-info-btn');

            if (editButton && editButton.dataset.infoIndex) {
                const infoIndex = parseInt(editButton.dataset.infoIndex);
                openAddEditInfoModal(infoIndex);
            } else if (deleteButton && deleteButton.dataset.infoId && deleteButton.dataset.infoTitle) {
                const infoId = deleteButton.dataset.infoId;
                const infoTitle = deleteButton.dataset.infoTitle;
                showDeleteInfoConfirmationModal(infoId, infoTitle);
            }
        });

        function openAddEditInfoModal(infoIndex = null) {
            if (!addEditInfoModal || !addEditInfoModalContent || !addEditInfoForm || !addEditInfoModalTitle || !infoIdInput || !infoTitleInput || !infoContentInput || !infoStatusSelect || !addEditInfoMessageDiv || !infoImageInput || !infoImagePreviewContainer || !infoImagePreview || !removeInfoImageBtn || !removeImageFlagInput) {
                console.error("Elemen modal tambah/edit informasi atau elemen gambar tidak ditemukan.");
                return;
            }

            addEditInfoForm.reset();
            clearFieldErrors(addEditInfoForm);
            addEditInfoMessageDiv.innerHTML = '';
            infoImagePreview.src = '#';
            infoImagePreviewContainer.classList.add('hidden');
            removeImageFlagInput.value = '0';

            if (infoIndex !== null && currentAdminInfoData[infoIndex]) {
                const info = currentAdminInfoData[infoIndex];
                addEditInfoModalTitle.innerHTML = `<i class="fas fa-edit mr-3 text-blue-500"></i> Edit Informasi`;
                infoIdInput.value = info.id;
                infoTitleInput.value = info.title || '';
                infoContentInput.value = info.content || '';
                infoStatusSelect.value = info.status || 'active';
                saveAddEditInfoButton.textContent = 'Simpan Perubahan';

                if (info.image_url) {
                    infoImagePreview.src = info.image_url;
                    infoImagePreviewContainer.classList.remove('hidden');
                }

            } else {
                addEditInfoModalTitle.innerHTML = `<i class="fas fa-plus-circle mr-3 text-green-500"></i> Tambah Informasi Baru`;
                infoIdInput.value = '';
                saveAddEditInfoButton.textContent = 'Simpan Informasi';
            }

            openModal(addEditInfoModal, addEditInfoModalContent);
        }

        if (infoImageInput && infoImagePreview && infoImagePreviewContainer && removeImageFlagInput) {
            infoImageInput.addEventListener('change', function(event) {
                const file = event.target.files[0];
                if (file && file.type.startsWith('image/')) {
                    const reader = new FileReader();
                    reader.onload = function(e) {
                        infoImagePreview.src = e.target.result;
                        infoImagePreviewContainer.classList.remove('hidden');
                        removeImageFlagInput.value = '0';
                    }
                    reader.readAsDataURL(file);
                } else {
                    infoImagePreview.src = '#';
                    infoImagePreviewContainer.classList.add('hidden');
                }
            });
        }

        if (removeInfoImageBtn && infoImageInput && infoImagePreview && infoImagePreviewContainer && removeImageFlagInput) {
            removeInfoImageBtn.addEventListener('click', function() {
                infoImageInput.value = '';
                infoImagePreview.src = '#';
                infoImagePreviewContainer.classList.add('hidden');
                removeImageFlagInput.value = '1';
            });
        }


        if(addInfoButton) {
            addInfoButton.addEventListener('click', () => openAddEditInfoModal(null));
        }
        if(closeAddEditInfoModalButton) {
            closeAddEditInfoModalButton.addEventListener('click', () => closeModal(addEditInfoModal, addEditInfoModalContent));
        }
        if(cancelAddEditInfoButton) {
            cancelAddEditInfoButton.addEventListener('click', () => closeModal(addEditInfoModal, addEditInfoModalContent));
        }
        if(addEditInfoModal) {
            addEditInfoModal.addEventListener('click', (event) => { if (event.target === addEditInfoModal) { closeModal(addEditInfoModal, addEditInfoModalContent); } });
        }

        if(addEditInfoForm && saveAddEditInfoButton) {
            addEditInfoForm.addEventListener('submit', (event) => {
                event.preventDefault();
                clearFieldErrors(addEditInfoForm);
                if(addEditInfoMessageDiv) addEditInfoMessageDiv.innerHTML = '';
                const formData = new FormData(addEditInfoForm);
                const infoId = formData.get('info_id');
                const isEditing = !!infoId;
                const ajaxUrl = isEditing ? `${jsBaseUrl}/ajax/admin/update_information` : `${jsBaseUrl}/ajax/admin/add_information`;

                const originalButtonText = saveAddEditInfoButton.textContent;
                saveAddEditInfoButton.textContent = 'Menyimpan...';
                saveAddEditInfoButton.disabled = true;

                fetch(ajaxUrl, {
                    method: 'POST',
                    body: formData
                })
                .then(response => {
                    const contentType = response.headers.get("content-type");
                    if (contentType && contentType.indexOf("application/json") !== -1) {
                        return response.json();
                    } else {
                        return response.text().then(text => {
                             console.error("Server Response (Not JSON):", text);
                             let errorMsg = `Server mengembalikan respons non-JSON (Status: ${response.status}). Cek log PHP.`;
                             if (text.toLowerCase().includes('fatal error')) {
                                 errorMsg += ' Terjadi kesalahan fatal di server. Cek log PHP.';
                             } else if (text.toLowerCase().includes('warning') || text.toLowerCase().includes('notice')) {
                                 errorMsg += ' Server menghasilkan warning/notice. Cek log PHP.';
                             }
                             throw new Error(errorMsg);
                        });
                    }
                })
                .then(data => {
                    if (data.success) {
                        closeModal(addEditInfoModal, addEditInfoModalContent);
                        displayGeneralMessage('admin-informations-message', data.message || `Informasi berhasil ${isEditing ? 'diperbarui' : 'ditambahkan'}.`, 'success', 3000);
                        loadAdminInformations(currentAdminInfoParams);
                    } else {
                        if(addEditInfoMessageDiv) displayGeneralMessage('add-edit-info-message', data.message || 'Gagal menyimpan.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(field, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error(`Fetch Error (${isEditing ? 'Update' : 'Add'} Info):`, error);
                    if(addEditInfoMessageDiv) displayGeneralMessage('add-edit-info-message', `Terjadi masalah: ${error.message}.`, 'error');
                })
                .finally(() => {
                    saveAddEditInfoButton.textContent = originalButtonText;
                    saveAddEditInfoButton.disabled = false;
                });
            });
        }

        function showDeleteInfoConfirmationModal(infoId, infoTitle) {
            const modal = document.getElementById('delete-info-confirm-modal');
            const modalContent = document.getElementById('delete-info-confirm-modal-content');
            const modalMessage = document.getElementById('delete-info-confirm-modal-message');
            const confirmBtn = document.getElementById('confirm-delete-info-btn');
            const cancelBtns = document.querySelectorAll('.close-confirm-delete-info-btn');

            if (!modal || !modalContent || !modalMessage || !confirmBtn || cancelBtns.length === 0) {
                console.error("Elemen modal konfirmasi hapus informasi atau tombolnya tidak ditemukan.");
                return;
            }

            modalMessage.innerHTML = `Apakah Anda yakin ingin menghapus informasi berjudul <strong class="font-semibold text-gray-800">"${escapeHTML(infoTitle)}"</strong> (ID: ${escapeHTML(infoId)})?`;

            let confirmHandler;
            let cancelHandler;
            let overlayClickHandler;

            confirmHandler = () => {
                const idToDelete = infoId;
                const titleToDelete = infoTitle;
                const confirmButtonOriginalHTML = confirmBtn.innerHTML;
                confirmBtn.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i> Menghapus...`;
                confirmBtn.disabled = true;
                cancelBtns.forEach(btn => btn.disabled = true);

                fetch(`${jsBaseUrl}/ajax/admin/delete_information`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
                    body: JSON.stringify({ info_id: idToDelete })
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        loadAdminInformations(currentAdminInfoParams);
                        displayGeneralMessage('admin-informations-message', data.message || `Informasi "${titleToDelete}" berhasil dihapus.`, 'success', 4000);
                    } else {
                        displayGeneralMessage('admin-informations-message', data.message || 'Gagal menghapus informasi.', 'error');
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Delete Info):', error);
                    displayGeneralMessage('admin-informations-message', 'Error koneksi saat menghapus.', 'error');
                })
                .finally(() => {
                    confirmBtn.innerHTML = confirmButtonOriginalHTML;
                    confirmBtn.disabled = false;
                    cancelBtns.forEach(btn => btn.disabled = false);
                    closeModal(modal, modalContent);
                    confirmBtn.removeEventListener('click', confirmHandler);
                });
            };

            cancelHandler = () => {
                closeModal(modal, modalContent);
                confirmBtn.removeEventListener('click', confirmHandler);
                cancelBtns.forEach(btn => btn.removeEventListener('click', cancelHandler));
                modal.removeEventListener('click', overlayClickHandler);
            };

             overlayClickHandler = (event) => {
                 if (event.target === modal) {
                     cancelHandler();
                 }
             };

            const newConfirmBtn = confirmBtn.cloneNode(true);
            confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
            const confirmBtnUpdated = document.getElementById('confirm-delete-info-btn');
            confirmBtnUpdated.addEventListener('click', confirmHandler, { once: true });

            cancelBtns.forEach(btn => {
                const newCancelBtn = btn.cloneNode(true);
                btn.parentNode.replaceChild(newCancelBtn, btn);
                newCancelBtn.addEventListener('click', cancelHandler, { once: true });
            });

            modal.removeEventListener('click', overlayClickHandler);
            modal.addEventListener('click', overlayClickHandler);

            openModal(modal, modalContent);
        }

        loadAdminInformations(currentAdminInfoParams);
    }

    // ========================================================
    // Logika untuk Modal Detail Informasi di Dashboard
    // ========================================================
    const informationContainer = document.getElementById('information-container');
    const infoDetailModal = document.getElementById('info-detail-modal');
    const infoDetailModalContent = document.getElementById('info-detail-modal-content');
    const infoDetailModalTitle = document.getElementById('info-detail-modal-title');
    const infoDetailModalBody = document.getElementById('info-detail-modal-body');
    const closeInfoDetailModalButton = document.getElementById('close-info-detail-modal');
    const closeInfoDetailModalFooterButton = document.getElementById('close-info-detail-modal-footer');

    if (informationContainer && infoDetailModal && infoDetailModalContent && infoDetailModalTitle && infoDetailModalBody && closeInfoDetailModalButton && closeInfoDetailModalFooterButton) {

        function openInfoDetail(event) {
            const button = event.target.closest('.open-info-detail-btn');
            if (!button) {
                return; 
            }

            const title = button.dataset.infoTitle || 'Detail Informasi';
            const content = button.dataset.infoContent || '<p>Konten tidak tersedia.</p>';
            const imageUrl = button.dataset.infoImage || '';
            const placeholderUrl = "https://placehold.co/600x300/374151/9ca3af?text=Info";
            const imageOnError = `this.onerror=null; this.src='${placeholderUrl}';`;

            infoDetailModalTitle.innerHTML = `<i class="fas fa-info-circle mr-2 text-cyan-400"></i> ${escapeHTML(title)}`;

            let modalBodyHTML = '';

            if (imageUrl) {
                modalBodyHTML += `
                    <div class="mb-4 rounded-lg overflow-hidden shadow-md">
                        <img src="${escapeHTML(imageUrl)}"
                             alt="${escapeHTML(title)}"
                             class="w-full h-auto max-h-60 object-cover"
                             onerror="${imageOnError}">
                    </div>
                `;
            }

            modalBodyHTML += `
                <div class="prose prose-sm prose-invert max-w-none text-gray-300 leading-relaxed">
                    ${content.replace(/\n/g, '<br>')}
                </div>
            `;

            infoDetailModalBody.innerHTML = modalBodyHTML;

            openModal(infoDetailModal, infoDetailModalContent);
        }

        function closeInfoDetail() {
            closeModal(infoDetailModal, infoDetailModalContent);
        }

        informationContainer.addEventListener('click', openInfoDetail);

        closeInfoDetailModalButton.addEventListener('click', closeInfoDetail);
        closeInfoDetailModalFooterButton.addEventListener('click', closeInfoDetail);

        infoDetailModal.addEventListener('click', (event) => {
            if (event.target === infoDetailModal) {
                closeInfoDetail();
            }
        });
    }

    // ========================================================
        // Logika untuk Halaman Kelola Tiket (Admin)
        // ========================================================
        const adminTicketsTableBody = document.getElementById('admin-tickets-table-body');
        const adminTicketFilterModalButton = document.getElementById('admin-ticket-filter-modal-button');
        const adminTicketFilterModal = document.getElementById('admin-ticket-filter-modal');
        const adminTicketFilterModalContent = document.getElementById('admin-ticket-filter-modal-content');
        const closeAdminTicketFilterModalButton = document.getElementById('close-admin-ticket-filter-modal');
        const adminTicketFilterForm = document.getElementById('admin-ticket-filter-form');
        const resetAdminTicketFilterButton = document.getElementById('reset-admin-ticket-filter-button');
        const adminTicketsPaginationInfo = document.getElementById('admin-tickets-pagination-info');
        const adminTicketsPaginationControls = document.getElementById('admin-tickets-pagination-controls');
        const adminTicketsMessageDiv = document.getElementById('admin-tickets-message');

        if (adminTicketsTableBody && adminTicketFilterModalButton && adminTicketFilterForm && jsBaseUrl) {
            let currentAdminTicketsParams = { page: 1, limit: 15, status: 'all', user_id: '', unread: 'all', sort_by: 't.updated_at', sort_type: 'DESC', search_column: 't.ticket_id', search_keyword: '' };
            let currentAdminTicketsData = [];

            function loadAdminTickets(params = {}) {
                adminTicketsTableBody.innerHTML = `<tr><td colspan="7" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data tiket...</td></tr>`;
                if(adminTicketsPaginationInfo) adminTicketsPaginationInfo.textContent = 'Memuat...';
                if(adminTicketsPaginationControls) adminTicketsPaginationControls.innerHTML = '';
                if(adminTicketsMessageDiv && !adminTicketsMessageDiv.innerHTML.includes('success')) {
                    adminTicketsMessageDiv.innerHTML = '';
                    adminTicketsMessageDiv.className = 'mb-4 text-sm';
                }

                currentAdminTicketsParams = { ...currentAdminTicketsParams, ...params };
                const queryParams = new URLSearchParams(currentAdminTicketsParams).toString();
                const url = `${jsBaseUrl}/ajax/admin/get_admin_tickets?${queryParams}`;

                fetch(url)
                    .then(response => {
                        if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                        return response.json();
                    })
                    .then(data => {
                        if (data.success && data.tickets && data.pagination) {
                            currentAdminTicketsData = data.tickets;
                            renderAdminTicketTable(data.tickets);
                            renderAdminTicketPagination(data.pagination);
                            if (adminTicketsMessageDiv && !adminTicketsMessageDiv.innerHTML.includes('success')) {
                                adminTicketsMessageDiv.innerHTML = '';
                                adminTicketsMessageDiv.className = 'mb-4 text-sm';
                            }
                        } else {
                            currentAdminTicketsData = [];
                            adminTicketsTableBody.innerHTML = `<tr><td colspan="7" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data tiket.')}</td></tr>`;
                            if(adminTicketsPaginationInfo) adminTicketsPaginationInfo.textContent = 'Gagal memuat data.';
                            if(adminTicketsPaginationControls) adminTicketsPaginationControls.innerHTML = '';
                            if (!adminTicketsMessageDiv || !adminTicketsMessageDiv.innerHTML.includes('success')) {
                                displayGeneralMessage('admin-tickets-message', data.message || 'Gagal memuat data tiket.', 'error');
                            }
                        }
                    })
                    .catch(error => {
                        currentAdminTicketsData = [];
                        console.error('Fetch Error (Admin Tickets):', error);
                        adminTicketsTableBody.innerHTML = `<tr><td colspan="7" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat tiket.</td></tr>`;
                        if(adminTicketsPaginationInfo) adminTicketsPaginationInfo.textContent = 'Error koneksi.';
                        if(adminTicketsPaginationControls) adminTicketsPaginationControls.innerHTML = '';
                        if (!adminTicketsMessageDiv || !adminTicketsMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('admin-tickets-message', 'Error koneksi saat memuat tiket.', 'error');
                        }
                    });
            }

            function renderAdminTicketTable(tickets) {
                adminTicketsTableBody.innerHTML = '';
                if (tickets.length === 0) {
                    adminTicketsTableBody.innerHTML = `<tr><td colspan="7" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada tiket yang cocok dengan filter.</td></tr>`;
                    return;
                }
                tickets.forEach((ticket, index) => {
                    const row = document.createElement('tr');
                    row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-sm');
                    const formattedDateTime = formatLocalDate(ticket.updated_at);
                    const statusClass = getTicketStatusBadgeClass(ticket.status);
                    const unreadClass = ticket.is_read_admin == 0 ? 'bg-red-100 text-red-800 font-semibold' : 'bg-gray-100 text-gray-600';
                    const unreadText = ticket.is_read_admin == 0 ? 'Belum Dibaca' : 'Sudah Dibaca';

                    row.innerHTML = `
                        <td class="px-4 py-3 whitespace-nowrap text-gray-500">${escapeHTML(ticket.ticket_id)}</td>
                        <td class="px-4 py-3 whitespace-nowrap text-gray-600" title="${escapeHTML(ticket.username)}">${escapeHTML(ticket.username)} (ID: ${escapeHTML(ticket.user_id)})</td>
                        <td class="px-6 py-3 text-gray-800 font-medium max-w-xs truncate" title="${escapeHTML(ticket.subject)}">${escapeHTML(ticket.subject)}</td>
                        <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2.5 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass}">${escapeHTML(ticket.status.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase()))}</span></td>
                        <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2 py-0.5 inline-flex text-xs leading-5 rounded-full ${unreadClass}">${unreadText}</span></td>
                        <td class="px-4 py-3 whitespace-nowrap text-gray-500 text-xs">${escapeHTML(formattedDateTime)}</td>
                        <td class="px-4 py-3 whitespace-nowrap text-center">
                            <a href="${jsBaseUrl}/tickets/view/${escapeHTML(ticket.ticket_id)}" class="text-blue-600 hover:text-blue-800 hover:underline text-xs font-medium">Lihat/Balas</a>
                        </td>
                    `;
                    adminTicketsTableBody.appendChild(row);
                });
            }

            function renderAdminTicketPagination(pagination) {
                if (!adminTicketsPaginationControls || !adminTicketsPaginationInfo) return;
                if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                    adminTicketsPaginationInfo.textContent = 'Tidak ada data.';
                    adminTicketsPaginationControls.innerHTML = '';
                    return;
                }
                adminTicketsPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} tiket. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
                adminTicketsPaginationControls.innerHTML = '';
                if (pagination.totalPages <= 1) return;
                let paginationHTML = '';
                const currentPage = pagination.currentPage;
                const totalPages = pagination.totalPages;
                paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-ticket-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;
                const maxPagesToShow = 5;
                let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
                let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
                if(endPage === totalPages) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }
                if (startPage > 1) {
                    paginationHTML += `<button type="button" data-page="1" class="admin-ticket-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                    if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                }
                for (let i = startPage; i <= endPage; i++) {
                    const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                    paginationHTML += `<button type="button" data-page="${i}" class="admin-ticket-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
                }
                 if (endPage < totalPages) {
                    if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                    paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-ticket-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
                }
                paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-ticket-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
                adminTicketsPaginationControls.innerHTML = paginationHTML;
            }

            if(adminTicketFilterModalButton && adminTicketFilterModal && closeAdminTicketFilterModalButton && adminTicketFilterModalContent) {
                adminTicketFilterModalButton.addEventListener('click', () => openModal(adminTicketFilterModal, adminTicketFilterModalContent));
                closeAdminTicketFilterModalButton.addEventListener('click', () => closeModal(adminTicketFilterModal, adminTicketFilterModalContent));
                adminTicketFilterModal.addEventListener('click', (event) => { if (event.target === adminTicketFilterModal) closeModal(adminTicketFilterModal, adminTicketFilterModalContent); });
            }

            if(adminTicketFilterForm) {
                adminTicketFilterForm.addEventListener('submit', (event) => {
                    event.preventDefault();
                    const formData = new FormData(adminTicketFilterForm);
                    const newParams = {};
                    for (const [key, value] of formData.entries()) {
                        newParams[key] = value;
                    }
                    newParams.page = 1; 
                    loadAdminTickets(newParams);
                    closeModal(adminTicketFilterModal, adminTicketFilterModalContent);
                });
            }

            if(resetAdminTicketFilterButton && adminTicketFilterForm) {
                resetAdminTicketFilterButton.addEventListener('click', () => {
                    adminTicketFilterForm.reset();
                    document.getElementById('filter_limit_admin_ticket').value = '15';
                    document.getElementById('filter_status_admin_ticket').value = 'all';
                    document.getElementById('filter_user_id_admin_ticket').value = '';
                    document.getElementById('filter_unread_admin_ticket').value = 'all';
                    document.getElementById('filter_search_column_admin_ticket').value = 't.ticket_id';
                    document.getElementById('filter_search_keyword_admin_ticket').value = '';
                    document.getElementById('filter_sort_by_admin_ticket').value = 't.updated_at';
                    document.getElementById('filter_sort_type_admin_ticket').value = 'DESC';
                    adminTicketFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
                });
            }

            if(adminTicketsPaginationControls) {
                adminTicketsPaginationControls.addEventListener('click', (event) => {
                    const targetButton = event.target.closest('.admin-ticket-pagination-link');
                    if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                        const pageToGo = parseInt(targetButton.dataset.page);
                        if (!isNaN(pageToGo)) {
                            loadAdminTickets({ page: pageToGo });
                        }
                    }
                });
            }

             const initialAdminTicketUrlParams = new URLSearchParams(window.location.search);
             const initialAdminTicketParams = {};
             initialAdminTicketUrlParams.forEach((value, key) => {
                 initialAdminTicketParams[key] = value;
                 if(adminTicketFilterForm && adminTicketFilterForm.elements[key]) {
                     adminTicketFilterForm.elements[key].value = value;
                 }
             });
             currentAdminTicketsParams = { ...currentAdminTicketsParams, ...initialAdminTicketParams };
              if(adminTicketFilterForm) {
                  for (const key in currentAdminTicketsParams) {
                      if(adminTicketFilterForm.elements[key]) {
                          adminTicketFilterForm.elements[key].value = currentAdminTicketsParams[key];
                      }
                  }
              }
            loadAdminTickets(currentAdminTicketsParams);
        }
        // ========================================================
    // Logika untuk Halaman Kelola Kategori (Admin)
    // ========================================================
    const adminCategoriesTableBody = document.getElementById('admin-categories-table-body');
    const adminCategoryFilterForm = document.getElementById('admin-category-filter-form');
    const addCategoryButton = document.getElementById('add-category-button');
    const addEditCategoryModal = document.getElementById('add-edit-category-modal');

    if (adminCategoriesTableBody && adminCategoryFilterForm && addCategoryButton && addEditCategoryModal) {
        const adminCategoryFilterModalButton = document.getElementById('admin-category-filter-modal-button');
        const adminCategoryFilterModal = document.getElementById('admin-category-filter-modal');
        const adminCategoryFilterModalContent = document.getElementById('admin-category-filter-modal-content');
        const closeAdminCategoryFilterModalButton = document.getElementById('close-admin-category-filter-modal');
        const resetAdminCategoryFilterButton = document.getElementById('reset-admin-category-filter-button');
        const adminCategoriesPaginationInfo = document.getElementById('admin-categories-pagination-info');
        const adminCategoriesPaginationControls = document.getElementById('admin-categories-pagination-controls');
        const adminCategoriesMessageDiv = document.getElementById('admin-categories-message');
        const addEditCategoryModalContent = document.getElementById('add-edit-category-modal-content');
        const addEditCategoryModalTitle = document.getElementById('add-edit-category-modal-title');
        const closeAddEditCategoryModalButton = document.getElementById('close-add-edit-category-modal');
        const cancelAddEditCategoryButton = document.getElementById('cancel-add-edit-category-button');
        const addEditCategoryForm = document.getElementById('add-edit-category-form');
        const saveAddEditCategoryButton = document.getElementById('save-add-edit-category-button');
        const addEditCategoryMessageDiv = document.getElementById('add-edit-category-message');
        const categoryIdInput = document.getElementById('category_id');
        const categoryNameInput = document.getElementById('category_name');
        const categoryIconInput = document.getElementById('category_icon_class');
        const categoryStatusSelect = document.getElementById('category_status');
        const deleteCategoryConfirmModal = document.getElementById('delete-category-confirm-modal');
        const deleteCategoryConfirmModalContent = document.getElementById('delete-category-confirm-modal-content');
        const deleteCategoryConfirmModalMessage = document.getElementById('delete-category-confirm-modal-message');
        const confirmDeleteCategoryButton = document.getElementById('confirm-delete-category-btn');
        const cancelDeleteCategoryButtons = document.querySelectorAll('.close-confirm-delete-category-btn');

        let currentAdminCategoryParams = { page: 1, limit: 15, status: 'all', sort_by: 'name', sort_type: 'ASC', search_column: 'name', search_keyword: '' };
        let currentAdminCategoryData = [];

        function loadAdminCategories(params = {}) {
            adminCategoriesTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data kategori...</td></tr>`;
            if(adminCategoriesPaginationInfo) adminCategoriesPaginationInfo.textContent = 'Memuat...';
            if(adminCategoriesPaginationControls) adminCategoriesPaginationControls.innerHTML = '';
            if(adminCategoriesMessageDiv && !adminCategoriesMessageDiv.innerHTML.includes('success')) {
                adminCategoriesMessageDiv.innerHTML = '';
                adminCategoriesMessageDiv.className = 'mb-4 text-sm';
            }

            currentAdminCategoryParams = { ...currentAdminCategoryParams, ...params };
            const queryParams = new URLSearchParams(currentAdminCategoryParams).toString();
            const url = `${jsBaseUrl}/ajax/admin/get_admin_categories?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.categories && data.pagination) {
                        currentAdminCategoryData = data.categories;
                        renderAdminCategoryTable(data.categories);
                        renderAdminCategoryPagination(data.pagination);
                         if (adminCategoriesMessageDiv && !adminCategoriesMessageDiv.innerHTML.includes('success')) {
                            adminCategoriesMessageDiv.innerHTML = '';
                            adminCategoriesMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        currentAdminCategoryData = [];
                        adminCategoriesTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data kategori.')}</td></tr>`;
                        if(adminCategoriesPaginationInfo) adminCategoriesPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminCategoriesPaginationControls) adminCategoriesPaginationControls.innerHTML = '';
                        if (!adminCategoriesMessageDiv || !adminCategoriesMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('admin-categories-message', data.message || 'Gagal memuat data kategori.', 'error');
                        }
                    }
                })
                .catch(error => {
                    currentAdminCategoryData = [];
                    console.error('Fetch Error (Admin Categories):', error);
                    adminCategoriesTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat kategori.</td></tr>`;
                    if(adminCategoriesPaginationInfo) adminCategoriesPaginationInfo.textContent = 'Error koneksi.';
                    if(adminCategoriesPaginationControls) adminCategoriesPaginationControls.innerHTML = '';
                     if (!adminCategoriesMessageDiv || !adminCategoriesMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('admin-categories-message', 'Error koneksi saat memuat kategori.', 'error');
                     }
                });
        }

        function renderAdminCategoryTable(categories) {
            adminCategoriesTableBody.innerHTML = '';
            if (categories.length === 0) {
                adminCategoriesTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada kategori yang cocok dengan filter.</td></tr>`;
                return;
            }
            categories.forEach((category, index) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-sm');
                const formattedDateTime = formatLocalDate(category.created_at);
                const statusBadgeClass = getStatusBadgeClass(category.status);
                const iconHtml = category.icon_class ? `<i class="${escapeHTML(category.icon_class)} text-indigo-600 text-lg"></i>` : `<i class="fas fa-tag text-gray-400 text-lg"></i>`;

                row.innerHTML = `
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500">${escapeHTML(category.id)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center">${iconHtml}</td>
                    <td class="px-6 py-3 text-gray-800 font-medium">${escapeHTML(category.name)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2.5 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusBadgeClass}">${escapeHTML(category.status ? category.status.charAt(0).toUpperCase() + category.status.slice(1) : 'N/A')}</span></td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500 text-xs">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center text-base space-x-1">
                        <button type="button" class="admin-edit-category-btn text-blue-600 hover:text-blue-800 p-1 hover:bg-blue-100 rounded" data-category-index="${index}" title="Edit Kategori"><i class="far fa-edit"></i></button>
                        <button type="button" class="admin-delete-category-btn text-red-600 hover:text-red-800 p-1 hover:bg-red-100 rounded" data-category-id="${escapeHTML(category.id)}" data-category-name="${escapeHTML(category.name)}" title="Hapus Kategori"><i class="far fa-trash-alt"></i></button>
                    </td>
                `;
                adminCategoriesTableBody.appendChild(row);
            });
        }

        function renderAdminCategoryPagination(pagination) {
             if (!adminCategoriesPaginationControls || !adminCategoriesPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                adminCategoriesPaginationInfo.textContent = 'Tidak ada data.';
                adminCategoriesPaginationControls.innerHTML = '';
                return;
            }
            adminCategoriesPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} kategori. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminCategoriesPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;
            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;
            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-category-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;
            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages && totalPages >= maxPagesToShow) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }
            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="admin-category-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="admin-category-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }
             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-category-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-category-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
            adminCategoriesPaginationControls.innerHTML = paginationHTML;
        }

        if(adminCategoryFilterModalButton && adminCategoryFilterModal && closeAdminCategoryFilterModalButton && adminCategoryFilterModalContent) {
            adminCategoryFilterModalButton.addEventListener('click', () => openModal(adminCategoryFilterModal, adminCategoryFilterModalContent));
            closeAdminCategoryFilterModalButton.addEventListener('click', () => closeModal(adminCategoryFilterModal, adminCategoryFilterModalContent));
            adminCategoryFilterModal.addEventListener('click', (event) => { if (event.target === adminCategoryFilterModal) closeModal(adminCategoryFilterModal, adminCategoryFilterModalContent); });
        }

        if(adminCategoryFilterForm) {
            adminCategoryFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(adminCategoryFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                newParams.page = 1;
                loadAdminCategories(newParams);
                closeModal(adminCategoryFilterModal, adminCategoryFilterModalContent);
            });
        }

        if(resetAdminCategoryFilterButton && adminCategoryFilterForm) {
            resetAdminCategoryFilterButton.addEventListener('click', () => {
                adminCategoryFilterForm.reset();
                document.getElementById('filter_limit_admin_category').value = '15';
                document.getElementById('filter_status_admin_category').value = 'all';
                document.getElementById('filter_search_column_admin_category').value = 'name';
                document.getElementById('filter_sort_by_admin_category').value = 'name';
                document.getElementById('filter_sort_type_admin_category').value = 'ASC';
                adminCategoryFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        if(adminCategoriesPaginationControls) {
            adminCategoriesPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-category-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) { loadAdminCategories({ page: pageToGo }); }
                }
            });
        }

        function openAddEditCategoryModal(categoryIndex = null) {
            if (!addEditCategoryModal || !addEditCategoryModalContent || !addEditCategoryForm || !addEditCategoryModalTitle || !categoryIdInput || !categoryNameInput || !categoryIconInput || !categoryStatusSelect || !addEditCategoryMessageDiv) {
                console.error("Elemen modal tambah/edit kategori tidak ditemukan.");
                return;
            }
            addEditCategoryForm.reset();
            clearFieldErrors(addEditCategoryForm);
            addEditCategoryMessageDiv.innerHTML = '';
            const saveButton = document.getElementById('save-add-edit-category-button');

            if (categoryIndex !== null && currentAdminCategoryData[categoryIndex]) {
                const category = currentAdminCategoryData[categoryIndex];
                addEditCategoryModalTitle.innerHTML = `<i class="fas fa-edit mr-3 text-blue-500"></i> Edit Kategori`;
                categoryIdInput.value = category.id;
                categoryNameInput.value = category.name || '';
                categoryIconInput.value = category.icon_class || '';
                categoryStatusSelect.value = category.status || 'active';
                if(saveButton) saveButton.textContent = 'Simpan Perubahan';
            } else {
                addEditCategoryModalTitle.innerHTML = `<i class="fas fa-plus-circle mr-3 text-green-500"></i> Tambah Kategori Baru`;
                categoryIdInput.value = '';
                if(saveButton) saveButton.textContent = 'Simpan Kategori';
            }
            openModal(addEditCategoryModal, addEditCategoryModalContent);
        }

        if(addCategoryButton) {
            addCategoryButton.addEventListener('click', () => openAddEditCategoryModal(null));
        }
        if(closeAddEditCategoryModalButton) {
            closeAddEditCategoryModalButton.addEventListener('click', () => closeModal(addEditCategoryModal, addEditCategoryModalContent));
        }
        if(cancelAddEditCategoryButton) {
            cancelAddEditCategoryButton.addEventListener('click', () => closeModal(addEditCategoryModal, addEditCategoryModalContent));
        }
        if(addEditCategoryModal) {
            addEditCategoryModal.addEventListener('click', (event) => { if (event.target === addEditCategoryModal) closeModal(addEditCategoryModal, addEditCategoryModalContent); });
        }

        if(addEditCategoryForm && saveAddEditCategoryButton) {
            addEditCategoryForm.addEventListener('submit', (event) => {
                event.preventDefault();
                clearFieldErrors(addEditCategoryForm);
                if(addEditCategoryMessageDiv) addEditCategoryMessageDiv.innerHTML = '';
                const formData = new FormData(addEditCategoryForm);
                const categoryId = formData.get('category_id');
                const isEditing = !!categoryId;
                const ajaxUrl = isEditing ? `${jsBaseUrl}/ajax/admin/update_category` : `${jsBaseUrl}/ajax/admin/add_category`;

                const originalButtonText = saveAddEditCategoryButton.textContent;
                saveAddEditCategoryButton.textContent = 'Menyimpan...';
                saveAddEditCategoryButton.disabled = true;

                fetch(ajaxUrl, {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        closeModal(addEditCategoryModal, addEditCategoryModalContent);
                        displayGeneralMessage('admin-categories-message', data.message || `Kategori berhasil ${isEditing ? 'diperbarui' : 'ditambahkan'}.`, 'success', 3000);
                        loadAdminCategories(currentAdminCategoryParams);
                    } else {
                        if(addEditCategoryMessageDiv) displayGeneralMessage('add-edit-category-message', data.message || 'Gagal menyimpan.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(field, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error(`Fetch Error (${isEditing ? 'Update' : 'Add'} Category):`, error);
                    if(addEditCategoryMessageDiv) displayGeneralMessage('add-edit-category-message', 'Terjadi masalah koneksi.', 'error');
                })
                .finally(() => {
                    saveAddEditCategoryButton.textContent = originalButtonText;
                    saveAddEditCategoryButton.disabled = false;
                });
            });
        }

        adminCategoriesTableBody.addEventListener('click', (event) => {
            const editButton = event.target.closest('.admin-edit-category-btn');
            const deleteButton = event.target.closest('.admin-delete-category-btn');

            if (editButton && editButton.dataset.categoryIndex) {
                const categoryIndex = parseInt(editButton.dataset.categoryIndex);
                openAddEditCategoryModal(categoryIndex);
            } else if (deleteButton && deleteButton.dataset.categoryId && deleteButton.dataset.categoryName) {
                const categoryId = deleteButton.dataset.categoryId;
                const categoryName = deleteButton.dataset.categoryName;
                showDeleteCategoryConfirmationModal(categoryId, categoryName);
            }
        });

        function showDeleteCategoryConfirmationModal(categoryId, categoryName) {
            const modal = document.getElementById('delete-category-confirm-modal');
            const modalContent = document.getElementById('delete-category-confirm-modal-content');
            const modalMessage = document.getElementById('delete-category-confirm-modal-message');
            const confirmBtn = document.getElementById('confirm-delete-category-btn');
            const cancelBtns = document.querySelectorAll('.close-confirm-delete-category-btn');

            if (!modal || !modalContent || !modalMessage || !confirmBtn || cancelBtns.length === 0) {
                console.error("Elemen modal konfirmasi hapus kategori atau tombolnya tidak ditemukan.");
                return;
            }

            modalMessage.innerHTML = `Apakah Anda yakin ingin menghapus kategori <strong class="font-semibold text-gray-800">"${escapeHTML(categoryName)}"</strong> (ID: ${escapeHTML(categoryId)})? <br><span class="text-xs text-red-600">(Menghapus kategori akan gagal jika masih ada layanan terkait)</span>`;

            let confirmHandler;
            let cancelHandler;
            let overlayClickHandler;

            confirmHandler = () => {
                const idToDelete = categoryId;
                const nameToDelete = categoryName;
                const confirmButtonOriginalHTML = confirmBtn.innerHTML;
                confirmBtn.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i> Menghapus...`;
                confirmBtn.disabled = true;
                cancelBtns.forEach(btn => btn.disabled = true);

                fetch(`${jsBaseUrl}/ajax/admin/delete_category`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
                    body: JSON.stringify({ category_id: idToDelete })
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        loadAdminCategories(currentAdminCategoryParams);
                        displayGeneralMessage('admin-categories-message', data.message || `Kategori "${nameToDelete}" berhasil dihapus.`, 'success', 4000);
                    } else {
                        displayGeneralMessage('admin-categories-message', data.message || 'Gagal menghapus kategori.', 'error');
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Delete Category):', error);
                    displayGeneralMessage('admin-categories-message', 'Error koneksi saat menghapus.', 'error');
                })
                .finally(() => {
                    confirmBtn.innerHTML = confirmButtonOriginalHTML;
                    confirmBtn.disabled = false;
                    cancelBtns.forEach(btn => btn.disabled = false);
                    closeModal(modal, modalContent);
                    const currentConfirmBtn = document.getElementById('confirm-delete-category-btn');
                    if (currentConfirmBtn) currentConfirmBtn.removeEventListener('click', confirmHandler);
                });
            };

            cancelHandler = () => {
                closeModal(modal, modalContent);
                const currentConfirmBtn = document.getElementById('confirm-delete-category-btn');
                 if (currentConfirmBtn) currentConfirmBtn.removeEventListener('click', confirmHandler);
                 cancelBtns.forEach(btn => {
                    btn.removeEventListener('click', cancelHandler);
                 });
                 modal.removeEventListener('click', overlayClickHandler);
            };

             overlayClickHandler = (event) => {
                 if (event.target === modal) {
                     cancelHandler();
                 }
             };

            const oldConfirmBtn = document.getElementById('confirm-delete-category-btn');
            const newConfirmBtn = oldConfirmBtn.cloneNode(true);
            oldConfirmBtn.parentNode.replaceChild(newConfirmBtn, oldConfirmBtn);
            newConfirmBtn.addEventListener('click', confirmHandler, { once: true });

            cancelBtns.forEach(btn => {
                const oldCancelBtn = btn;
                const newCancelBtn = oldCancelBtn.cloneNode(true);
                oldCancelBtn.parentNode.replaceChild(newCancelBtn, oldCancelBtn);
                newCancelBtn.addEventListener('click', cancelHandler, { once: true });
            });

            modal.removeEventListener('click', overlayClickHandler);
            modal.addEventListener('click', overlayClickHandler);

            openModal(modal, modalContent);
        }

        loadAdminCategories(currentAdminCategoryParams);
    }
    // --- Akhir Logika Kelola Kategori Admin ---

    // ========================================================
    // Logika untuk Halaman Kelola Layanan (Admin)
    // ========================================================
    const adminServicesTableBody = document.getElementById('admin-services-table-body');
    const adminServiceFilterModalButton = document.getElementById('admin-service-filter-modal-button');
    const adminServiceFilterForm = document.getElementById('admin-service-filter-form');
    const addServiceButton = document.getElementById('add-service-button');
    const addEditServiceModal = document.getElementById('add-edit-service-modal');

    if (adminServicesTableBody && adminServiceFilterForm && addServiceButton && addEditServiceModal) {
        const adminServiceFilterModal = document.getElementById('admin-service-filter-modal');
        const adminServiceFilterModalContent = document.getElementById('admin-service-filter-modal-content');
        const closeAdminServiceFilterModalButton = document.getElementById('close-admin-service-filter-modal');
        const resetAdminServiceFilterButton = document.getElementById('reset-admin-service-filter-button');
        const adminServicesPaginationInfo = document.getElementById('admin-services-pagination-info');
        const adminServicesPaginationControls = document.getElementById('admin-services-pagination-controls');
        const adminServicesMessageDiv = document.getElementById('admin-services-message');
        const addEditServiceModalContent = document.getElementById('add-edit-service-modal-content');
        const addEditServiceModalTitle = document.getElementById('add-edit-service-modal-title');
        const closeAddEditServiceModalButton = document.getElementById('close-add-edit-service-modal');
        const cancelAddEditServiceButton = document.getElementById('cancel-add-edit-service-button');
        const addEditServiceForm = document.getElementById('add-edit-service-form');
        const saveAddEditServiceButton = document.getElementById('save-add-edit-service-button');
        const addEditServiceMessageDiv = document.getElementById('add-edit-service-message');
        const serviceIdInput = document.getElementById('service_id');
        const serviceCategoryIdSelect = document.getElementById('service_category_id');
        const serviceProviderIdSelect = document.getElementById('service_provider_id');
        const serviceProviderServiceIdInput = document.getElementById('service_provider_service_id');
        const serviceNameInput = document.getElementById('service_name');
        const serviceNoteTextarea = document.getElementById('service_note');
        const servicePriceInput = document.getElementById('service_price_per_1000');
        const serviceMinInput = document.getElementById('service_min_order');
        const serviceMaxInput = document.getElementById('service_max_order');
        const serviceStatusSelect = document.getElementById('service_status');
        const deleteServiceConfirmModal = document.getElementById('delete-service-confirm-modal');
        const deleteServiceConfirmModalContent = document.getElementById('delete-service-confirm-modal-content');
        const deleteServiceConfirmModalMessage = document.getElementById('delete-service-confirm-modal-message');
        const confirmDeleteServiceButton = document.getElementById('confirm-delete-service-btn');
        const cancelDeleteServiceButtons = document.querySelectorAll('.close-confirm-delete-service-btn');

        let currentAdminServiceParams = { page: 1, limit: 15, status: 'all', category_id: 'all', provider_id: 'all', sort_by: 's.name', sort_type: 'ASC', search_column: 's.name', search_keyword: '' };
        let currentAdminServiceData = [];

        function loadAdminServices(params = {}) {
            adminServicesTableBody.innerHTML = `<tr><td colspan="10" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data layanan...</td></tr>`;
            if(adminServicesPaginationInfo) adminServicesPaginationInfo.textContent = 'Memuat...';
            if(adminServicesPaginationControls) adminServicesPaginationControls.innerHTML = '';
            if(adminServicesMessageDiv && !adminServicesMessageDiv.innerHTML.includes('success')) {
                adminServicesMessageDiv.innerHTML = '';
                adminServicesMessageDiv.className = 'mb-4 text-sm';
            }

            currentAdminServiceParams = { ...currentAdminServiceParams, ...params };
            const queryParams = new URLSearchParams(currentAdminServiceParams).toString();
            const url = `${jsBaseUrl}/ajax/admin/get_admin_services?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.services && data.pagination) {
                        currentAdminServiceData = data.services;
                        renderAdminServiceTable(data.services);
                        renderAdminServicePagination(data.pagination);
                         if (adminServicesMessageDiv && !adminServicesMessageDiv.innerHTML.includes('success')) {
                            adminServicesMessageDiv.innerHTML = '';
                            adminServicesMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        currentAdminServiceData = [];
                        adminServicesTableBody.innerHTML = `<tr><td colspan="10" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data layanan.')}</td></tr>`;
                        if(adminServicesPaginationInfo) adminServicesPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminServicesPaginationControls) adminServicesPaginationControls.innerHTML = '';
                        if (!adminServicesMessageDiv || !adminServicesMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('admin-services-message', data.message || 'Gagal memuat data layanan.', 'error');
                        }
                    }
                })
                .catch(error => {
                    currentAdminServiceData = [];
                    console.error('Fetch Error (Admin Services):', error);
                    adminServicesTableBody.innerHTML = `<tr><td colspan="10" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat layanan.</td></tr>`;
                    if(adminServicesPaginationInfo) adminServicesPaginationInfo.textContent = 'Error koneksi.';
                    if(adminServicesPaginationControls) adminServicesPaginationControls.innerHTML = '';
                     if (!adminServicesMessageDiv || !adminServicesMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('admin-services-message', 'Error koneksi saat memuat layanan.', 'error');
                     }
                });
        }

        function renderAdminServiceTable(services) {
            adminServicesTableBody.innerHTML = '';
            if (services.length === 0) {
                adminServicesTableBody.innerHTML = `<tr><td colspan="10" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada layanan yang cocok dengan filter.</td></tr>`;
                return;
            }
            services.forEach((service, index) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-xs');
                const statusBadgeClass = getStatusBadgeClass(service.status);

                row.innerHTML = `
                    <td class="px-3 py-2 whitespace-nowrap text-gray-500">${escapeHTML(service.id)}</td>
                    <td class="px-4 py-2 text-gray-800 font-medium max-w-xs truncate" title="${escapeHTML(service.name)}">${escapeHTML(service.name)}</td>
                    <td class="px-4 py-2 whitespace-nowrap text-gray-600 max-w-[150px] truncate" title="${escapeHTML(service.category_name)}">${escapeHTML(service.category_name)}</td>
                    <td class="px-4 py-2 whitespace-nowrap text-gray-600 max-w-[150px] truncate" title="${escapeHTML(service.provider_name)}">${escapeHTML(service.provider_name)}</td>
                    <td class="px-3 py-2 whitespace-nowrap text-center text-gray-500">${escapeHTML(service.provider_service_id)}</td>
                    <td class="px-3 py-2 whitespace-nowrap text-right text-indigo-700 font-semibold">Rp ${escapeHTML(service.price_per_1000?.toLocaleString('id-ID', {minimumFractionDigits: 0, maximumFractionDigits: 2}) ?? 'N/A')}</td>
                    <td class="px-3 py-2 whitespace-nowrap text-center text-gray-600">${escapeHTML(service.min_order?.toLocaleString('id-ID') ?? '-')}</td>
                    <td class="px-3 py-2 whitespace-nowrap text-center text-gray-600">${escapeHTML(service.max_order?.toLocaleString('id-ID') ?? '-')}</td>
                    <td class="px-3 py-2 whitespace-nowrap text-center"><span class="px-2 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusBadgeClass}">${escapeHTML(service.status ? service.status.charAt(0).toUpperCase() + service.status.slice(1) : 'N/A')}</span></td>
                    <td class="px-4 py-2 whitespace-nowrap text-center text-sm space-x-1">
                        <button type="button" class="admin-edit-service-btn text-blue-600 hover:text-blue-800 p-1 hover:bg-blue-100 rounded" data-service-index="${index}" title="Edit Layanan"><i class="far fa-edit"></i></button>
                        <button type="button" class="admin-delete-service-btn text-red-600 hover:text-red-800 p-1 hover:bg-red-100 rounded" data-service-id="${escapeHTML(service.id)}" data-service-name="${escapeHTML(service.name)}" title="Hapus Layanan"><i class="far fa-trash-alt"></i></button>
                    </td>
                `;
                adminServicesTableBody.appendChild(row);
            });
        }

        function renderAdminServicePagination(pagination) {
             if (!adminServicesPaginationControls || !adminServicesPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                adminServicesPaginationInfo.textContent = 'Tidak ada data.';
                adminServicesPaginationControls.innerHTML = '';
                return;
            }
            adminServicesPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} layanan. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminServicesPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;
            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;
            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-service-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;
            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages && totalPages >= maxPagesToShow) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }
            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="admin-service-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="admin-service-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }
             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-service-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-service-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
            adminServicesPaginationControls.innerHTML = paginationHTML;
        }

        if(adminServiceFilterModalButton && adminServiceFilterModal && closeAdminServiceFilterModalButton && adminServiceFilterModalContent) {
            adminServiceFilterModalButton.addEventListener('click', () => openModal(adminServiceFilterModal, adminServiceFilterModalContent));
            closeAdminServiceFilterModalButton.addEventListener('click', () => closeModal(adminServiceFilterModal, adminServiceFilterModalContent));
            adminServiceFilterModal.addEventListener('click', (event) => { if (event.target === adminServiceFilterModal) closeModal(adminServiceFilterModal, adminServiceFilterModalContent); });
        }

        if(adminServiceFilterForm) {
            adminServiceFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(adminServiceFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                newParams.page = 1;
                loadAdminServices(newParams);
                closeModal(adminServiceFilterModal, adminServiceFilterModalContent);
            });
        }

        if(resetAdminServiceFilterButton && adminServiceFilterForm) {
            resetAdminServiceFilterButton.addEventListener('click', () => {
                adminServiceFilterForm.reset();
                document.getElementById('filter_limit_admin_service').value = '15';
                document.getElementById('filter_status_admin_service').value = 'all';
                document.getElementById('filter_category_admin_service').value = 'all';
                document.getElementById('filter_provider_admin_service').value = 'all';
                document.getElementById('filter_search_column_admin_service').value = 's.name';
                document.getElementById('filter_sort_by_admin_service').value = 's.name';
                document.getElementById('filter_sort_type_admin_service').value = 'ASC';
                adminServiceFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        if(adminServicesPaginationControls) {
            adminServicesPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-service-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) { loadAdminServices({ page: pageToGo }); }
                }
            });
        }

        function openAddEditServiceModal(serviceIndex = null) {
            if (!addEditServiceModal || !addEditServiceModalContent || !addEditServiceForm || !addEditServiceModalTitle || !serviceIdInput || !serviceCategoryIdSelect || !serviceProviderIdSelect || !serviceProviderServiceIdInput || !serviceNameInput || !serviceNoteTextarea || !servicePriceInput || !serviceMinInput || !serviceMaxInput || !serviceStatusSelect || !addEditServiceMessageDiv) {
                console.error("Elemen modal tambah/edit layanan tidak ditemukan.");
                return;
            }
            addEditServiceForm.reset();
            clearFieldErrors(addEditServiceForm);
            addEditServiceMessageDiv.innerHTML = '';
            const saveButton = document.getElementById('save-add-edit-service-button');

            if (serviceIndex !== null && currentAdminServiceData[serviceIndex]) {
                const service = currentAdminServiceData[serviceIndex];
                addEditServiceModalTitle.innerHTML = `<i class="fas fa-edit mr-3 text-blue-500"></i> Edit Layanan`;
                serviceIdInput.value = service.id;
                serviceCategoryIdSelect.value = service.category_id || '';
                serviceProviderIdSelect.value = service.provider_id || '';
                serviceProviderServiceIdInput.value = service.provider_service_id || '';
                serviceNameInput.value = service.name || '';
                serviceNoteTextarea.value = service.note || '';
                servicePriceInput.value = service.price_per_1000 || '';
                serviceMinInput.value = service.min_order || '';
                serviceMaxInput.value = service.max_order || '';
                serviceStatusSelect.value = service.status || 'active';
                if(saveButton) saveButton.textContent = 'Simpan Perubahan';
            } else {
                addEditServiceModalTitle.innerHTML = `<i class="fas fa-plus-circle mr-3 text-green-500"></i> Tambah Layanan Baru`;
                serviceIdInput.value = '';
                if(saveButton) saveButton.textContent = 'Simpan Layanan';
            }
            openModal(addEditServiceModal, addEditServiceModalContent);
        }

        if(addServiceButton) {
            addServiceButton.addEventListener('click', () => openAddEditServiceModal(null));
        }
        if(closeAddEditServiceModalButton) {
            closeAddEditServiceModalButton.addEventListener('click', () => closeModal(addEditServiceModal, addEditServiceModalContent));
        }
        if(cancelAddEditServiceButton) {
            cancelAddEditServiceButton.addEventListener('click', () => closeModal(addEditServiceModal, addEditServiceModalContent));
        }
        if(addEditServiceModal) {
            addEditServiceModal.addEventListener('click', (event) => { if (event.target === addEditServiceModal) closeModal(addEditServiceModal, addEditServiceModalContent); });
        }

        if(addEditServiceForm && saveAddEditServiceButton) {
            addEditServiceForm.addEventListener('submit', (event) => {
                event.preventDefault();
                clearFieldErrors(addEditServiceForm);
                if(addEditServiceMessageDiv) addEditServiceMessageDiv.innerHTML = '';
                const formData = new FormData(addEditServiceForm);
                const serviceId = formData.get('service_id');
                const isEditing = !!serviceId;
                const ajaxUrl = isEditing ? `${jsBaseUrl}/ajax/admin/update_service` : `${jsBaseUrl}/ajax/admin/add_service`;

                const originalButtonText = saveAddEditServiceButton.textContent;
                saveAddEditServiceButton.textContent = 'Menyimpan...';
                saveAddEditServiceButton.disabled = true;

                fetch(ajaxUrl, {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        closeModal(addEditServiceModal, addEditServiceModalContent);
                        displayGeneralMessage('admin-services-message', data.message || `Layanan berhasil ${isEditing ? 'diperbarui' : 'ditambahkan'}.`, 'success', 3000);
                        loadAdminServices(currentAdminServiceParams);
                    } else {
                        if(addEditServiceMessageDiv) displayGeneralMessage('add-edit-service-message', data.message || 'Gagal menyimpan.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(field, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error(`Fetch Error (${isEditing ? 'Update' : 'Add'} Service):`, error);
                    if(addEditServiceMessageDiv) displayGeneralMessage('add-edit-service-message', 'Terjadi masalah koneksi.', 'error');
                })
                .finally(() => {
                    saveAddEditServiceButton.textContent = originalButtonText;
                    saveAddEditServiceButton.disabled = false;
                });
            });
        }

        adminServicesTableBody.addEventListener('click', (event) => {
            const editButton = event.target.closest('.admin-edit-service-btn');
            const deleteButton = event.target.closest('.admin-delete-service-btn');

            if (editButton && editButton.dataset.serviceIndex) {
                const serviceIndex = parseInt(editButton.dataset.serviceIndex);
                openAddEditServiceModal(serviceIndex);
            } else if (deleteButton && deleteButton.dataset.serviceId && deleteButton.dataset.serviceName) {
                const serviceId = deleteButton.dataset.serviceId;
                const serviceName = deleteButton.dataset.serviceName;
                showDeleteServiceConfirmationModal(serviceId, serviceName);
            }
        });

        function showDeleteServiceConfirmationModal(serviceId, serviceName) {
            const modal = document.getElementById('delete-service-confirm-modal');
            const modalContent = document.getElementById('delete-service-confirm-modal-content');
            const modalMessage = document.getElementById('delete-service-confirm-modal-message');
            const confirmBtn = document.getElementById('confirm-delete-service-btn');
            const cancelBtns = document.querySelectorAll('.close-confirm-delete-service-btn');

            if (!modal || !modalContent || !modalMessage || !confirmBtn || cancelBtns.length === 0) {
                console.error("Elemen modal konfirmasi hapus layanan atau tombolnya tidak ditemukan.");
                return;
            }

            modalMessage.innerHTML = `Apakah Anda yakin ingin menghapus layanan <strong class="font-semibold text-gray-800">"${escapeHTML(serviceName)}"</strong> (ID: ${escapeHTML(serviceId)})?`;

            let confirmHandler;
            let cancelHandler;
            let overlayClickHandler;

            confirmHandler = () => {
                const idToDelete = serviceId;
                const nameToDelete = serviceName;
                const confirmButtonOriginalHTML = confirmBtn.innerHTML;
                confirmBtn.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i> Menghapus...`;
                confirmBtn.disabled = true;
                cancelBtns.forEach(btn => btn.disabled = true);

                fetch(`${jsBaseUrl}/ajax/admin/delete_service`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
                    body: JSON.stringify({ service_id: idToDelete })
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        loadAdminServices(currentAdminServiceParams);
                        displayGeneralMessage('admin-services-message', data.message || `Layanan "${nameToDelete}" berhasil dihapus.`, 'success', 4000);
                    } else {
                        displayGeneralMessage('admin-services-message', data.message || 'Gagal menghapus layanan.', 'error');
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Delete Service):', error);
                    displayGeneralMessage('admin-services-message', 'Error koneksi saat menghapus.', 'error');
                })
                .finally(() => {
                    confirmBtn.innerHTML = confirmButtonOriginalHTML;
                    confirmBtn.disabled = false;
                    cancelBtns.forEach(btn => btn.disabled = false);
                    closeModal(modal, modalContent);
                    const currentConfirmBtn = document.getElementById('confirm-delete-service-btn');
                    if (currentConfirmBtn) currentConfirmBtn.removeEventListener('click', confirmHandler);
                });
            };

            cancelHandler = () => {
                closeModal(modal, modalContent);
                const currentConfirmBtn = document.getElementById('confirm-delete-service-btn');
                 if (currentConfirmBtn) currentConfirmBtn.removeEventListener('click', confirmHandler);
                 cancelBtns.forEach(btn => {
                    btn.removeEventListener('click', cancelHandler);
                 });
                 modal.removeEventListener('click', overlayClickHandler);
            };

             overlayClickHandler = (event) => {
                 if (event.target === modal) {
                     cancelHandler();
                 }
             };

            const oldConfirmBtn = document.getElementById('confirm-delete-service-btn');
            const newConfirmBtn = oldConfirmBtn.cloneNode(true);
            oldConfirmBtn.parentNode.replaceChild(newConfirmBtn, oldConfirmBtn);
            newConfirmBtn.addEventListener('click', confirmHandler, { once: true });

            cancelBtns.forEach(btn => {
                const oldCancelBtn = btn;
                const newCancelBtn = oldCancelBtn.cloneNode(true);
                oldCancelBtn.parentNode.replaceChild(newCancelBtn, oldCancelBtn);
                newCancelBtn.addEventListener('click', cancelHandler, { once: true });
            });

            modal.removeEventListener('click', overlayClickHandler);
            modal.addEventListener('click', overlayClickHandler);

            openModal(modal, modalContent);
        }

        loadAdminServices(currentAdminServiceParams);
    }

        const websiteSettingsForm = document.getElementById('website-settings-form');
        const websiteSettingsMessageDiv = document.getElementById('website-settings-message');
        const saveSettingsButton = document.getElementById('save-settings-button');
        const logoInput = document.getElementById('setting_app_logo');
        const logoPreviewContainer = document.getElementById('logo-preview-container');
        const logoPreview = document.getElementById('logo-preview');
        const removeLogoBtn = document.getElementById('remove-logo-btn');
        const removeLogoFlagInput = document.getElementById('remove_logo_flag');

        if (websiteSettingsForm && saveSettingsButton && jsBaseUrl) {

            function loadWebsiteSettings() {
                 displayGeneralMessage('website-settings-message', '<i class="fas fa-spinner fa-spin mr-2"></i> Memuat pengaturan...', 'info');
                 const url = `${jsBaseUrl}/ajax/admin/get_website_settings`;
                 fetch(url)
                    .then(response => {
                        if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                        return response.json();
                    })
                    .then(data => {
                         displayGeneralMessage('website-settings-message', ''); 
                        if (data.success && data.settings) {
                            document.getElementById('setting_app_name').value = data.settings.app_name || '';
                            document.getElementById('setting_meta_description').value = data.settings.meta_description || '';
                            document.getElementById('setting_meta_keywords').value = data.settings.meta_keywords || '';
                            document.getElementById('setting_contact_email').value = data.settings.contact_email || '';
                            document.getElementById('setting_contact_phone').value = data.settings.contact_phone || '';

                            if (data.settings.app_logo_url) {
                                if(logoPreview) logoPreview.src = data.settings.app_logo_url;
                                if(logoPreviewContainer) logoPreviewContainer.classList.remove('hidden');
                            } else {
                                if(logoPreview) logoPreview.src = '#';
                                if(logoPreviewContainer) logoPreviewContainer.classList.add('hidden');
                            }
                        } else {
                            displayGeneralMessage('website-settings-message', data.message || 'Gagal memuat pengaturan.', 'error');
                        }
                    })
                    .catch(error => {
                        console.error("Fetch Error (Get Settings):", error);
                        displayGeneralMessage('website-settings-message', 'Error koneksi saat memuat pengaturan.', 'error');
                    });
            }

            loadWebsiteSettings();

             const btnTextEl = document.getElementById('settings-btn-text');
             if(btnTextEl) saveSettingsButton.dataset.originalText = btnTextEl.textContent;

            websiteSettingsForm.addEventListener('submit', function(event) {
                event.preventDefault();
                clearFieldErrors(websiteSettingsForm);
                displayGeneralMessage('website-settings-message', '');
                let isValid = true;
                const formData = new FormData(websiteSettingsForm);

                const appName = formData.get('app_name')?.trim() ?? '';
                const logoFile = logoInput ? logoInput.files[0] : null;
                const contactEmail = formData.get('contact_email')?.trim() ?? '';

                if (!appName) {
                     isValid = false;
                     displayFieldError('setting_app_name', 'Nama Aplikasi wajib diisi.');
                }
                if (contactEmail && !/\S+@\S+\.\S+/.test(contactEmail)) { 
                     isValid = false;
                     displayFieldError('setting_contact_email', 'Format email kontak tidak valid.');
                }

                if (logoFile) {
                    const maxSize = 1 * 1024 * 1024; // 1MB
                    const allowedTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/svg+xml'];
                    if (logoFile.size > maxSize) {
                        isValid = false;
                        displayFieldError('setting_app_logo', 'Ukuran file logo maksimal 1MB.');
                    } else if (!allowedTypes.includes(logoFile.type)) {
                        isValid = false;
                        displayFieldError('setting_app_logo', 'Format logo tidak valid (PNG, JPG, GIF, SVG).');
                    }
                }

                if (!isValid) return;

                setButtonLoading('save-settings-button', 'settings-btn-text', 'settings-spinner', true, 'Menyimpan...');
                const ajaxUrl = websiteSettingsForm.action;

                fetch(ajaxUrl, {
                    method: 'POST',
                    body: formData 
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        displayGeneralMessage('website-settings-message', data.message || 'Pengaturan berhasil disimpan.', 'success', 3000);
                        if (data.hasOwnProperty('new_logo_url')) {
                             if (data.new_logo_url) {
                                if(logoPreview) logoPreview.src = data.new_logo_url;
                                if(logoPreviewContainer) logoPreviewContainer.classList.remove('hidden');
                            } else {
                                if(logoPreview) logoPreview.src = '#';
                                if(logoPreviewContainer) logoPreviewContainer.classList.add('hidden');
                            }
                            if(logoInput) logoInput.value = '';
                            if(removeLogoFlagInput) removeLogoFlagInput.value = '0';
                        }
                         const newAppName = formData.get('app_name');
                         if(newAppName && typeof APP_NAME !== 'undefined' && newAppName !== APP_NAME) {
                             document.title = newAppName;
                             const sidebarAppName = document.querySelector('#sidebar .text-xl.font-bold');
                             if(sidebarAppName) sidebarAppName.textContent = newAppName;
                         }

                    } else {
                        displayGeneralMessage('website-settings-message', data.message || 'Gagal menyimpan pengaturan.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(`setting_${field}`, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Update Settings):', error);
                    displayGeneralMessage('website-settings-message', 'Terjadi masalah koneksi.', 'error');
                })
                .finally(() => {
                    setButtonLoading('save-settings-button', 'settings-btn-text', 'settings-spinner', false);
                });
            });

            if (logoInput && logoPreview && logoPreviewContainer) {
                logoInput.addEventListener('change', function(event) {
                    const file = event.target.files[0];
                    if (file && file.type.startsWith('image/')) {
                        const reader = new FileReader();
                        reader.onload = function(e) {
                            logoPreview.src = e.target.result;
                            logoPreviewContainer.classList.remove('hidden');
                            if(removeLogoFlagInput) removeLogoFlagInput.value = '0';
                        }
                        reader.readAsDataURL(file);
                    } else {
                    }
                });
            }

            if (removeLogoBtn && logoInput && logoPreview && logoPreviewContainer && removeLogoFlagInput) {
                removeLogoBtn.addEventListener('click', function() {
                    logoInput.value = ''; 
                    logoPreview.src = '#';
                    logoPreviewContainer.classList.add('hidden');
                    removeLogoFlagInput.value = '1'; 
                });
            }
        }

    const adminProvidersTableBody = document.getElementById('admin-providers-table-body');
    const adminProviderFilterModalButton = document.getElementById('admin-provider-filter-modal-button');
    const adminProviderFilterForm = document.getElementById('admin-provider-filter-form');
    const addProviderButton = document.getElementById('add-provider-button');
    const addEditProviderModal = document.getElementById('add-edit-provider-modal');

    if (adminProvidersTableBody && adminProviderFilterForm && addProviderButton && addEditProviderModal) {
        const adminProviderFilterModal = document.getElementById('admin-provider-filter-modal');
        const adminProviderFilterModalContent = document.getElementById('admin-provider-filter-modal-content');
        const closeAdminProviderFilterModalButton = document.getElementById('close-admin-provider-filter-modal');
        const resetAdminProviderFilterButton = document.getElementById('reset-admin-provider-filter-button');
        const adminProvidersPaginationInfo = document.getElementById('admin-providers-pagination-info');
        const adminProvidersPaginationControls = document.getElementById('admin-providers-pagination-controls');
        const adminProvidersMessageDiv = document.getElementById('admin-providers-message');
        const addEditProviderModalContent = document.getElementById('add-edit-provider-modal-content');
        const addEditProviderModalTitle = document.getElementById('add-edit-provider-modal-title');
        const closeAddEditProviderModalButton = document.getElementById('close-add-edit-provider-modal');
        const cancelAddEditProviderButton = document.getElementById('cancel-add-edit-provider-button');
        const addEditProviderForm = document.getElementById('add-edit-provider-form');
        const saveAddEditProviderButton = document.getElementById('save-add-edit-provider-button');
        const addEditProviderMessageDiv = document.getElementById('add-edit-provider-message');
        const providerIdInput = document.getElementById('provider_id');
        const providerNameInput = document.getElementById('provider_name');
        const providerApiUrlInput = document.getElementById('provider_api_url');
        const providerApiIdInput = document.getElementById('provider_api_id');
        const providerApiKeyInput = document.getElementById('provider_api_key');
        const providerSecretKeyInput = document.getElementById('provider_secret_key');
        const providerStatusSelect = document.getElementById('provider_status');
        const deleteProviderConfirmModal = document.getElementById('delete-provider-confirm-modal');
        const deleteProviderConfirmModalContent = document.getElementById('delete-provider-confirm-modal-content');
        const deleteProviderConfirmModalMessage = document.getElementById('delete-provider-confirm-modal-message');
        const confirmDeleteProviderButton = document.getElementById('confirm-delete-provider-btn');
        const cancelDeleteProviderButtons = document.querySelectorAll('.close-confirm-delete-provider-btn');

        let currentAdminProviderParams = { page: 1, limit: 15, status: 'all', sort_by: 'name', sort_type: 'ASC', search_column: 'name', search_keyword: '' };
        let currentAdminProviderData = [];

        function loadAdminProviders(params = {}) {
            adminProvidersTableBody.innerHTML = `<tr><td colspan="7" class="px-6 py-10 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data provider...</td></tr>`;
            if(adminProvidersPaginationInfo) adminProvidersPaginationInfo.textContent = 'Memuat...';
            if(adminProvidersPaginationControls) adminProvidersPaginationControls.innerHTML = '';
            if(adminProvidersMessageDiv && !adminProvidersMessageDiv.innerHTML.includes('success')) {
                adminProvidersMessageDiv.innerHTML = '';
                adminProvidersMessageDiv.className = 'mb-4 text-sm';
            }

            currentAdminProviderParams = { ...currentAdminProviderParams, ...params };
            const queryParams = new URLSearchParams(currentAdminProviderParams).toString();
            const url = `${jsBaseUrl}/ajax/admin/get_admin_providers?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    const contentType = response.headers.get("content-type");
                    if (contentType && contentType.indexOf("application/json") !== -1) {
                        return response.json();
                    } else {
                        return response.text().then(text => {
                            throw new Error(`Respons server bukan JSON: ${text.substring(0, 100)}...`);
                        });
                    }
                })
                .then(data => {
                    if (data.success && data.providers && data.pagination) {
                        currentAdminProviderData = data.providers;
                        renderAdminProviderTable(data.providers);
                        renderAdminProviderPagination(data.pagination);
                         if (adminProvidersMessageDiv && !adminProvidersMessageDiv.innerHTML.includes('success')) {
                            adminProvidersMessageDiv.innerHTML = '';
                            adminProvidersMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        currentAdminProviderData = [];
                        adminProvidersTableBody.innerHTML = `<tr><td colspan="7" class="px-6 py-10 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data provider.')}</td></tr>`;
                        if(adminProvidersPaginationInfo) adminProvidersPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminProvidersPaginationControls) adminProvidersPaginationControls.innerHTML = '';
                        if (!adminProvidersMessageDiv || !adminProvidersMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('admin-providers-message', data.message || 'Gagal memuat data provider.', 'error');
                        }
                    }
                })
                .catch(error => {
                    currentAdminProviderData = [];
                    console.error('Fetch Error (Admin Providers):', error);
                    adminProvidersTableBody.innerHTML = `<tr><td colspan="7" class="px-6 py-10 text-center text-sm text-red-500 italic">Error koneksi saat memuat provider. ${error.message}</td></tr>`;
                    if(adminProvidersPaginationInfo) adminProvidersPaginationInfo.textContent = 'Error koneksi.';
                    if(adminProvidersPaginationControls) adminProvidersPaginationControls.innerHTML = '';
                     if (!adminProvidersMessageDiv || !adminProvidersMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('admin-providers-message', `Error koneksi saat memuat provider: ${error.message}`, 'error');
                     }
                });
        }

        function renderAdminProviderTable(providers) {
            adminProvidersTableBody.innerHTML = '';
            if (providers.length === 0) {
                adminProvidersTableBody.innerHTML = `<tr><td colspan="7" class="px-6 py-10 text-center text-sm text-gray-500 italic">Tidak ada provider yang cocok dengan filter.</td></tr>`;
                return;
            }
            providers.forEach((provider, index) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-sm');
                const formattedDateTime = formatLocalDate(provider.created_at);
                const statusBadgeClass = getStatusBadgeClass(provider.status);

                row.innerHTML = `
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500">${escapeHTML(provider.id)}</td>
                    <td class="px-6 py-3 text-gray-800 font-medium">${escapeHTML(provider.name)}</td>
                    <td class="px-6 py-3 text-gray-600 max-w-xs truncate" title="${escapeHTML(provider.api_url)}">${escapeHTML(provider.api_url)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500">${escapeHTML(provider.api_id || '-')}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center"><span class="px-2.5 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusBadgeClass}">${escapeHTML(provider.status ? provider.status.charAt(0).toUpperCase() + provider.status.slice(1) : 'N/A')}</span></td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-500 text-xs">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center text-base space-x-1">
                        <button type="button" class="admin-edit-provider-btn text-blue-600 hover:text-blue-800 p-1 hover:bg-blue-100 rounded" data-provider-index="${index}" title="Edit Provider"><i class="far fa-edit"></i></button>
                        <button type="button" class="admin-delete-provider-btn text-red-600 hover:text-red-800 p-1 hover:bg-red-100 rounded" data-provider-id="${escapeHTML(provider.id)}" data-provider-name="${escapeHTML(provider.name)}" title="Hapus Provider"><i class="far fa-trash-alt"></i></button>
                    </td>
                `;
                adminProvidersTableBody.appendChild(row);
            });
        }

        function renderAdminProviderPagination(pagination) {
             if (!adminProvidersPaginationControls || !adminProvidersPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                adminProvidersPaginationInfo.textContent = 'Tidak ada data.';
                adminProvidersPaginationControls.innerHTML = '';
                return;
            }
            adminProvidersPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} provider. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminProvidersPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;
            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;
            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-provider-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;
            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages && totalPages >= maxPagesToShow) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }
            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="admin-provider-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="admin-provider-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }
             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-provider-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-provider-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
            adminProvidersPaginationControls.innerHTML = paginationHTML;
        }

        if(adminProviderFilterModalButton && adminProviderFilterModal && closeAdminProviderFilterModalButton && adminProviderFilterModalContent) {
            adminProviderFilterModalButton.addEventListener('click', () => openModal(adminProviderFilterModal, adminProviderFilterModalContent));
            closeAdminProviderFilterModalButton.addEventListener('click', () => closeModal(adminProviderFilterModal, adminProviderFilterModalContent));
            adminProviderFilterModal.addEventListener('click', (event) => { if (event.target === adminProviderFilterModal) closeModal(adminProviderFilterModal, adminProviderFilterModalContent); });
        }

        if(adminProviderFilterForm) {
            adminProviderFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(adminProviderFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                newParams.page = 1;
                loadAdminProviders(newParams);
                closeModal(adminProviderFilterModal, adminProviderFilterModalContent);
            });
        }

        if(resetAdminProviderFilterButton && adminProviderFilterForm) {
            resetAdminProviderFilterButton.addEventListener('click', () => {
                adminProviderFilterForm.reset();
                document.getElementById('filter_limit_admin_provider').value = '15';
                document.getElementById('filter_status_admin_provider').value = 'all';
                document.getElementById('filter_search_column_admin_provider').value = 'name';
                document.getElementById('filter_sort_by_admin_provider').value = 'name';
                document.getElementById('filter_sort_type_admin_provider').value = 'ASC';
                adminProviderFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        if(adminProvidersPaginationControls) {
            adminProvidersPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-provider-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) { loadAdminProviders({ page: pageToGo }); }
                }
            });
        }

        function openAddEditProviderModal(providerIndex = null) {
            if (!addEditProviderModal || !addEditProviderModalContent || !addEditProviderForm || !addEditProviderModalTitle || !providerIdInput || !providerNameInput || !providerApiUrlInput || !providerApiIdInput || !providerApiKeyInput || !providerSecretKeyInput || !providerStatusSelect || !addEditProviderMessageDiv) {
                console.error("Elemen modal tambah/edit provider tidak ditemukan.");
                return;
            }
            addEditProviderForm.reset();
            clearFieldErrors(addEditProviderForm);
            addEditProviderMessageDiv.innerHTML = '';
            const saveButton = document.getElementById('save-add-edit-provider-button');

            if (providerIndex !== null && currentAdminProviderData[providerIndex]) {
                const provider = currentAdminProviderData[providerIndex];
                addEditProviderModalTitle.innerHTML = `<i class="fas fa-edit mr-3 text-blue-500"></i> Edit Provider`;
                providerIdInput.value = provider.id;
                providerNameInput.value = provider.name || '';
                providerApiUrlInput.value = provider.api_url || '';
                providerApiIdInput.value = provider.api_id || '';
                providerStatusSelect.value = provider.status || 'active';
                if(saveButton) saveButton.textContent = 'Simpan Perubahan';
                providerApiKeyInput.required = false; 
                providerSecretKeyInput.required = false; 
                providerApiKeyInput.value = ''; 
                providerSecretKeyInput.value = ''; 
                providerApiKeyInput.placeholder = 'Kosongkan jika tidak ingin ganti API Key';
                providerSecretKeyInput.placeholder = 'Kosongkan jika tidak ingin ganti Secret Key';

            } else {
                addEditProviderModalTitle.innerHTML = `<i class="fas fa-plus-circle mr-3 text-green-500"></i> Tambah Provider Baru`;
                providerIdInput.value = '';
                providerApiKeyInput.required = true; 
                providerApiKeyInput.placeholder = 'API Key dari provider';
                providerSecretKeyInput.placeholder = 'Secret Key jika diperlukan';
                if(saveButton) saveButton.textContent = 'Simpan Provider';
            }
            openModal(addEditProviderModal, addEditProviderModalContent);
        }


        if(addProviderButton) {
            addProviderButton.addEventListener('click', () => openAddEditProviderModal(null));
        }
        if(closeAddEditProviderModalButton) {
            closeAddEditProviderModalButton.addEventListener('click', () => closeModal(addEditProviderModal, addEditProviderModalContent));
        }
        if(cancelAddEditProviderButton) {
            cancelAddEditProviderButton.addEventListener('click', () => closeModal(addEditProviderModal, addEditProviderModalContent));
        }
        if(addEditProviderModal) {
            addEditProviderModal.addEventListener('click', (event) => { if (event.target === addEditProviderModal) closeModal(addEditProviderModal, addEditProviderModalContent); });
        }

        if(addEditProviderForm && saveAddEditProviderButton) {
            addEditProviderForm.addEventListener('submit', (event) => {
                event.preventDefault();
                clearFieldErrors(addEditProviderForm);
                if(addEditProviderMessageDiv) addEditProviderMessageDiv.innerHTML = '';
                const formData = new FormData(addEditProviderForm);
                const providerId = formData.get('provider_id');
                const isEditing = !!providerId;
                const ajaxUrl = isEditing ? `${jsBaseUrl}/ajax/admin/update_provider` : `${jsBaseUrl}/ajax/admin/add_provider`;

                if (isEditing) {
                    if (formData.get('api_key') === '') {
                        formData.delete('api_key'); 
                    }
                    if (formData.get('secret_key') === '') {
                         formData.delete('secret_key');
                    }
                }
                const originalButtonText = saveAddEditProviderButton.textContent;
                saveAddEditProviderButton.textContent = 'Menyimpan...';
                saveAddEditProviderButton.disabled = true;

                fetch(ajaxUrl, {
                    method: 'POST',
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        closeModal(addEditProviderModal, addEditProviderModalContent);
                        displayGeneralMessage('admin-providers-message', data.message || `Provider berhasil ${isEditing ? 'diperbarui' : 'ditambahkan'}.`, 'success', 3000);
                        loadAdminProviders(currentAdminProviderParams);
                    } else {
                        if(addEditProviderMessageDiv) displayGeneralMessage('add-edit-provider-message', data.message || 'Gagal menyimpan.', 'error');
                        if (data.errors) {
                            for (const field in data.errors) {
                                displayFieldError(field, data.errors[field]);
                            }
                        }
                    }
                })
                .catch(error => {
                    console.error(`Fetch Error (${isEditing ? 'Update' : 'Add'} Provider):`, error);
                    if(addEditProviderMessageDiv) displayGeneralMessage('add-edit-provider-message', 'Terjadi masalah koneksi.', 'error');
                })
                .finally(() => {
                    saveAddEditProviderButton.textContent = originalButtonText;
                    saveAddEditProviderButton.disabled = false;
                });
            });
        }

        adminProvidersTableBody.addEventListener('click', (event) => {
            const editButton = event.target.closest('.admin-edit-provider-btn');
            const deleteButton = event.target.closest('.admin-delete-provider-btn');

            if (editButton && editButton.dataset.providerIndex) {
                const providerIndex = parseInt(editButton.dataset.providerIndex);
                openAddEditProviderModal(providerIndex);
            } else if (deleteButton && deleteButton.dataset.providerId && deleteButton.dataset.providerName) {
                const providerId = deleteButton.dataset.providerId;
                const providerName = deleteButton.dataset.providerName;
                showDeleteProviderConfirmationModal(providerId, providerName);
            }
        });

        function showDeleteProviderConfirmationModal(providerId, providerName) {
            const modal = document.getElementById('delete-provider-confirm-modal');
            const modalContent = document.getElementById('delete-provider-confirm-modal-content');
            const modalMessage = document.getElementById('delete-provider-confirm-modal-message');
            const confirmBtn = document.getElementById('confirm-delete-provider-btn');
            const cancelBtns = document.querySelectorAll('.close-confirm-delete-provider-btn');

            if (!modal || !modalContent || !modalMessage || !confirmBtn || cancelBtns.length === 0) {
                console.error("Elemen modal konfirmasi hapus provider atau tombolnya tidak ditemukan.");
                return;
            }

            modalMessage.innerHTML = `Apakah Anda yakin ingin menghapus provider <strong class="font-semibold text-gray-800">"${escapeHTML(providerName)}"</strong> (ID: ${escapeHTML(providerId)})?`;

            let confirmHandler;
            let cancelHandler;
            let overlayClickHandler;

            confirmHandler = () => {
                const idToDelete = providerId;
                const nameToDelete = providerName;
                const confirmButtonOriginalHTML = confirmBtn.innerHTML;
                confirmBtn.innerHTML = `<i class="fas fa-spinner fa-spin mr-2"></i> Menghapus...`;
                confirmBtn.disabled = true;
                cancelBtns.forEach(btn => btn.disabled = true);

                fetch(`${jsBaseUrl}/ajax/admin/delete_provider`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
                    body: JSON.stringify({ provider_id: idToDelete })
                })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        loadAdminProviders(currentAdminProviderParams);
                        displayGeneralMessage('admin-providers-message', data.message || `Provider "${nameToDelete}" berhasil dihapus.`, 'success', 4000);
                    } else {
                        displayGeneralMessage('admin-providers-message', data.message || 'Gagal menghapus provider.', 'error');
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Delete Provider):', error);
                    displayGeneralMessage('admin-providers-message', 'Error koneksi saat menghapus.', 'error');
                })
                .finally(() => {
                    confirmBtn.innerHTML = confirmButtonOriginalHTML;
                    confirmBtn.disabled = false;
                    cancelBtns.forEach(btn => btn.disabled = false);
                    closeModal(modal, modalContent);
                    const currentConfirmBtn = document.getElementById('confirm-delete-provider-btn');
                     if (currentConfirmBtn) currentConfirmBtn.removeEventListener('click', confirmHandler);
                });
            };

            cancelHandler = () => {
                closeModal(modal, modalContent);
                const currentConfirmBtn = document.getElementById('confirm-delete-provider-btn');
                 if (currentConfirmBtn) currentConfirmBtn.removeEventListener('click', confirmHandler);
                 cancelBtns.forEach(btn => {
                    btn.removeEventListener('click', cancelHandler);
                 });
                 modal.removeEventListener('click', overlayClickHandler);
            };

             overlayClickHandler = (event) => {
                 if (event.target === modal) {
                     cancelHandler();
                 }
             };

            const oldConfirmBtn = document.getElementById('confirm-delete-provider-btn');
            const newConfirmBtn = oldConfirmBtn.cloneNode(true);
            oldConfirmBtn.parentNode.replaceChild(newConfirmBtn, oldConfirmBtn);
            newConfirmBtn.addEventListener('click', confirmHandler, { once: true });

            cancelBtns.forEach(btn => {
                const oldCancelBtn = btn;
                const newCancelBtn = oldCancelBtn.cloneNode(true);
                oldCancelBtn.parentNode.replaceChild(newCancelBtn, oldCancelBtn);
                newCancelBtn.addEventListener('click', cancelHandler, { once: true });
            });

            modal.removeEventListener('click', overlayClickHandler);
            modal.addEventListener('click', overlayClickHandler);

            openModal(modal, modalContent);
        }

        loadAdminProviders(currentAdminProviderParams); 
    }

    const chatWidgetContainer = document.getElementById('chat-widget-container');

    if (chatWidgetContainer && typeof jsBaseUrl !== 'undefined' && jsBaseUrl && typeof currentLoggedInUserId !== 'undefined') {
        const toggleButton = document.getElementById('chat-widget-toggle');
        const chatWindow = document.getElementById('chat-widget-window');
        const messagesArea = document.getElementById('chat-widget-messages');
        const inputArea = document.getElementById('chat-widget-input-area');
        const optionsArea = document.getElementById('chat-widget-options');
        const textInputArea = document.getElementById('chat-widget-text-input');
        const textInput = document.getElementById('chat-user-input');
        const sendButton = document.getElementById('chat-send-button');
        const closeButtonHeader = document.getElementById('chat-widget-close-header');
        const chatIcon = document.getElementById('chat-widget-icon'); // Ikon comments
        const closeIcon = document.getElementById('chat-widget-close-icon'); // Ikon X

        if (!toggleButton || !chatWindow || !messagesArea || !inputArea || !optionsArea || !textInputArea || !textInput || !sendButton || !closeButtonHeader || !chatIcon || !closeIcon) {
            console.error("Chat Widget Error: Satu atau lebih elemen HTML inti widget tidak ditemukan.");
        } else {
            let chatState = 'initial';
            let currentOrderId = null;
            let isProcessing = false;
            let chatHistory = [];
            let lastUserMessageForTicket = "";
            let originalUserIntentMessage = "";
            let nextActionTypeFromAI = null;
            let orderIdToClarifyFromAI = null;
            let typingIndicatorElement = null;

            const chatStorageKey = `chatWidgetState_user_${currentLoggedInUserId || 'guest'}`;

            function escapeHTML(str) {
                if (typeof str !== 'string') return str;
                const map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' };
                return str.replace(/[&<>"']/g, function(m) { return map[m]; });
            }

            function cleanActionTags(text) {
                if (typeof text !== 'string') return text;
                return text.replace(/`?\[INTENT:[A-Z_]+(?:,ACTION_TYPE:[A-Z\/]+)?(?:,ORDER_ID:\d+)?\]`?/gi, '').trim();
            }

            function parseSimpleMarkdown(text) {
                if (typeof text !== 'string') return '';
                let html = text;
                html = cleanActionTags(html);
                html = html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
                html = html.replace(/\*\*(.*?)\*\*|__(.*?)__/g, '<strong>$1$2</strong>');
                html = html.replace(/(?<!\w|\*|_)(\*|_)(?!\s|\*|_)(.+?)(?<!\s|\*|_)(\1)(?!\w|\*|_)/g, '<em>$2</em>');
                const blocks = html.split(/\n\s*\n/);
                html = blocks.map(block => {
                    block = block.trim();
                    if (block === '') return '';
                    const lines = block.split('\n');
                    const isList = lines.every(line => line.match(/^\s*(\*|-)\s+.*/));
                    if (isList) {
                        let listHtml = '<ul class="list-disc list-inside ml-1 space-y-1">';
                        lines.forEach(line => {
                            const itemMatch = line.match(/^\s*(\*|-)\s+(.*)/);
                            if (itemMatch) {
                                listHtml += '<li>' + parseSimpleMarkdownInline(itemMatch[2].trim()) + '</li>';
                            }
                        });
                        listHtml += '</ul>';
                        return listHtml;
                    } else {
                        return '<p class="mb-2 last:mb-0">' + parseSimpleMarkdownInline(block.replace(/\n/g, '<br>')) + '</p>';
                    }
                }).join('');
                return html;
            }

            function parseSimpleMarkdownInline(text) {
                let inlineHtml = text;
                inlineHtml = inlineHtml.replace(/\*\*(.*?)\*\*|__(.*?)__/g, '<strong>$1$2</strong>');
                inlineHtml = inlineHtml.replace(/(?<!\w|\*|_)(\*|_)(?!\s|\*|_)(.+?)(?<!\s|\*|_)(\1)(?!\w|\*|_)/g, '<em>$2</em>');
                return inlineHtml;
            }

            function saveChatState() {
                try {
                    const stateToSave = {
                        userId: currentLoggedInUserId,
                        state: chatState,
                        orderId: currentOrderId,
                        history: chatHistory.slice(-10),
                        lastUserMessage: lastUserMessageForTicket,
                        originalIntent: originalUserIntentMessage,
                        nextActionTypeAI: nextActionTypeFromAI,
                        orderIdToClarifyAI: orderIdToClarifyFromAI
                    };
                    sessionStorage.setItem(chatStorageKey, JSON.stringify(stateToSave));
                } catch (e) { console.error("Error saving chat state:", e); }
            }

            function loadChatState() {
                try {
                    const savedStateJSON = sessionStorage.getItem(chatStorageKey);
                    if (savedStateJSON) {
                        const parsedState = JSON.parse(savedStateJSON);
                        if (parsedState.userId && parsedState.userId === currentLoggedInUserId) {
                            chatState = parsedState.state || 'initial';
                            currentOrderId = parsedState.orderId || null;
                            chatHistory = Array.isArray(parsedState.history) ? parsedState.history : [];
                            lastUserMessageForTicket = parsedState.lastUserMessage || "";
                            originalUserIntentMessage = parsedState.originalIntent || "";
                            nextActionTypeFromAI = parsedState.nextActionTypeAI || null;
                            orderIdToClarifyFromAI = parsedState.orderIdToClarifyAI || null;
                            renderChatHistory();
                            restoreUIState();
                            return;
                        } else {
                            sessionStorage.removeItem(chatStorageKey);
                        }
                    }
                    resetChat();
                } catch (e) {
                    console.error("Error loading chat state:", e);
                    sessionStorage.removeItem(chatStorageKey);
                    resetChat();
                }
            }

            function renderChatHistory() {
                messagesArea.innerHTML = '';
                chatHistory.forEach(msg => addMessageInternal(msg.text, msg.sender));
                setTimeout(() => { messagesArea.scrollTop = messagesArea.scrollHeight; }, 50);
            }

            function addMessageInternal(text, sender = 'bot') {
                const messageDiv = document.createElement('div');
                messageDiv.classList.add('chat-message', sender);
                let messageContent = sender === 'user' ? escapeHTML(text) : parseSimpleMarkdown(text);

                if (sender === 'user') {
                    messageDiv.innerHTML = `<div class="chat-bubble user">${messageContent}</div>`;
                } else {
                    const avatarDiv = `<div class="bot-avatar"><i class="fas fa-robot"></i></div>`;
                    const bubbleDiv = `<div class="chat-bubble bot">${messageContent}</div>`;
                    messageDiv.innerHTML = avatarDiv + bubbleDiv;
                }
                messagesArea.appendChild(messageDiv);
            }

            function removeTypingIndicator() {
                if (typingIndicatorElement && typingIndicatorElement.parentNode) {
                    typingIndicatorElement.remove();
                    typingIndicatorElement = null;
                }
            }

            function addMessage(text, sender = 'bot') {
                removeTypingIndicator();
                chatHistory.push({ text, sender });
                addMessageInternal(text, sender);
                setTimeout(() => { messagesArea.scrollTop = messagesArea.scrollHeight; }, 50);
                saveChatState();
            }

            function showTypingIndicator() {
                removeTypingIndicator();
                typingIndicatorElement = document.createElement('div');
                typingIndicatorElement.classList.add('chat-message', 'bot', 'typing-indicator-wrapper');
                const avatarDiv = `<div class="bot-avatar"><i class="fas fa-robot"></i></div>`;
                const bubbleDiv = `<div class="chat-bubble bot typing-indicator"><span></span><span></span><span></span></div>`;
                typingIndicatorElement.innerHTML = avatarDiv + bubbleDiv;
                messagesArea.appendChild(typingIndicatorElement);
                messagesArea.scrollTop = messagesArea.scrollHeight;
            }

            function showOptions(options, showEndChatButton = false) {
                optionsArea.innerHTML = '';
                optionsArea.classList.remove('hidden');
                textInputArea.classList.add('hidden');
                const existingEndChatBtnInput = inputArea.querySelector('.end-chat-input-btn');
                if (existingEndChatBtnInput) {
                    existingEndChatBtnInput.remove();
                }

                let titleText = '';
                if (chatState === 'initial') titleText = 'Pilih topik bantuan:';
                else if (chatState === 'awaiting_order_action') titleText = `Pilih tindakan untuk pesanan #${currentOrderId || 'ini'}:`;
                else if (chatState === 'ai_failed') titleText = 'Asisten AI tidak dapat membantu. Pilih tindakan:';
                else if (chatState === 'awaiting_action_for_order_id') titleText = `Untuk pesanan #${orderIdToClarifyFromAI || 'ini'}, apa yang ingin Anda lakukan?`;


                if (titleText) {
                    const title = document.createElement('p');
                    title.className = 'option-title';
                    title.textContent = titleText;
                    optionsArea.appendChild(title);
                }

                options.forEach(opt => {
                    const button = document.createElement('button');
                    button.type = 'button';
                    button.dataset.action = opt.action;
                    let buttonClass = 'w-full px-4 py-2.5 text-sm font-medium rounded-xl border focus:outline-none focus:ring-2 focus:ring-offset-1 transition duration-150 ease-in-out text-left ';
                    if (opt.isDanger) {
                        buttonClass += 'danger-option';
                    } else if (opt.isSecondary) {
                        buttonClass += 'secondary-option';
                    } else {
                        buttonClass += 'primary-option';
                    }
                    button.className = buttonClass;
                    button.textContent = opt.label;
                    button.addEventListener('click', handleOptionClick);
                    optionsArea.appendChild(button);
                });

                if (showEndChatButton && chatState !== 'initial') {
                    const endChatButton = document.createElement('button');
                    endChatButton.type = 'button';
                    endChatButton.dataset.action = 'end_ai_chat';
                    endChatButton.className = 'w-full mt-2 px-4 py-2.5 text-sm font-medium rounded-xl border text-red-600 bg-white border-red-300 hover:bg-red-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-red-300 transition duration-150 ease-in-out text-left danger-option';
                    endChatButton.innerHTML = '<i class="fas fa-times-circle mr-2"></i> Akhiri Chat & Kembali ke Menu';
                    endChatButton.addEventListener('click', handleOptionClick);
                    optionsArea.appendChild(endChatButton);
                }
                saveChatState();
            }

            function showTextInput(placeholder = 'Ketik pesan Anda...', enableSend = true, showEndChatBtnInInput = true) {
                optionsArea.innerHTML = '';
                optionsArea.classList.add('hidden');
                textInputArea.classList.remove('hidden');
                textInput.placeholder = placeholder;
                textInput.value = '';
                sendButton.disabled = !enableSend;

                const existingEndChatBtn = inputArea.querySelector('.end-chat-input-btn');
                if (existingEndChatBtn) {
                    existingEndChatBtn.remove();
                }

                if (showEndChatBtnInInput && chatState !== 'initial') {
                    const endChatButtonInput = document.createElement('button');
                    endChatButtonInput.type = 'button';
                    endChatButtonInput.dataset.action = 'end_ai_chat';
                    endChatButtonInput.className = 'end-chat-input-btn';
                    endChatButtonInput.innerHTML = '<i class="fas fa-arrow-left mr-2"></i> Kembali ke Menu Utama';
                    endChatButtonInput.addEventListener('click', handleOptionClick);
                    inputArea.insertBefore(endChatButtonInput, textInputArea);
                }
                setTimeout(() => textInput.focus(), 100);
                saveChatState();
            }

            function resetChat(manualReset = false) {
                chatState = 'initial';
                currentOrderId = null;
                isProcessing = false;
                if (manualReset) chatHistory = [];
                lastUserMessageForTicket = "";
                originalUserIntentMessage = "";
                nextActionTypeFromAI = null;
                orderIdToClarifyFromAI = null;
                messagesArea.innerHTML = '';
                addMessageInternal('Halo! Saya Asisten Virtual SMM Panel Anda. Ada yang bisa dibantu? Silakan pilih opsi atau ketik pertanyaan Anda.', 'bot');
                showOptions([
                    { label: 'Komplain Pesanan', action: 'start_order_complaint' },
                    { label: 'Chat dengan AI', action: 'start_general_chat' }
                ], false);

                const existingEndChatBtnInput = inputArea.querySelector('.end-chat-input-btn');
                if (existingEndChatBtnInput) {
                    existingEndChatBtnInput.remove();
                }
                if (chatHistory.length > 0 && chatHistory[0].text.startsWith("Halo!")) {
                    chatHistory.shift();
                }
                if (manualReset) {
                    saveChatState();
                }
            }

            function restoreUIState() {
                if (chatState === 'awaiting_order_id_for_complaint') {
                    showTextInput('Masukkan ID Pesanan untuk komplain...', true, true);
                } else if (chatState === 'awaiting_order_id_for_ai_action') {
                    let placeholderText = 'Masukkan ID Pesanan...';
                    if(nextActionTypeFromAI === 'STATUS') placeholderText = `ID Pesanan untuk cek status?`;
                    else if(nextActionTypeFromAI === 'CANCEL') placeholderText = `ID Pesanan untuk dibatalkan?`;
                    else if(nextActionTypeFromAI === 'REFILL') placeholderText = `ID Pesanan untuk refill?`;
                    showTextInput(placeholderText, true, true);
                } else if (chatState === 'awaiting_action_for_order_id') {
                     showOptions([
                        { label: 'Cek Status Pesanan', action: 'provide_action_status' },
                        { label: 'Minta Pembatalan (Cancel)', action: 'provide_action_cancel' },
                        { label: 'Minta Isi Ulang (Refill)', action: 'provide_action_refill' },
                        { label: 'Bukan Pesanan Ini / Kembali', action: 'cancel_complaint', isSecondary: true }
                    ], true);
                }
                 else if (chatState === 'awaiting_order_action') {
                    showOptions([
                        { label: 'Minta Pembatalan (Cancel)', action: 'request_cancel' },
                        { label: 'Minta Isi Ulang (Refill)', action: 'request_refill' },
                        { label: 'Batalkan / Kembali', action: 'cancel_complaint', isSecondary: true }
                    ], true);
                } else if (chatState === 'general_chat') {
                    showTextInput('Ketik pesan Anda...', true, true);
                } else if (chatState === 'ai_failed') {
                    showOptions([
                        { label: 'Ya, Buat Tiket untuk Admin', action: 'create_ticket_after_ai_fail' },
                        { label: 'Tidak, Terima Kasih (Kembali)', action: 'cancel_after_ai_fail', isSecondary: true }
                    ], true);
                } else { // initial
                    showOptions([
                        { label: 'Komplain Pesanan', action: 'start_order_complaint' },
                        { label: 'Chat dengan AI', action: 'start_general_chat' }
                    ], false);
                }
            }

            function toggleChatWindow() {
                const isOpening = chatWindow.classList.contains('hidden');
                toggleButton.classList.toggle('open', isOpening); // Tambahkan/hapus kelas 'open' pada tombol utama

                if (isOpening) {
                    chatWindow.classList.remove('hidden');
                    void chatWindow.offsetWidth; // Trigger reflow untuk animasi
                    chatWindow.classList.remove('opacity-0', 'scale-90');
                    chatWindow.classList.add('opacity-100', 'scale-100');
                    loadChatState();
                    setTimeout(() => {
                        if (!textInputArea.classList.contains('hidden')) textInput.focus();
                        messagesArea.scrollTop = messagesArea.scrollHeight;
                    }, 50); // Sedikit delay untuk memastikan elemen visible sebelum fokus
                } else {
                    chatWindow.classList.remove('opacity-100', 'scale-100');
                    chatWindow.classList.add('opacity-0', 'scale-90');
                    setTimeout(() => {
                        chatWindow.classList.add('hidden');
                    }, 300); // Sesuaikan dengan durasi transisi CSS
                }
            }


            function handleOptionClick(event) {
                if (isProcessing) return;
                const action = event.target.dataset.action;
                const label = event.target.textContent;

                addMessage(label, 'user');
                isProcessing = true;
                optionsArea.querySelectorAll('button').forEach(btn => btn.disabled = true);
                showTypingIndicator();

                setTimeout(() => {
                    let userMessageForAI = label;

                    if (action === 'start_order_complaint') {
                        chatState = 'awaiting_order_id_for_complaint';
                        addMessage('Baik, silakan masukkan ID Pesanan Anda (contoh: 12345).', 'bot');
                        showTextInput('Masukkan ID Pesanan...', true, true);
                    } else if (action === 'start_general_chat') {
                        chatState = 'general_chat';
                        originalUserIntentMessage = "";
                        addMessage('Silakan ketik pertanyaan atau pesan Anda untuk dijawab oleh asisten AI.', 'bot');
                        showTextInput('Ketik pertanyaan Anda...', true, true);
                    } else if (action === 'request_cancel' || action === 'provide_action_cancel') {
                        addMessage(`Membuat tiket untuk permintaan pembatalan pesanan #${currentOrderId || orderIdToClarifyFromAI}...`, 'bot');
                        createTicket(`Request Pembatalan Pesanan #${currentOrderId || orderIdToClarifyFromAI}`, `User meminta pembatalan untuk pesanan ID: ${currentOrderId || orderIdToClarifyFromAI}`);
                        addMessage('Permintaan pembatalan Anda telah diteruskan ke Admin via tiket.', 'bot');
                        setTimeout(() => resetChat(true), 3000);
                    } else if (action === 'request_refill' || action === 'provide_action_refill') {
                        addMessage(`Membuat tiket untuk permintaan isi ulang (refill) pesanan #${currentOrderId || orderIdToClarifyFromAI}...`, 'bot');
                        createTicket(`Request Refill Pesanan #${currentOrderId || orderIdToClarifyFromAI}`, `User meminta refill untuk pesanan ID: ${currentOrderId || orderIdToClarifyFromAI}`);
                        addMessage('Permintaan isi ulang (refill) Anda telah diteruskan ke Admin via tiket.', 'bot');
                        setTimeout(() => resetChat(true), 3000);
                    } else if (action === 'provide_action_status') {
                        userMessageForAI = `Cek status untuk pesanan ID ${orderIdToClarifyFromAI}`;
                        lastUserMessageForTicket = userMessageForAI;
                        originalUserIntentMessage = userMessageForAI;
                        getAiChatResponse(userMessageForAI);
                    }
                    else if (action === 'cancel_complaint' || action === 'cancel_after_ai_fail' || action === 'end_ai_chat') {
                        addMessage('Baik, kembali ke menu utama.', 'bot');
                        resetChat(true);
                    } else if (action === 'create_ticket_after_ai_fail') {
                        if (lastUserMessageForTicket) {
                            addMessage('Membuat tiket untuk pertanyaan Anda...', 'bot');
                            createTicket(`Chat Lanjutan: ${lastUserMessageForTicket.substring(0, 50)}...`, `Pesan asli pengguna setelah AI tidak dapat menjawab: ${lastUserMessageForTicket}`);
                            addMessage('Tiket telah dibuat untuk pertanyaan Anda. Admin akan segera merespons.', 'bot');
                        } else {
                            addMessage('Tidak ada pesan sebelumnya untuk dibuatkan tiket.', 'bot');
                        }
                        setTimeout(() => resetChat(true), 3000);
                    }

                    if(chatState !== 'initial' && optionsArea.querySelectorAll('button').length > 0) {
                        optionsArea.querySelectorAll('button').forEach(btn => btn.disabled = false);
                    }
                    isProcessing = false;
                    removeTypingIndicator();
                }, 500);
            }

            function handleTextInputSubmit() {
                if (isProcessing) return;
                const userInput = textInput.value.trim();
                if (!userInput) return;

                addMessage(userInput, 'user');
                textInput.value = '';
                isProcessing = true;
                showTextInput('Memproses...', false, true);
                showTypingIndicator();

                lastUserMessageForTicket = userInput;
                if (chatState === 'general_chat' && !originalUserIntentMessage) {
                    originalUserIntentMessage = userInput;
                }
                getAiChatResponse(userInput);
            }


            function getAiChatResponse(userMessage) {
                const ajaxUrl = `${jsBaseUrl}/ajax/get_ai_response`;
                const formData = new FormData();
                formData.append('user_message', userMessage);

                fetch(ajaxUrl, { method: 'POST', body: formData })
                    .then(response => {
                        if (!response.ok) {
                            if(response.status === 404) throw new Error(`Endpoint AI tidak ditemukan (404).`);
                            return response.json().catch(() => null).then(errData => { throw new Error(errData?.message || `Error ${response.status}`); });
                        }
                        return response.json();
                    })
                    .then(data => {
                        removeTypingIndicator();
                        if (data.success && data.ai_response) {
                            addMessage(data.ai_response, 'bot');

                            if (data.action_taken === 'ASK_FOR_ORDER_ID' && data.next_action_type) {
                                chatState = 'awaiting_order_id_for_ai_action';
                                nextActionTypeFromAI = data.next_action_type;
                                orderIdToClarifyFromAI = null;
                                let placeholderText = 'Silakan masukkan ID Pesanan Anda...';
                                if(nextActionTypeFromAI === 'STATUS') placeholderText = `ID Pesanan untuk cek status?`;
                                else if(nextActionTypeFromAI === 'CANCEL') placeholderText = `ID Pesanan untuk dibatalkan?`;
                                else if(nextActionTypeFromAI === 'REFILL') placeholderText = `ID Pesanan untuk refill?`;
                                showTextInput(placeholderText, true, true);
                            } else if (data.action_taken === 'ASK_FOR_ACTION' && data.order_id_to_clarify) {
                                chatState = 'awaiting_action_for_order_id';
                                orderIdToClarifyFromAI = data.order_id_to_clarify;
                                nextActionTypeFromAI = null;
                                showOptions([
                                    { label: 'Cek Status Pesanan', action: 'provide_action_status' },
                                    { label: 'Minta Pembatalan (Cancel)', action: 'provide_action_cancel' },
                                    { label: 'Minta Isi Ulang (Refill)', action: 'provide_action_refill' },
                                    { label: 'Bukan Pesanan Ini / Kembali', action: 'cancel_complaint', isSecondary: true }
                                ], true);
                            } else if (data.action_taken === 'VALIDATE_ORDER_AND_PROCESS') {
                                chatState = 'general_chat';
                                originalUserIntentMessage = "";
                                nextActionTypeFromAI = null;
                                orderIdToClarifyFromAI = null;
                                currentOrderId = null;
                                showTextInput('Ada lagi yang bisa dibantu?', true, true);
                            } else {
                                chatState = 'general_chat';
                                originalUserIntentMessage = "";
                                nextActionTypeFromAI = null;
                                orderIdToClarifyFromAI = null;
                                showTextInput('Ada lagi yang bisa dibantu?', true, true);
                            }
                        } else {
                            chatState = 'ai_failed';
                            let errorMessage = data.message || 'Maaf, saya tidak bisa merespons saat ini.';
                            errorMessage += '<br><br>Apakah Anda ingin membuat tiket untuk bantuan lebih lanjut dari Admin?';
                            addMessage(errorMessage, 'bot');
                            showOptions([
                                { label: 'Ya, Buat Tiket untuk Admin', action: 'create_ticket_after_ai_fail' },
                                { label: 'Tidak, Terima Kasih (Kembali)', action: 'cancel_after_ai_fail', isSecondary: true }
                            ], true);
                        }
                    })
                    .catch(error => {
                        removeTypingIndicator();
                        console.error("Error fetching AI response:", error);
                        chatState = 'ai_failed';
                        addMessage(`Maaf, terjadi masalah koneksi dengan asisten AI (${error.message}).`, 'bot');
                        showOptions([
                            { label: 'Buat Tiket Bantuan Admin', action: 'create_ticket_after_ai_fail' },
                            { label: 'Tutup Chat', action: 'cancel_after_ai_fail', isSecondary: true }
                        ], true);
                    })
                    .finally(() => {
                        isProcessing = false;
                        if (textInputArea.classList.contains('hidden') && optionsArea.classList.contains('hidden') && chatState !== 'ai_failed' && chatState !== 'awaiting_order_action' && chatState !== 'awaiting_action_for_order_id') {
                           showTextInput('Ada lagi yang bisa dibantu?', true, true);
                        }
                    });
            }
             function validateOrderIdForComplaint(orderId) {
                removeTypingIndicator();
                if (!/^\d+$/.test(orderId)) {
                    addMessage('Format ID Pesanan tidak valid. Mohon masukkan angka saja.', 'bot');
                    showTextInput('Masukkan ID Pesanan yang benar...', true, true);
                    isProcessing = false; return;
                }
                showTypingIndicator();
                const validationUrl = `${jsBaseUrl}/ajax/validate_user_order?order_id=${encodeURIComponent(orderId)}`;
                fetch(validationUrl)
                    .then(response => {
                        if (!response.ok) {
                            if(response.status === 404) throw new Error(`Endpoint validasi tidak ditemukan (404).`);
                            return response.json().catch(() => null).then(errData => { throw new Error(errData?.message || `Error ${response.status}`); });
                        }
                        return response.json();
                    })
                    .then(data => {
                        removeTypingIndicator();
                        if (data.success) {
                            currentOrderId = orderId;
                            chatState = 'awaiting_order_action';
                            addMessage(`Baik, untuk pesanan #${currentOrderId}, apa yang ingin Anda lakukan?`, 'bot');
                            showOptions([
                                { label: 'Minta Pembatalan (Cancel)', action: 'request_cancel' },
                                { label: 'Minta Isi Ulang (Refill)', action: 'request_refill' },
                                { label: 'Batalkan / Kembali', action: 'cancel_complaint', isSecondary: true }
                            ], true);
                        } else {
                            addMessage(data.message || 'ID Pesanan tidak valid/ditemukan.', 'bot');
                            showTextInput('Masukkan ID Pesanan yang benar...', true, true);
                        }
                    })
                    .catch(error => {
                        removeTypingIndicator();
                        console.error("Error validating Order ID for complaint:", error);
                        addMessage(`Masalah memeriksa ID Pesanan (${error.message}).`, 'bot');
                        showTextInput('Masukkan ID Pesanan...', true, true);
                    })
                    .finally(() => {
                        isProcessing = false;
                        if(chatState === 'awaiting_order_id_for_complaint' && optionsArea.classList.contains('hidden')){
                            showTextInput('Masukkan ID Pesanan yang benar...', true, true);
                        }
                    });
            }


            function createTicket(subject, message) {
                const ajaxUrl = `${jsBaseUrl}/ajax/create_ticket_from_chat`;
                const formData = new FormData();
                formData.append('subject', subject);
                formData.append('message', message);
                fetch(ajaxUrl, { method: 'POST', body: formData })
                .then(response => response.json())
                .then(data => {
                    if (data.success && data.ticket_id) console.log(`Tiket #${data.ticket_id} dibuat dari chat.`);
                    else {
                        addMessage(`Gagal membuat tiket (${data.message || 'Error'}).`, 'bot');
                        console.error("Gagal membuat tiket dari chat:", data);
                    }
                })
                .catch(error => {
                    addMessage('Masalah koneksi saat meneruskan permintaan.', 'bot');
                    console.error("Error koneksi saat createTicket from chat:", error);
                });
            }

            if (toggleButton) toggleButton.addEventListener('click', toggleChatWindow);
            if (closeButtonHeader) closeButtonHeader.addEventListener('click', toggleChatWindow);
            if (sendButton) sendButton.addEventListener('click', handleTextInputSubmit);
            if (textInput) textInput.addEventListener('keypress', function(e) {
                if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleTextInputSubmit(); }
            });

            loadChatState();
            if (chatWindow.classList.contains('hidden')) {
                // Initial state: widget closed, icon should be comments
                toggleButton.classList.remove('open');
            } else {
                // Widget was likely open on page load (e.g. from session restore)
                toggleButton.classList.add('open');
                restoreUIState(); // Ensure UI matches loaded state
            }

        }
    } else {
        if (!chatWidgetContainer) console.log("Chat Widget: Container (chat-widget-container) not found.");
        if (typeof jsBaseUrl === 'undefined' || !jsBaseUrl) console.error("Chat Widget: jsBaseUrl is not defined or empty.");
    }

    const depositHistoryTableBody = document.getElementById('deposit-history-table-body');
    const depositHistoryFilterModalButton = document.getElementById('deposit-history-filter-modal-button');
    const depositHistoryFilterModal = document.getElementById('deposit-history-filter-modal');
    const depositHistoryFilterModalContent = document.getElementById('deposit-history-filter-modal-content');
    const closeDepositHistoryFilterModalButton = document.getElementById('close-deposit-history-filter-modal');
    const depositHistoryFilterForm = document.getElementById('deposit-history-filter-form');
    const resetDepositHistoryFilterButton = document.getElementById('reset-deposit-history-filter-button');
    const depositHistoryPaginationInfo = document.getElementById('deposit-history-pagination-info');
    const depositHistoryPaginationControls = document.getElementById('deposit-history-pagination-controls');
    const depositHistoryMessageDiv = document.getElementById('deposit-history-message');

    if (depositHistoryTableBody && depositHistoryFilterModalButton && depositHistoryFilterForm && jsBaseUrl) {
        let currentDepositHistoryParams = {
            page: 1,
            limit: 10,
            status: 'all',
            sort_by: 'd.created_at',
            sort_type: 'DESC',
            search_keyword: '',
            date_start: '',
            date_end: ''
        };

        function loadDepositHistory(params = {}) {
            depositHistoryTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-16 text-center text-sm text-gray-400 italic"><i class="fas fa-spinner fa-spin mr-2 text-xl"></i> Memuat riwayat deposit...</td></tr>`;
            if (depositHistoryPaginationInfo) depositHistoryPaginationInfo.textContent = 'Memuat...';
            if (depositHistoryPaginationControls) depositHistoryPaginationControls.innerHTML = '';
            if (depositHistoryMessageDiv) depositHistoryMessageDiv.innerHTML = '';

            currentDepositHistoryParams = { ...currentDepositHistoryParams, ...params };
            const queryParams = new URLSearchParams(currentDepositHistoryParams).toString();
            const url = `${jsBaseUrl}/ajax/get_deposit_history?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.deposits && data.pagination) {
                        renderDepositHistoryTable(data.deposits);
                        renderDepositHistoryPagination(data.pagination);
                    } else {
                        depositHistoryTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-16 text-center text-sm text-red-400 italic">${escapeHTML(data.message || 'Gagal memuat data.')}</td></tr>`;
                        if (depositHistoryPaginationInfo) depositHistoryPaginationInfo.textContent = 'Gagal memuat data.';
                        displayGeneralMessage('deposit-history-message', data.message || 'Gagal memuat data.', 'error');
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Deposit History):', error);
                    depositHistoryTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-16 text-center text-sm text-red-400 italic">Error koneksi saat memuat riwayat.</td></tr>`;
                    if (depositHistoryPaginationInfo) depositHistoryPaginationInfo.textContent = 'Error koneksi.';
                    displayGeneralMessage('deposit-history-message', 'Error koneksi saat memuat riwayat.', 'error');
                });
        }

        function renderDepositHistoryTable(deposits) {
            depositHistoryTableBody.innerHTML = '';
            if (deposits.length === 0) {
                depositHistoryTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-16 text-center text-sm text-gray-500 italic">Tidak ada riwayat deposit yang cocok dengan filter.</td></tr>`;
                return;
            }
            deposits.forEach((deposit) => {
                const row = document.createElement('tr');
                row.className = 'hover:bg-gray-700 transition-colors duration-150 text-xs';
                const formattedDateTime = formatLocalDate(deposit.created_at);
                const statusBadgeClass = getStatusBadgeClass(deposit.status);
                const statusText = deposit.status ? deposit.status.charAt(0).toUpperCase() + deposit.status.slice(1) : 'N/A';
                const methodLogoHtml = deposit.method_logo ? `<img src="${escapeHTML(deposit.method_logo)}" alt="${escapeHTML(deposit.method_name)}" class="h-5 w-auto mr-2 inline-block bg-white p-0.5 rounded-sm object-contain">` : `<i class="fas fa-credit-card text-gray-400 mr-2"></i>`;

                row.innerHTML = `
                    <td class="px-4 py-3 whitespace-nowrap text-gray-300 font-medium">${escapeHTML(deposit.deposit_id)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-gray-400">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-5 py-3 whitespace-nowrap text-gray-200 flex items-center">${methodLogoHtml} ${escapeHTML(deposit.method_name)}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-right text-gray-200">Rp ${escapeHTML(parseFloat(deposit.amount).toLocaleString('id-ID'))}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-right text-green-400">+Rp ${escapeHTML(parseFloat(deposit.bonus).toLocaleString('id-ID'))}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-right text-cyan-400 font-semibold">Rp ${escapeHTML(parseFloat(deposit.received_amount).toLocaleString('id-ID'))}</td>
                    <td class="px-4 py-3 whitespace-nowrap text-center">
                        <span class="px-2.5 py-1 inline-flex text-xs leading-tight font-semibold rounded-full ${statusBadgeClass} shadow-sm">
                            ${escapeHTML(statusText)}
                        </span>
                    </td>
                    <td class="px-4 py-3 whitespace-nowrap text-center">
                        <a href="${jsBaseUrl}/deposit/invoice/${escapeHTML(deposit.paydisini_unique_code)}" class="text-purple-400 hover:text-purple-300 hover:underline" title="Lihat Invoice">
                            <i class="fas fa-eye mr-1"></i> Invoice
                        </a>
                    </td>
                `;
                depositHistoryTableBody.appendChild(row);
            });
        }

        function renderDepositHistoryPagination(pagination) {
            if (!depositHistoryPaginationControls || !depositHistoryPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                depositHistoryPaginationInfo.textContent = 'Tidak ada data.';
                depositHistoryPaginationControls.innerHTML = '';
                return;
            }
            depositHistoryPaginationInfo.textContent = `Menampilkan ${pagination.offset + 1} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} deposit. (Hal ${pagination.currentPage}/${pagination.totalPages})`;
            depositHistoryPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;

            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;

            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="deposit-history-pagination-link px-3 py-1.5 border rounded-md transition-colors text-xs ${currentPage > 1 ? 'bg-gray-600 hover:bg-gray-500 text-gray-200 border-gray-500' : 'bg-gray-700 text-gray-500 border-gray-600 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Seb</button>`;
            const maxPagesToShow = 3;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if (endPage === totalPages && totalPages > maxPagesToShow) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }
            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="deposit-history-pagination-link px-3 py-1.5 border rounded-md bg-gray-600 hover:bg-gray-500 text-gray-200 border-gray-500 transition-colors text-xs">1</button>`;
                if (startPage > 2) paginationHTML += `<span class="px-3 py-1.5 text-gray-500">...</span>`;
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-cyan-500 text-white border-cyan-500 z-10' : 'bg-gray-600 hover:bg-gray-500 text-gray-200 border-gray-500';
                paginationHTML += `<button type="button" data-page="${i}" class="deposit-history-pagination-link px-3 py-1.5 border rounded-md ${activeClass} transition-colors text-xs">${i}</button>`;
            }
            if (endPage < totalPages) {
                if (endPage < totalPages - 1) paginationHTML += `<span class="px-3 py-1.5 text-gray-500">...</span>`;
                paginationHTML += `<button type="button" data-page="${totalPages}" class="deposit-history-pagination-link px-3 py-1.5 border rounded-md bg-gray-600 hover:bg-gray-500 text-gray-200 border-gray-500 transition-colors text-xs">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="deposit-history-pagination-link px-3 py-1.5 border rounded-md transition-colors text-xs ${currentPage < totalPages ? 'bg-gray-600 hover:bg-gray-500 text-gray-200 border-gray-500' : 'bg-gray-700 text-gray-500 border-gray-600 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berik &raquo;</button>`;
            depositHistoryPaginationControls.innerHTML = paginationHTML;
        }

        if (depositHistoryFilterModalButton && depositHistoryFilterModal && closeDepositHistoryFilterModalButton && depositHistoryFilterModalContent) {
            depositHistoryFilterModalButton.addEventListener('click', () => openModal(depositHistoryFilterModal, depositHistoryFilterModalContent));
            closeDepositHistoryFilterModalButton.addEventListener('click', () => closeModal(depositHistoryFilterModal, depositHistoryFilterModalContent));
            depositHistoryFilterModal.addEventListener('click', (event) => { if (event.target === depositHistoryFilterModal) closeModal(depositHistoryFilterModal, depositHistoryFilterModalContent); });
        }

        if (depositHistoryFilterForm) {
            depositHistoryFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(depositHistoryFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                newParams.page = 1;
                loadDepositHistory(newParams);
                closeModal(depositHistoryFilterModal, depositHistoryFilterModalContent);
            });
        }

        if (resetDepositHistoryFilterButton && depositHistoryFilterForm) {
            resetDepositHistoryFilterButton.addEventListener('click', () => {
                depositHistoryFilterForm.reset();
                // Set default values for select elements after reset
                const defaultParams = {
                    limit: '10',
                    status: 'all',
                    date_start: '',
                    date_end: '',
                    search_keyword: '',
                    sort_by: 'd.created_at',
                    sort_type: 'DESC'
                };
                for (const key in defaultParams) {
                    const element = depositHistoryFilterForm.elements[key];
                    if (element) {
                        element.value = defaultParams[key];
                    }
                }
                depositHistoryFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }


        if (depositHistoryPaginationControls) {
            depositHistoryPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.deposit-history-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) loadDepositHistory({ page: pageToGo });
                }
            });
        }

        // Function to apply initial URL parameters to the filter form
        function applyInitialUrlParamsToForm() {
            const urlParams = new URLSearchParams(window.location.search);
            let paramsApplied = false;
            urlParams.forEach((value, key) => {
                const inputElement = depositHistoryFilterForm.elements[key];
                if (inputElement) {
                    inputElement.value = value;
                    paramsApplied = true;
                }
            });
            return paramsApplied;
        }

        // Load initial data
        if (applyInitialUrlParamsToForm()) {
            // If params from URL were applied, submit the form to load data with these filters
            depositHistoryFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
        } else {
            // Otherwise, load with default params
            loadDepositHistory(currentDepositHistoryParams);
        }
    }

    const depositReportFilterForm = document.getElementById('deposit-report-filter-form');
    const depositChartCanvas = document.getElementById('depositChart');
    const depositStatusSummaryContainer = document.getElementById('deposit-status-summary-container');
    const depositReportMessageDiv = document.getElementById('deposit-report-message');
    const depositChartLoadingPlaceholder = document.getElementById('deposit-chart-loading-placeholder');

    if (depositReportFilterForm && depositChartCanvas && depositStatusSummaryContainer && jsBaseUrl) {
        let depositChartInstance = null;

        function loadDepositReport(startDate, endDate) {
            if(depositReportMessageDiv) depositReportMessageDiv.innerHTML = '';
            if(depositChartLoadingPlaceholder) depositChartLoadingPlaceholder.style.display = 'flex';
            if(depositStatusSummaryContainer) depositStatusSummaryContainer.innerHTML = `<div class="col-span-full flex items-center justify-center p-6 bg-gray-700 rounded-lg text-sm text-gray-400 italic"><span>Memuat ringkasan status...</span><i class="fas fa-spinner fa-spin ml-2"></i></div>`;
            setButtonLoading('apply-deposit-report-filter', 'deposit-report-filter-btn-text', 'deposit-report-filter-spinner', true);

            const params = new URLSearchParams({ date_start: startDate, date_end: endDate });
            const url = `${jsBaseUrl}/ajax/get_deposit_report?${params.toString()}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.chartData && data.statusSummary) {
                        renderDepositChart(data.chartData);
                        renderDepositStatusSummary(data.statusSummary);
                    } else {
                        displayGeneralMessage('deposit-report-message', data.message || 'Gagal memuat data laporan deposit.', 'error');
                        if (depositChartInstance) depositChartInstance.destroy();
                        if(depositStatusSummaryContainer) depositStatusSummaryContainer.innerHTML = `<p class="col-span-full text-center text-red-400 italic py-6">Gagal memuat ringkasan.</p>`;
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Deposit Report):', error);
                    displayGeneralMessage('deposit-report-message', 'Error koneksi saat memuat laporan deposit.', 'error');
                    if (depositChartInstance) depositChartInstance.destroy();
                    if(depositStatusSummaryContainer) depositStatusSummaryContainer.innerHTML = `<p class="col-span-full text-center text-red-400 italic py-6">Error koneksi.</p>`;
                })
                .finally(() => {
                    if(depositChartLoadingPlaceholder) depositChartLoadingPlaceholder.style.display = 'none';
                    setButtonLoading('apply-deposit-report-filter', 'deposit-report-filter-btn-text', 'deposit-report-filter-spinner', false);
                });
        }

        function renderDepositChart(chartData) {
            if (!depositChartCanvas) return;
            const ctx = depositChartCanvas.getContext('2d');
            if (depositChartInstance) {
                depositChartInstance.destroy();
            }
            depositChartInstance = new Chart(ctx, {
                type: 'line',
                data: {
                    labels: chartData.labels,
                    datasets: chartData.datasets.map(dataset => ({
                        ...dataset,
                        tension: 0.3,
                        pointBackgroundColor: dataset.borderColor,
                        pointBorderColor: '#1f2937', // bg-gray-800
                        pointHoverRadius: 7,
                        pointHoverBackgroundColor: dataset.borderColor,
                        pointHoverBorderColor: '#1f2937',
                        pointRadius: 5,
                    }))
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        x: {
                            type: 'time',
                            time: {
                                unit: 'day',
                                tooltipFormat: 'dd MMM yy',
                                displayFormats: { day: 'dd MMM' }
                            },
                            grid: { color: 'rgba(107, 114, 128, 0.3)' }, // text-gray-500
                            ticks: { color: '#d1d5db' } // text-gray-300
                        },
                        yAmount: {
                            type: 'linear',
                            position: 'left',
                            beginAtZero: true,
                            grid: { color: 'rgba(107, 114, 128, 0.3)' },
                            ticks: {
                                color: '#d1d5db',
                                callback: function(value) { return 'Rp ' + value.toLocaleString('id-ID'); }
                            },
                            title: { display: true, text: 'Jumlah (Rp)', color: '#d1d5db'}
                        },
                        yCount: {
                            type: 'linear',
                            position: 'right',
                            beginAtZero: true,
                            grid: { drawOnChartArea: false, color: 'rgba(107, 114, 128, 0.3)' },
                            ticks: {
                                color: '#d1d5db',
                                callback: function(value) { if (Number.isInteger(value)) { return value; } }
                            },
                            title: { display: true, text: 'Total Transaksi', color: '#d1d5db'}
                        }
                    },
                    plugins: {
                        legend: {
                            display: true,
                            position: 'top',
                            labels: { color: '#d1d5db', boxWidth: 12, padding: 15 }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(31, 41, 55, 0.9)', // bg-gray-800 with opacity
                            titleColor: '#e5e7eb', // text-gray-200
                            bodyColor: '#d1d5db', // text-gray-300
                            titleFont: { weight: 'bold' },
                            bodySpacing: 5,
                            padding: 12,
                            mode: 'index',
                            intersect: false,
                            callbacks: {
                                label: function(context) {
                                    let label = context.dataset.label || '';
                                    if (label) {
                                        label += ': ';
                                    }
                                    if (context.parsed.y !== null) {
                                        if (context.dataset.yAxisID === 'yAmount') {
                                            label += 'Rp ' + context.parsed.y.toLocaleString('id-ID');
                                        } else {
                                            label += context.parsed.y.toLocaleString('id-ID');
                                        }
                                    }
                                    return label;
                                }
                            }
                        }
                    },
                    interaction: {
                        mode: 'index',
                        intersect: false,
                    },
                }
            });
        }

        function renderDepositStatusSummary(summaryData) {
            if (!depositStatusSummaryContainer) return;
            depositStatusSummaryContainer.innerHTML = '';
            if (!Array.isArray(summaryData) || summaryData.length === 0) {
                depositStatusSummaryContainer.innerHTML = `<p class="col-span-full text-center text-gray-500 italic py-6">Tidak ada data ringkasan status.</p>`;
                return;
            }
            summaryData.forEach(item => {
                const div = document.createElement('div');
                const badgeClass = getStatusBadgeClass(item.status_key);
                div.className = `p-4 rounded-lg shadow-md flex flex-col justify-between ${badgeClass.replace('text-white', 'text-gray-100').replace('text-gray-800', 'text-gray-900')} bg-opacity-20 border border-opacity-30`;

                div.innerHTML = `
                    <div class="flex justify-between items-center mb-1">
                        <span class="text-sm font-semibold">${escapeHTML(item.status)}</span>
                        <span class="text-xs px-2 py-0.5 rounded-full ${badgeClass} bg-opacity-100 text-opacity-100">${escapeHTML(item.count.toLocaleString('id-ID'))} trx</span>
                    </div>
                    <p class="text-lg font-bold">${escapeHTML(item.total_amount_formatted)}</p>
                `;
                depositStatusSummaryContainer.appendChild(div);
            });
        }

        depositReportFilterForm.addEventListener('submit', (event) => {
            event.preventDefault();
            const startDate = document.getElementById('report_deposit_date_start').value;
            const endDate = document.getElementById('report_deposit_date_end').value;
            if (!startDate || !endDate) {
                displayGeneralMessage('deposit-report-message', 'Silakan pilih tanggal mulai dan tanggal akhir.', 'error', 3000);
                return;
            }
            if (new Date(endDate) < new Date(startDate)) {
                displayGeneralMessage('deposit-report-message', 'Tanggal akhir tidak boleh sebelum tanggal mulai.', 'error', 3000);
                return;
            }
            loadDepositReport(startDate, endDate);
        });

        const initialStartDate = document.getElementById('report_deposit_date_start').value;
        const initialEndDate = document.getElementById('report_deposit_date_end').value;
        if (initialStartDate && initialEndDate) {
            loadDepositReport(initialStartDate, initialEndDate);
        } else {
            if(depositChartLoadingPlaceholder) depositChartLoadingPlaceholder.style.display = 'none';
            if(depositStatusSummaryContainer) depositStatusSummaryContainer.innerHTML = `<p class="col-span-full text-center text-gray-500 italic py-6">Silakan pilih rentang tanggal untuk melihat laporan.</p>`;
        }
    }

    const adminBalanceLogsTableBody = document.getElementById('admin-balance-logs-table-body');
    const adminBalanceLogFilterModalButton = document.getElementById('admin-balance-log-filter-modal-button');
    const adminBalanceLogFilterModal = document.getElementById('admin-balance-log-filter-modal');
    const adminBalanceLogFilterModalContent = document.getElementById('admin-balance-log-filter-modal-content');
    const closeAdminBalanceLogFilterModalButton = document.getElementById('close-admin-balance-log-filter-modal');
    const adminBalanceLogFilterForm = document.getElementById('admin-balance-log-filter-form');
    const resetAdminBalanceLogFilterButton = document.getElementById('reset-admin-balance-log-filter-button');
    const adminBalanceLogsPaginationInfo = document.getElementById('admin-balance-logs-pagination-info');
    const adminBalanceLogsPaginationControls = document.getElementById('admin-balance-logs-pagination-controls');
    const adminBalanceLogsMessageDiv = document.getElementById('admin-balance-logs-message');

    if (adminBalanceLogsTableBody && adminBalanceLogFilterModalButton && adminBalanceLogFilterForm && jsBaseUrl) {
        let currentAdminBalanceLogParams = {
            page: 1,
            limit: 15,
            type: 'all',
            category: 'all',
            source: 'all',
            user_id: '',
            sort_by: 'bl.created_at',
            sort_type: 'DESC',
            search_column: 'bl.id',
            search_keyword: ''
        };

        function loadAdminBalanceLogs(params = {}) {
            adminBalanceLogsTableBody.innerHTML = `<tr><td colspan="10" class="px-6 py-24 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data mutasi saldo...</td></tr>`;
            if(adminBalanceLogsPaginationInfo) adminBalanceLogsPaginationInfo.textContent = 'Memuat...';
            if(adminBalanceLogsPaginationControls) adminBalanceLogsPaginationControls.innerHTML = '';
            if(adminBalanceLogsMessageDiv && !adminBalanceLogsMessageDiv.innerHTML.includes('success')) {
                adminBalanceLogsMessageDiv.innerHTML = '';
                adminBalanceLogsMessageDiv.className = 'mb-4 text-sm';
            }

            currentAdminBalanceLogParams = { ...currentAdminBalanceLogParams, ...params };
            const queryParams = new URLSearchParams(currentAdminBalanceLogParams).toString();
            const url = `${jsBaseUrl}/ajax/admin/get_admin_balance_logs?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.logs && data.pagination) {
                        renderAdminBalanceLogTable(data.logs);
                        renderAdminBalanceLogPagination(data.pagination);
                        if (adminBalanceLogsMessageDiv && !adminBalanceLogsMessageDiv.innerHTML.includes('success')) {
                            adminBalanceLogsMessageDiv.innerHTML = '';
                            adminBalanceLogsMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        adminBalanceLogsTableBody.innerHTML = `<tr><td colspan="10" class="px-6 py-24 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data mutasi saldo.')}</td></tr>`;
                        if(adminBalanceLogsPaginationInfo) adminBalanceLogsPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminBalanceLogsPaginationControls) adminBalanceLogsPaginationControls.innerHTML = '';
                        if (!adminBalanceLogsMessageDiv || !adminBalanceLogsMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('admin-balance-logs-message', data.message || 'Gagal memuat data mutasi saldo.', 'error');
                        }
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Admin Balance Logs):', error);
                    adminBalanceLogsTableBody.innerHTML = `<tr><td colspan="10" class="px-6 py-24 text-center text-sm text-red-500 italic">Error koneksi saat memuat mutasi saldo.</td></tr>`;
                    if(adminBalanceLogsPaginationInfo) adminBalanceLogsPaginationInfo.textContent = 'Error koneksi.';
                    if(adminBalanceLogsPaginationControls) adminBalanceLogsPaginationControls.innerHTML = '';
                     if (!adminBalanceLogsMessageDiv || !adminBalanceLogsMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('admin-balance-logs-message', 'Error koneksi saat memuat mutasi saldo.', 'error');
                     }
                });
        }

        function renderAdminBalanceLogTable(logs) {
            adminBalanceLogsTableBody.innerHTML = '';
            if (logs.length === 0) {
                adminBalanceLogsTableBody.innerHTML = `<tr><td colspan="10" class="px-6 py-24 text-center text-sm text-gray-500 italic">Tidak ada data mutasi saldo yang cocok dengan filter.</td></tr>`;
                return;
            }
            logs.forEach((log) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-xs');
                const formattedDateTime = formatLocalDate(log.created_at);
                const typeClass = log.type === 'credit' ? 'text-green-600 font-semibold' : 'text-red-600 font-semibold';
                const typeText = log.type === 'credit' ? 'Kredit' : 'Debit';
                const amountFormatted = 'Rp ' + parseFloat(log.amount).toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
                const beforeFormatted = 'Rp ' + parseFloat(log.balance_before).toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
                const afterFormatted = 'Rp ' + parseFloat(log.balance_after).toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 });

                let categoryText = log.category;
                switch(log.category) {
                    case 'deposit': categoryText = 'Deposit Saldo'; break;
                    case 'order_placement': categoryText = 'Pemesanan'; break;
                    case 'order_refund': categoryText = 'Refund Pesanan'; break;
                    case 'admin_adjustment': categoryText = 'Penyesuaian Admin'; break;
                    case 'other': categoryText = 'Lainnya'; break;
                }

                row.innerHTML = `
                    <td class="px-3 py-2.5 whitespace-nowrap text-gray-500">${escapeHTML(log.id)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-700 font-medium" title="User ID: ${escapeHTML(log.user_id)}">${escapeHTML(log.username)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-500">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-3 py-2.5 whitespace-nowrap text-gray-500 hidden md:table-cell">${escapeHTML(log.source.toUpperCase())}</td>
                    <td class="px-3 py-2.5 whitespace-nowrap text-center ${typeClass}">${escapeHTML(typeText)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-600">${escapeHTML(categoryText)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-right ${typeClass}">${log.type === 'credit' ? '+' : '-'}${escapeHTML(amountFormatted)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-right text-gray-500 hidden sm:table-cell">${escapeHTML(beforeFormatted)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-right text-gray-700 font-medium">${escapeHTML(afterFormatted)}</td>
                    <td class="px-6 py-2.5 text-gray-600 max-w-xs truncate" title="${escapeHTML(log.description || '')}">${escapeHTML(log.description || '-')}</td>
                `;
                adminBalanceLogsTableBody.appendChild(row);
            });
        }

        function renderAdminBalanceLogPagination(pagination) {
            if (!adminBalanceLogsPaginationControls || !adminBalanceLogsPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                adminBalanceLogsPaginationInfo.textContent = 'Tidak ada data.';
                adminBalanceLogsPaginationControls.innerHTML = '';
                return;
            }
            adminBalanceLogsPaginationInfo.textContent = `Menampilkan ${pagination.totalItems > 0 ? pagination.offset + 1 : 0} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} log. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminBalanceLogsPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;

            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;

            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-balance-log-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;

            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages && totalPages >= maxPagesToShow) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }

            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="admin-balance-log-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="admin-balance-log-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }
             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-balance-log-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-balance-log-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
            adminBalanceLogsPaginationControls.innerHTML = paginationHTML;
        }

        if(adminBalanceLogFilterModalButton && adminBalanceLogFilterModal && closeAdminBalanceLogFilterModalButton && adminBalanceLogFilterModalContent) {
            adminBalanceLogFilterModalButton.addEventListener('click', () => openModal(adminBalanceLogFilterModal, adminBalanceLogFilterModalContent));
            closeAdminBalanceLogFilterModalButton.addEventListener('click', () => closeModal(adminBalanceLogFilterModal, adminBalanceLogFilterModalContent));
            adminBalanceLogFilterModal.addEventListener('click', (event) => { if (event.target === adminBalanceLogFilterModal) closeModal(adminBalanceLogFilterModal, adminBalanceLogFilterModalContent); });
        }

        if(adminBalanceLogFilterForm) {
            adminBalanceLogFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(adminBalanceLogFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                newParams.page = 1;
                loadAdminBalanceLogs(newParams);
                closeModal(adminBalanceLogFilterModal, adminBalanceLogFilterModalContent);
            });
        }

        if(resetAdminBalanceLogFilterButton && adminBalanceLogFilterForm) {
            resetAdminBalanceLogFilterButton.addEventListener('click', () => {
                adminBalanceLogFilterForm.reset();
                document.getElementById('filter_limit_admin_log').value = '15';
                document.getElementById('filter_type_admin_log').value = 'all';
                document.getElementById('filter_category_admin_log').value = 'all';
                document.getElementById('filter_user_id_admin_log').value = '';
                document.getElementById('filter_source_admin_log').value = 'all';
                document.getElementById('filter_search_column_admin_log').value = 'bl.id';
                document.getElementById('filter_search_keyword_admin_log').value = '';
                document.getElementById('filter_sort_by_admin_log').value = 'bl.created_at';
                document.getElementById('filter_sort_type_admin_log').value = 'DESC';
                adminBalanceLogFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        if(adminBalanceLogsPaginationControls) {
            adminBalanceLogsPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-balance-log-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) { loadAdminBalanceLogs({ page: pageToGo }); }
                }
            });
        }
        loadAdminBalanceLogs(currentAdminBalanceLogParams);
    }

    const userBalanceLogsTableBody = document.getElementById('user-balance-logs-table-body');
    const userBalanceLogFilterModalButton = document.getElementById('user-balance-log-filter-modal-button');
    const userBalanceLogFilterModal = document.getElementById('user-balance-log-filter-modal');
    const userBalanceLogFilterModalContent = document.getElementById('user-balance-log-filter-modal-content');
    const closeUserBalanceLogFilterModalButton = document.getElementById('close-user-balance-log-filter-modal');
    const userBalanceLogFilterForm = document.getElementById('user-balance-log-filter-form');
    const resetUserBalanceLogFilterButton = document.getElementById('reset-user-balance-log-filter-button');
    const userBalanceLogsPaginationInfo = document.getElementById('user-balance-logs-pagination-info');
    const userBalanceLogsPaginationControls = document.getElementById('user-balance-logs-pagination-controls');
    const userBalanceLogsMessageDiv = document.getElementById('user-balance-logs-message');

    if (userBalanceLogsTableBody && userBalanceLogFilterModalButton && userBalanceLogFilterForm && jsBaseUrl) {
        let currentUserBalanceLogParams = {
            page: 1,
            limit: 10,
            type: 'all',
            category: 'all',
            reference_id: '',
            sort_by: 'bl.created_at',
            sort_type: 'DESC'
        };

        function loadUserBalanceLogs(params = {}) {
            userBalanceLogsTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-24 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data mutasi saldo Anda...</td></tr>`;
            if(userBalanceLogsPaginationInfo) userBalanceLogsPaginationInfo.textContent = 'Memuat...';
            if(userBalanceLogsPaginationControls) userBalanceLogsPaginationControls.innerHTML = '';
            if(userBalanceLogsMessageDiv && !userBalanceLogsMessageDiv.innerHTML.includes('success')) {
                userBalanceLogsMessageDiv.innerHTML = '';
                userBalanceLogsMessageDiv.className = 'mb-4 text-sm';
            }

            currentUserBalanceLogParams = { ...currentUserBalanceLogParams, ...params };
            const queryParams = new URLSearchParams(currentUserBalanceLogParams).toString();
            const url = `${jsBaseUrl}/ajax/get_balance_history?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.logs && data.pagination) {
                        renderUserBalanceLogTable(data.logs);
                        renderUserBalanceLogPagination(data.pagination);
                        if (userBalanceLogsMessageDiv && !userBalanceLogsMessageDiv.innerHTML.includes('success')) {
                            userBalanceLogsMessageDiv.innerHTML = '';
                            userBalanceLogsMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        userBalanceLogsTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-24 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data mutasi saldo.')}</td></tr>`;
                        if(userBalanceLogsPaginationInfo) userBalanceLogsPaginationInfo.textContent = 'Gagal memuat data.';
                        if(userBalanceLogsPaginationControls) userBalanceLogsPaginationControls.innerHTML = '';
                        if (!userBalanceLogsMessageDiv || !userBalanceLogsMessageDiv.innerHTML.includes('success')) {
                            displayGeneralMessage('user-balance-logs-message', data.message || 'Gagal memuat data mutasi saldo.', 'error');
                        }
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (User Balance Logs):', error);
                    userBalanceLogsTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-24 text-center text-sm text-red-500 italic">Error koneksi saat memuat mutasi saldo.</td></tr>`;
                    if(userBalanceLogsPaginationInfo) userBalanceLogsPaginationInfo.textContent = 'Error koneksi.';
                    if(userBalanceLogsPaginationControls) userBalanceLogsPaginationControls.innerHTML = '';
                     if (!userBalanceLogsMessageDiv || !userBalanceLogsMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('user-balance-logs-message', 'Error koneksi saat memuat mutasi saldo.', 'error');
                     }
                });
        }

        function renderUserBalanceLogTable(logs) {
            userBalanceLogsTableBody.innerHTML = '';
            if (logs.length === 0) {
                userBalanceLogsTableBody.innerHTML = `<tr><td colspan="6" class="px-6 py-24 text-center text-sm text-gray-500 italic">Tidak ada data mutasi saldo yang cocok dengan filter.</td></tr>`;
                return;
            }
            logs.forEach((log) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-xs');
                const formattedDateTime = formatLocalDate(log.created_at);
                const typeClass = log.type === 'credit' ? 'text-green-600 font-semibold' : 'text-red-600 font-semibold';
                const typeText = log.type === 'credit' ? 'Kredit' : 'Debit';
                const amountFormatted = 'Rp ' + parseFloat(log.amount).toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
                const afterFormatted = 'Rp ' + parseFloat(log.balance_after).toLocaleString('id-ID', { minimumFractionDigits: 2, maximumFractionDigits: 2 });

                let categoryText = log.category;
                switch(log.category) {
                    case 'deposit': categoryText = 'Deposit Saldo'; break;
                    case 'order_placement': categoryText = 'Pemesanan'; break;
                    case 'order_refund': categoryText = 'Refund Pesanan'; break;
                    case 'admin_adjustment': categoryText = 'Penyesuaian'; break; // Disederhanakan untuk user
                    case 'other': categoryText = 'Lainnya'; break;
                }

                row.innerHTML = `
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-500">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-3 py-2.5 whitespace-nowrap text-center ${typeClass}">${escapeHTML(typeText)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-600">${escapeHTML(categoryText)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-right ${typeClass}">${log.type === 'credit' ? '+' : '-'}${escapeHTML(amountFormatted)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-right text-gray-700 font-medium">${escapeHTML(afterFormatted)}</td>
                    <td class="px-6 py-2.5 text-gray-600 max-w-xs truncate" title="${escapeHTML(log.description || '')}">${escapeHTML(log.description || '-')}</td>
                `;
                userBalanceLogsTableBody.appendChild(row);
            });
        }

        function renderUserBalanceLogPagination(pagination) {
            if (!userBalanceLogsPaginationControls || !userBalanceLogsPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                userBalanceLogsPaginationInfo.textContent = 'Tidak ada data.';
                userBalanceLogsPaginationControls.innerHTML = '';
                return;
            }
            userBalanceLogsPaginationInfo.textContent = `Menampilkan ${pagination.totalItems > 0 ? pagination.offset + 1 : 0} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} log. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            userBalanceLogsPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;

            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;

            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="user-balance-log-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;

            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages && totalPages >= maxPagesToShow) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }

            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="user-balance-log-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="user-balance-log-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }
             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="user-balance-log-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="user-balance-log-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
            userBalanceLogsPaginationControls.innerHTML = paginationHTML;
        }

        if(userBalanceLogFilterModalButton && userBalanceLogFilterModal && closeUserBalanceLogFilterModalButton && userBalanceLogFilterModalContent) {
            userBalanceLogFilterModalButton.addEventListener('click', () => openModal(userBalanceLogFilterModal, userBalanceLogFilterModalContent));
            closeUserBalanceLogFilterModalButton.addEventListener('click', () => closeModal(userBalanceLogFilterModal, userBalanceLogFilterModalContent));
            userBalanceLogFilterModal.addEventListener('click', (event) => { if (event.target === userBalanceLogFilterModal) closeModal(userBalanceLogFilterModal, userBalanceLogFilterModalContent); });
        }

        if(userBalanceLogFilterForm) {
            userBalanceLogFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(userBalanceLogFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                newParams.page = 1;
                loadUserBalanceLogs(newParams);
                closeModal(userBalanceLogFilterModal, userBalanceLogFilterModalContent);
            });
        }

        if(resetUserBalanceLogFilterButton && userBalanceLogFilterForm) {
            resetUserBalanceLogFilterButton.addEventListener('click', () => {
                userBalanceLogFilterForm.reset();
                document.getElementById('filter_limit_user_log').value = '10';
                document.getElementById('filter_type_user_log').value = 'all';
                document.getElementById('filter_category_user_log').value = 'all';
                document.getElementById('filter_reference_id_user_log').value = '';
                document.getElementById('filter_sort_by_user_log').value = 'bl.created_at';
                document.getElementById('filter_sort_type_user_log').value = 'DESC';
                userBalanceLogFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        if(userBalanceLogsPaginationControls) {
            userBalanceLogsPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.user-balance-log-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) { loadUserBalanceLogs({ page: pageToGo }); }
                }
            });
        }
        loadUserBalanceLogs(currentUserBalanceLogParams);
    }
    // ========================================================
    // Logika untuk Pop-up Informasi Setelah Login
    // ========================================================
    const loginInformationModal = document.getElementById('login-information-modal');
    const loginInformationModalContent = document.getElementById('login-information-modal-content');
    const loginInformationModalTitle = document.getElementById('login-information-modal-title');
    const loginInformationModalBody = document.getElementById('login-information-modal-body');
    const closeLoginInformationModalHeaderButton = document.getElementById('close-login-information-modal-header');
    const markInfoAsReadButton = document.getElementById('mark-info-as-read-button');

    // Variabel global currentLoggedInUserId harus sudah di-set oleh PHP di template Anda
    // contoh: <script> const currentLoggedInUserId = <?php echo isset($_SESSION['user_id']) ? json_encode($_SESSION['user_id']) : 'null'; ?>; </script>

    if (loginInformationModal && loginInformationModalContent && loginInformationModalTitle && loginInformationModalBody && closeLoginInformationModalHeaderButton && markInfoAsReadButton && typeof jsBaseUrl !== 'undefined' && jsBaseUrl) {
        
        function showLoginInformationPopup() {
            const isLoggedIn = typeof currentLoggedInUserId !== 'undefined' && currentLoggedInUserId !== null;
            const currentPath = window.location.pathname;
            // Asumsi halaman login tidak mengandung '/dashboard' atau '/admin/' atau path spesifik lainnya setelah login
            const isLikelyPostLoginPage = currentPath.includes('/dashboard') || currentPath.includes('/admin/') || (currentPath.endsWith(jsBaseUrl + '/') && jsBaseUrl !== '');


            if (isLoggedIn && isLikelyPostLoginPage) {
                fetch(`${jsBaseUrl}/ajax/get_latest_information`)
                    .then(response => {
                        if (!response.ok) {
                            throw new Error(`HTTP error ${response.status}`);
                        }
                        return response.json();
                    })
                    .then(data => {
                        if (data.success && data.information) {
                            const info = data.information;
                            const infoSessionKey = `loginInfoPopupRead_${info.id}`;

                            if (sessionStorage.getItem(infoSessionKey)) {
                                console.log(`Informasi ID ${info.id} sudah dibaca dalam sesi ini.`);
                                return; 
                            }

                            loginInformationModalTitle.innerHTML = `<i class="fas fa-bullhorn mr-3 text-yellow-400"></i> ${escapeHTML(info.title || 'Informasi Penting')}`;
                            
                            let bodyHTML = '';
                            if (info.image_url) {
                                const placeholderUrl = `https://placehold.co/600x250/4A5568/E2E8F0?text=${encodeURIComponent(info.title || 'Informasi')}`;
                                const imageOnError = `this.onerror=null; this.src='${placeholderUrl}'; this.classList.add('object-contain');`;
                                bodyHTML += `
                                    <div class="mb-4 rounded-lg overflow-hidden shadow-md max-h-60 bg-gray-700 flex justify-center items-center">
                                        <img src="${escapeHTML(info.image_url)}" 
                                             alt="${escapeHTML(info.title)}" 
                                             class="w-full h-auto max-h-60 object-cover"
                                             onerror="${imageOnError}">
                                    </div>`;
                            }
                            
                            const formattedContent = info.content ? escapeHTML(info.content).replace(/(\r\n|\n|\r)/gm, "<br>") : '<p class="text-center text-gray-400 italic">Tidak ada detail informasi untuk ditampilkan.</p>';
                            bodyHTML += `<div class="prose prose-sm prose-invert max-w-none text-gray-300 leading-relaxed">${formattedContent}</div>`;
                            
                            loginInformationModalBody.innerHTML = bodyHTML;

                            const handleCloseAndMarkRead = () => {
                                sessionStorage.setItem(infoSessionKey, 'true');
                                closeModal(loginInformationModal, loginInformationModalContent);
                            };

                            markInfoAsReadButton.onclick = handleCloseAndMarkRead;
                            closeLoginInformationModalHeaderButton.onclick = handleCloseAndMarkRead;
                            
                            loginInformationModal.onclick = (event) => {
                                if (event.target === loginInformationModal) {
                                     handleCloseAndMarkRead();
                                }
                            };

                            openModal(loginInformationModal, loginInformationModalContent);
                        } else {
                            console.log(data.message || "Tidak ada informasi aktif terbaru untuk ditampilkan sebagai pop-up.");
                        }
                    })
                    .catch(error => {
                        console.error("Error fetching latest information for popup:", error);
                    });
            } else {
                if (!isLoggedIn) console.log("Info popup: User not logged in.");
                if (!isLikelyPostLoginPage) console.log("Info popup: Not on a post-login page.");
            }
        }

        showLoginInformationPopup();
    }

    // ========================================================
    // Logika untuk Halaman Log Masuk (Admin)
    // ========================================================
    const adminLoginLogsTableBody = document.getElementById('admin-login-logs-table-body');
    const adminLoginLogFilterModalButton = document.getElementById('admin-login-log-filter-modal-button');
    const adminLoginLogFilterModal = document.getElementById('admin-login-log-filter-modal');
    const adminLoginLogFilterModalContent = document.getElementById('admin-login-log-filter-modal-content');
    const closeAdminLoginLogFilterModalButton = document.getElementById('close-admin-login-log-filter-modal');
    const adminLoginLogFilterForm = document.getElementById('admin-login-log-filter-form');
    const resetAdminLoginLogFilterButton = document.getElementById('reset-admin-login-log-filter-button');
    const adminLoginLogsPaginationInfo = document.getElementById('admin-login-logs-pagination-info');
    const adminLoginLogsPaginationControls = document.getElementById('admin-login-logs-pagination-controls');
    const adminLoginLogsMessageDiv = document.getElementById('admin-login-logs-message');
    const loginLogDetailModal = document.getElementById('login-log-detail-modal'); // Jika Anda ingin modal detail
    const loginLogDetailModalContent = document.getElementById('login-log-detail-modal-content');
    const loginLogDetailModalBody = document.getElementById('login-log-detail-modal-body');
    const closeLoginLogDetailModalButton = document.getElementById('close-login-log-detail-modal');


    if (adminLoginLogsTableBody && adminLoginLogFilterModalButton && adminLoginLogFilterForm && typeof jsBaseUrl !== 'undefined' && jsBaseUrl) {
        let currentAdminLoginLogParams = {
            page: 1,
            limit: 15,
            status: 'all',
            user_id: '',
            ip_address: '',
            sort_by: 'll.login_at',
            sort_type: 'DESC',
            search_column: 'll.id',
            search_keyword: ''
        };

        function loadAdminLoginLogs(params = {}) {
            adminLoginLogsTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-24 text-center text-sm text-gray-500 italic"><i class="fas fa-spinner fa-spin mr-2"></i> Memuat data log masuk...</td></tr>`;
            if(adminLoginLogsPaginationInfo) adminLoginLogsPaginationInfo.textContent = 'Memuat...';
            if(adminLoginLogsPaginationControls) adminLoginLogsPaginationControls.innerHTML = '';
            if(adminLoginLogsMessageDiv && !adminLoginLogsMessageDiv.innerHTML.includes('success')) {
                adminLoginLogsMessageDiv.innerHTML = '';
                adminLoginLogsMessageDiv.className = 'mb-4 text-sm';
            }

            currentAdminLoginLogParams = { ...currentAdminLoginLogParams, ...params };
            const queryParams = new URLSearchParams(currentAdminLoginLogParams).toString();
            const url = `${jsBaseUrl}/ajax/admin/get_admin_login_logs?${queryParams}`;

            fetch(url)
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP error ${response.status}`);
                    return response.json();
                })
                .then(data => {
                    if (data.success && data.logs && data.pagination) {
                        renderAdminLoginLogTable(data.logs);
                        renderAdminLoginLogPagination(data.pagination);
                         if (adminLoginLogsMessageDiv && !adminLoginLogsMessageDiv.innerHTML.includes('success')) {
                            adminLoginLogsMessageDiv.innerHTML = '';
                            adminLoginLogsMessageDiv.className = 'mb-4 text-sm';
                        }
                    } else {
                        adminLoginLogsTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-24 text-center text-sm text-red-500 italic">${escapeHTML(data.message || 'Gagal memuat data log masuk.')}</td></tr>`;
                        if(adminLoginLogsPaginationInfo) adminLoginLogsPaginationInfo.textContent = 'Gagal memuat data.';
                        if(adminLoginLogsPaginationControls) adminLoginLogsPaginationControls.innerHTML = '';
                        if (!adminLoginLogsMessageDiv || !adminLoginLogsMessageDiv.innerHTML.includes('success')) {
                             displayGeneralMessage('admin-login-logs-message', data.message || 'Gagal memuat data log masuk.', 'error');
                        }
                    }
                })
                .catch(error => {
                    console.error('Fetch Error (Admin Login Logs):', error);
                    adminLoginLogsTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-24 text-center text-sm text-red-500 italic">Error koneksi saat memuat log masuk.</td></tr>`;
                    if(adminLoginLogsPaginationInfo) adminLoginLogsPaginationInfo.textContent = 'Error koneksi.';
                    if(adminLoginLogsPaginationControls) adminLoginLogsPaginationControls.innerHTML = '';
                    if (!adminLoginLogsMessageDiv || !adminLoginLogsMessageDiv.innerHTML.includes('success')) {
                        displayGeneralMessage('admin-login-logs-message', 'Error koneksi saat memuat log masuk.', 'error');
                    }
                });
        }

        function renderAdminLoginLogTable(logs) {
            adminLoginLogsTableBody.innerHTML = '';
            if (logs.length === 0) {
                adminLoginLogsTableBody.innerHTML = `<tr><td colspan="8" class="px-6 py-24 text-center text-sm text-gray-500 italic">Tidak ada data log masuk yang cocok dengan filter.</td></tr>`;
                return;
            }
            logs.forEach((log, index) => {
                const row = document.createElement('tr');
                row.classList.add('hover:bg-gray-50', 'transition-colors', 'text-xs');
                const formattedDateTime = formatLocalDate(log.login_at);
                
                let statusText = log.status;
                let statusClass = 'bg-gray-100 text-gray-800';
                switch(log.status) {
                    case 'success': statusText = 'Sukses'; statusClass = 'bg-green-100 text-green-800'; break;
                    case 'failed_password': statusText = 'Gagal (Password)'; statusClass = 'bg-red-100 text-red-800'; break;
                    case 'failed_username': statusText = 'Gagal (Username)'; statusClass = 'bg-yellow-100 text-yellow-800'; break;
                    case 'admin_impersonate_start': statusText = 'Impersonate Mulai'; statusClass = 'bg-purple-100 text-purple-800'; break;
                    case 'admin_impersonate_end': statusText = 'Impersonate Selesai'; statusClass = 'bg-indigo-100 text-indigo-800'; break;
                }

                const usernameDisplay = log.user_id ? `${escapeHTML(log.username)} (ID: ${log.user_id})` : `Percobaan: ${escapeHTML(log.username_attempt)}`;
                const usernameTitle = log.user_id ? `Username: ${escapeHTML(log.username)}, User ID: ${log.user_id}` : `Percobaan Username: ${escapeHTML(log.username_attempt)}`;


                row.innerHTML = `
                    <td class="px-3 py-2.5 whitespace-nowrap text-gray-500">${escapeHTML(log.id)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-700 font-medium" title="${usernameTitle}">${usernameDisplay}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-500">${escapeHTML(formattedDateTime)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-600">${escapeHTML(log.ip_address)}</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-600 hidden md:table-cell">${escapeHTML(log.device_type || '-')}</td>
                    <td class="px-4 py-2.5 text-gray-600 hidden lg:table-cell max-w-xs truncate" title="${escapeHTML(log.browser_name || '')} di ${escapeHTML(log.platform_name || '')}">${escapeHTML(log.browser_name || '-')} (${escapeHTML(log.platform_name || '-')})</td>
                    <td class="px-4 py-2.5 whitespace-nowrap text-gray-600 hidden md:table-cell" title="${escapeHTML(log.location_info || '')}">${escapeHTML(log.location_info || '-')}</td>
                    <td class="px-3 py-2.5 whitespace-nowrap text-center">
                        <span class="px-2 py-0.5 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass} border ${statusClass.replace('bg-', 'border-').replace('-100', '-200')}">
                            ${escapeHTML(statusText)}
                        </span>
                    </td>
                `;
                adminLoginLogsTableBody.appendChild(row);
            });
        }

        function renderAdminLoginLogPagination(pagination) {
            if (!adminLoginLogsPaginationControls || !adminLoginLogsPaginationInfo) return;
            if (!pagination || typeof pagination.totalItems === 'undefined' || pagination.totalItems === 0) {
                adminLoginLogsPaginationInfo.textContent = 'Tidak ada data.';
                adminLoginLogsPaginationControls.innerHTML = '';
                return;
            }
            adminLoginLogsPaginationInfo.textContent = `Menampilkan ${pagination.totalItems > 0 ? pagination.offset + 1 : 0} - ${Math.min(pagination.offset + pagination.limit, pagination.totalItems)} dari ${pagination.totalItems.toLocaleString('id-ID')} log. (Halaman ${pagination.currentPage}/${pagination.totalPages})`;
            adminLoginLogsPaginationControls.innerHTML = '';
            if (pagination.totalPages <= 1) return;

            let paginationHTML = '';
            const currentPage = pagination.currentPage;
            const totalPages = pagination.totalPages;

            paginationHTML += `<button type="button" data-page="${currentPage - 1}" class="admin-login-log-pagination-link px-3 py-1 border rounded transition-colors ${currentPage > 1 ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage <= 1 ? 'disabled' : ''}>&laquo; Sebelumnya</button>`;

            const maxPagesToShow = 5;
            let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2));
            let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1);
            if(endPage === totalPages && totalPages >= maxPagesToShow) { startPage = Math.max(1, totalPages - maxPagesToShow + 1); }

            if (startPage > 1) {
                paginationHTML += `<button type="button" data-page="1" class="admin-login-log-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">1</button>`;
                if (startPage > 2) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
            }
            for (let i = startPage; i <= endPage; i++) {
                const activeClass = (i === currentPage) ? 'bg-blue-600 text-white border-blue-600 z-10' : 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300';
                paginationHTML += `<button type="button" data-page="${i}" class="admin-login-log-pagination-link px-3 py-1 border rounded ${activeClass} transition-colors">${i}</button>`;
            }
             if (endPage < totalPages) {
                if (endPage < totalPages - 1) { paginationHTML += `<span class="px-3 py-1 text-gray-500">...</span>`; }
                paginationHTML += `<button type="button" data-page="${totalPages}" class="admin-login-log-pagination-link px-3 py-1 border rounded bg-white hover:bg-gray-100 text-gray-700 border-gray-300 transition-colors">${totalPages}</button>`;
            }
            paginationHTML += `<button type="button" data-page="${currentPage + 1}" class="admin-login-log-pagination-link px-3 py-1 border rounded transition-colors ${currentPage < totalPages ? 'bg-white hover:bg-gray-100 text-gray-700 border-gray-300' : 'bg-gray-100 text-gray-400 border-gray-200 cursor-not-allowed'}" ${currentPage >= totalPages ? 'disabled' : ''}>Berikutnya &raquo;</button>`;
            adminLoginLogsPaginationControls.innerHTML = paginationHTML;
        }

        if(adminLoginLogFilterModalButton && adminLoginLogFilterModal && closeAdminLoginLogFilterModalButton && adminLoginLogFilterModalContent) {
            adminLoginLogFilterModalButton.addEventListener('click', () => openModal(adminLoginLogFilterModal, adminLoginLogFilterModalContent));
            closeAdminLoginLogFilterModalButton.addEventListener('click', () => closeModal(adminLoginLogFilterModal, adminLoginLogFilterModalContent));
            adminLoginLogFilterModal.addEventListener('click', (event) => { if (event.target === adminLoginLogFilterModal) closeModal(adminLoginLogFilterModal, adminLoginLogFilterModalContent); });
        }

        if(adminLoginLogFilterForm) {
            adminLoginLogFilterForm.addEventListener('submit', (event) => {
                event.preventDefault();
                const formData = new FormData(adminLoginLogFilterForm);
                const newParams = {};
                for (const [key, value] of formData.entries()) { newParams[key] = value; }
                newParams.page = 1;
                loadAdminLoginLogs(newParams);
                closeModal(adminLoginLogFilterModal, adminLoginLogFilterModalContent);
            });
        }

        if(resetAdminLoginLogFilterButton && adminLoginLogFilterForm) {
            resetAdminLoginLogFilterButton.addEventListener('click', () => {
                adminLoginLogFilterForm.reset();
                document.getElementById('filter_limit_admin_login_log').value = '15';
                document.getElementById('filter_status_admin_login_log').value = 'all';
                document.getElementById('filter_user_id_admin_login_log').value = '';
                document.getElementById('filter_ip_address_admin_login_log').value = '';
                document.getElementById('filter_search_column_admin_login_log').value = 'll.id';
                document.getElementById('filter_search_keyword_admin_login_log').value = '';
                document.getElementById('filter_sort_by_admin_login_log').value = 'll.login_at';
                document.getElementById('filter_sort_type_admin_login_log').value = 'DESC';
                adminLoginLogFilterForm.dispatchEvent(new Event('submit', { cancelable: true }));
            });
        }

        if(adminLoginLogsPaginationControls) {
            adminLoginLogsPaginationControls.addEventListener('click', (event) => {
                const targetButton = event.target.closest('.admin-login-log-pagination-link');
                if (targetButton && !targetButton.disabled && targetButton.dataset.page) {
                    const pageToGo = parseInt(targetButton.dataset.page);
                    if (!isNaN(pageToGo)) { loadAdminLoginLogs({ page: pageToGo }); }
                }
            });
        }

        loadAdminLoginLogs(currentAdminLoginLogParams);
    }

    const animatedElements = document.querySelectorAll('.fade-in'); animatedElements.forEach(el => { el.style.opacity = ''; el.classList.add('fade-in'); });

});
