{% extends "base.html" %}
{% from "components/ui.html" import page_header, stat_card, badge %}
{% from "components/client_select.html" import client_select %}

{% block title %}{{ _('Time Entries Overview') }}{% endblock %}

{% block content %}
{% set breadcrumbs = [
    {'text': _('Time Entries')}
] %}

{{ page_header(
    icon_class='fas fa-clock',
    title_text=_('Time Entries Overview'),
    subtitle_text=_('View and manage all time entries'),
    breadcrumbs=breadcrumbs,
    actions_html=None
) }}

<!-- Summary Cards -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
    {{ stat_card(_('Total Hours'), totals.total_hours, 'fas fa-hourglass-half', 'blue-500') }}
    {{ stat_card(_('Billable Hours'), totals.total_billable_hours, 'fas fa-dollar-sign', 'green-500') }}
    {{ stat_card(_('Paid Hours'), totals.total_paid_hours, 'fas fa-check-circle', 'emerald-500') }}
    {{ stat_card(_('Entries'), totals.total_entries, 'fas fa-list', 'purple-500') }}
</div>

<!-- Filters -->
<div class="bg-card-light dark:bg-card-dark p-6 rounded-xl border border-border-light dark:border-border-dark shadow-sm mb-6">
    <div class="flex justify-between items-center mb-4">
        <h2 class="text-lg font-semibold">{{ _('Filters') }}</h2>
        <div class="flex items-center gap-2 flex-wrap">
            <span class="text-xs text-text-muted-light dark:text-text-muted-dark self-center mr-1" title="{{ _('Exports use current filters') }}"><i class="fas fa-info-circle mr-0.5" aria-hidden="true"></i>{{ _('Exports use current filters') }}</span>
            <button type="button" id="applyFiltersBtn" class="btn btn-primary btn-sm" aria-label="{{ _('Apply filters') }}">
                <i class="fas fa-filter mr-2" aria-hidden="true"></i>{{ _('Apply filters') }}
            </button>
            <button type="button" id="clearFiltersBtn" class="btn btn-secondary btn-sm" aria-label="{{ _('Clear Filters') }}">
                <i class="fas fa-times mr-1" aria-hidden="true"></i>{{ _('Clear Filters') }}
            </button>
            <a
                id="exportCsvBtn"
                data-export-base="{{ url_for('timer.export_time_entries_csv') }}"
                href="{{ url_for('timer.export_time_entries_csv') }}"
                class="btn btn-primary btn-sm"
                aria-label="{{ _('Export CSV') }}"
            >
                <i class="fas fa-file-csv mr-2" aria-hidden="true"></i>{{ _('Export CSV') }}
            </a>
            <a
                id="exportPdfBtn"
                data-export-base="{{ url_for('timer.export_time_entries_pdf') }}"
                href="{{ url_for('timer.export_time_entries_pdf') }}"
                class="btn btn-secondary btn-sm"
                aria-label="{{ _('Export PDF') }}"
            >
                <i class="fas fa-file-pdf mr-2" aria-hidden="true"></i>{{ _('Export PDF') }}
            </a>
            <button type="button" class="btn btn-ghost btn-sm" id="toggleFilters" aria-label="{{ _('Toggle filters') }}" aria-expanded="true">
                <i class="fas fa-chevron-up" id="filterToggleIcon" aria-hidden="true"></i>
            </button>
        </div>
    </div>
    <div id="filterBody">
        <form method="GET" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4" id="timeEntriesFilterForm" data-filter-form data-filter-handler="custom">
            {% if can_view_all %}
            <div>
                <label for="user_id" class="form-label">{{ _('User') }}</label>
                <select name="user_id" id="user_id" class="form-input">
                    <option value="">{{ _('All Users') }}</option>
                    {% for user in users %}
                    <option value="{{ user.id }}" {% if filters.user_id is not none and (filters.user_id|string) == (user.id|string) %}selected{% endif %}>{{ user.display_name }}</option>
                    {% endfor %}
                </select>
            </div>
            {% endif %}
            <div class="lg:col-span-2">
                <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
                    <div>
                        <label for="start_date" class="form-label">{{ _('Start Date') }}</label>
                        <input type="date" name="start_date" id="start_date" value="{{ filters.start_date or '' }}" class="form-input user-date-input">
                    </div>
                    <div>
                        <label for="end_date" class="form-label">{{ _('End Date') }}</label>
                        <input type="date" name="end_date" id="end_date" value="{{ filters.end_date or '' }}" class="form-input user-date-input">
                    </div>
                </div>
            </div>
            <div>
                <label for="project_id" class="form-label">{{ _('Project') }}</label>
                <select name="project_id" id="project_id" class="form-input">
                    <option value="">{{ _('All Projects') }}</option>
                    {% for project in projects %}
                    <option value="{{ project.id }}" {% if filters.project_id == project.id %}selected{% endif %}>{{ project.name }}</option>
                    {% endfor %}
                </select>
            </div>
            <div>
                <label for="client_id" class="form-label">{{ _('Client') }}</label>
                {{ client_select('client_id', clients, selected_id=filters.client_id, required=False, only_one_client=only_one_client|default(false), single_client=single_client) }}
            </div>
            <div>
                <label for="paid" class="form-label">{{ _('Paid Status') }}</label>
                <select name="paid" id="paid" class="form-input">
                    <option value="">{{ _('All') }}</option>
                    <option value="true" {% if filters.paid == 'true' %}selected{% endif %}>{{ _('Paid') }}</option>
                    <option value="false" {% if filters.paid == 'false' %}selected{% endif %}>{{ _('Unpaid') }}</option>
                </select>
            </div>
            <div>
                <label for="billable" class="form-label">{{ _('Billable Status') }}</label>
                <select name="billable" id="billable" class="form-input">
                    <option value="">{{ _('All') }}</option>
                    <option value="true" {% if filters.billable == 'true' %}selected{% endif %}>{{ _('Billable') }}</option>
                    <option value="false" {% if filters.billable == 'false' %}selected{% endif %}>{{ _('Non-billable') }}</option>
                </select>
            </div>
            <div>
                <label for="time-entries-filter-search" class="form-label">{{ _('Search') }}</label>
                <input type="text" name="search" id="time-entries-filter-search" value="{{ filters.search or '' }}" placeholder="{{ _('Search in notes and tags...') }}" class="form-input">
            </div>
            {% if custom_field_definitions %}
            {% for definition in custom_field_definitions %}
            <div>
                <label for="custom_field_{{ definition.field_key }}" class="form-label">{{ definition.label }} (Client)</label>
                <input type="text" name="custom_field_{{ definition.field_key }}" id="custom_field_{{ definition.field_key }}" 
                       value="{{ filters.client_custom_field.get(definition.field_key, '') if filters.client_custom_field else '' }}" 
                       class="form-input" 
                       placeholder="{{ definition.description or '' }}">
            </div>
            {% endfor %}
            {% endif %}
            <div class="flex items-end">
                <button type="submit" class="btn btn-primary btn-sm">
                    <i class="fas fa-filter mr-2" aria-hidden="true"></i>{{ _('Apply filters') }}
                </button>
            </div>
        </form>
    </div>
</div>

<!-- Bulk Actions Forms -->
<form id="bulkPaidForm" method="POST" action="{{ url_for('timer.bulk_mark_paid') }}" class="hidden">
    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
    <input type="hidden" name="paid" id="bulkPaidValue">
    {% for key, value in filters.items() %}
        {% if value %}
        <input type="hidden" name="{{ key }}" value="{{ value }}">
        {% endif %}
    {% endfor %}
</form>

<form id="bulkDeleteForm" method="POST" action="{{ url_for('timer.bulk_delete_time_entries') }}" class="hidden">
    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
    <input type="hidden" name="reason" id="bulkDeleteReason">
    {% for key, value in filters.items() %}
        {% if value %}
        <input type="hidden" name="{{ key }}" value="{{ value }}">
        {% endif %}
    {% endfor %}
</form>

<!-- Time Entries Table -->
<div class="bg-card-light dark:bg-card-dark rounded-xl border border-border-light dark:border-border-dark shadow-sm overflow-hidden">
    {% include 'timer/_time_entries_list.html' %}
</div>

<!-- Bulk Delete Dialog -->
<div id="bulkDeleteDialog" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50">
    <div class="bg-card-light dark:bg-card-dark rounded-lg shadow-xl max-w-md w-full mx-4">
        <div class="p-6">
            <h3 class="text-lg font-semibold mb-4 text-rose-600">{{ _('Delete Selected Time Entries') }}</h3>
            <p class="text-sm text-gray-600 dark:text-gray-400 mb-4" id="bulkDeleteMessage"></p>
            <div class="mb-4">
                <label for="bulkDeleteReasonInput" class="form-label">
                    {{ _('Reason for Deletion') }} <span class="text-text-muted-light dark:text-text-muted-dark text-xs">({{ _('Optional but recommended') }})</span>
                </label>
                <textarea id="bulkDeleteReasonInput" class="form-input w-full" rows="3" placeholder="{{ _('e.g., Duplicate entry, incorrect time, etc.') }}"></textarea>
            </div>
            <div class="flex justify-end gap-3 mt-6">
                <button type="button" class="px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors" id="closeBulkDeleteBtn">
                    {{ _('Cancel') }}
                </button>
                <button type="button" class="px-4 py-2 bg-rose-600 text-white rounded-lg hover:bg-rose-700 transition-colors" id="confirmBulkDeleteBtn">
                    <i class="fas fa-trash mr-2"></i>{{ _('Delete') }}
                </button>
            </div>
        </div>
    </div>
</div>

<!-- Bulk Mark Paid Dialog -->
<div id="bulkPaidDialog" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50">
    <div class="bg-card-light dark:bg-card-dark rounded-lg shadow-xl max-w-md w-full mx-4">
        <div class="p-6">
            <h3 class="text-lg font-semibold mb-4">{{ _('Mark Selected Entries as Paid/Unpaid') }}</h3>
            <label for="bulkPaidSelect" class="form-label">{{ _('Status') }}</label>
            <select id="bulkPaidSelect" class="form-input w-full mb-4">
                <option value="true">{{ _('Paid') }}</option>
                <option value="false">{{ _('Unpaid') }}</option>
            </select>
            <div id="invoiceReferenceField" class="hidden mb-4">
                <label for="bulkInvoiceReference" class="form-label">{{ _('Invoice Reference') }} <span class="text-text-muted-light dark:text-text-muted-dark text-xs">({{ _('Optional') }})</span></label>
                <input type="text" id="bulkInvoiceReference" class="form-input w-full" placeholder="{{ _('e.g., Invoice number or payment reference') }}">
            </div>
            <div class="flex justify-end gap-3 mt-6">
                <button type="button" class="px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors" id="closeBulkPaidBtn">
                    {{ _('Cancel') }}
                </button>
                <button type="button" class="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors" id="submitBulkPaidBtn">
                    {{ _('Update') }}
                </button>
            </div>
        </div>
    </div>
</div>

<script>
// Bind event listeners (replaces inline onclick/onchange handlers)
document.addEventListener('DOMContentLoaded', function() {
    var toggleFiltersBtn = document.getElementById('toggleFilters');
    if (toggleFiltersBtn) toggleFiltersBtn.addEventListener('click', toggleFilterVisibility);

    var clearFiltersBtn = document.getElementById('clearFiltersBtn');
    if (clearFiltersBtn) clearFiltersBtn.addEventListener('click', clearAllFilters);

    var closeBulkDeleteBtn = document.getElementById('closeBulkDeleteBtn');
    if (closeBulkDeleteBtn) closeBulkDeleteBtn.addEventListener('click', closeBulkDeleteDialog);

    var confirmBulkDeleteBtn = document.getElementById('confirmBulkDeleteBtn');
    if (confirmBulkDeleteBtn) confirmBulkDeleteBtn.addEventListener('click', confirmBulkDelete);

    var bulkPaidSelect = document.getElementById('bulkPaidSelect');
    if (bulkPaidSelect) bulkPaidSelect.addEventListener('change', toggleInvoiceReferenceField);

    var closeBulkPaidBtn = document.getElementById('closeBulkPaidBtn');
    if (closeBulkPaidBtn) closeBulkPaidBtn.addEventListener('click', closeBulkPaidDialog);

    var submitBulkPaidBtn = document.getElementById('submitBulkPaidBtn');
    if (submitBulkPaidBtn) submitBulkPaidBtn.addEventListener('click', submitBulkPaid);
});

function toggleFilterVisibility() {
    const filterBody = document.getElementById('filterBody');
    const icon = document.getElementById('filterToggleIcon');
    const toggleBtn = document.getElementById('toggleFilters');
    filterBody.classList.toggle('hidden');
    icon.classList.toggle('fa-chevron-up');
    icon.classList.toggle('fa-chevron-down');
    if (toggleBtn) toggleBtn.setAttribute('aria-expanded', filterBody.classList.contains('hidden') ? 'false' : 'true');
}

function clearAllFilters() {
    const form = document.getElementById('timeEntriesFilterForm');
    if (!form) return;
    form.querySelectorAll('select').forEach(function(el) { el.value = ''; });
    form.querySelectorAll('input[type="date"], input[type="text"]').forEach(function(el) { el.value = ''; });
    form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
}

function toggleSelectAll() {
    const selectAll = document.getElementById('selectAll');
    const selectAllHeader = document.getElementById('selectAllHeader');
    const checkboxes = document.querySelectorAll('.entry-checkbox');
    const checked = selectAll.checked || selectAllHeader.checked;
    
    checkboxes.forEach(cb => cb.checked = checked);
    selectAll.checked = checked;
    selectAllHeader.checked = checked;
    updateBulkActions();
}

function updateBulkActions() {
    const checkboxes = document.querySelectorAll('.entry-checkbox:checked');
    const count = checkboxes.length;
    const countValue = document.getElementById('countValue');
    const selectedCount = document.getElementById('selectedCount');
    const bulkActionsBtn = document.getElementById('bulkActionsBtn');
    
    if (count > 0) {
        countValue.textContent = count;
        selectedCount.classList.remove('hidden');
        bulkActionsBtn.disabled = false;
    } else {
        selectedCount.classList.add('hidden');
        bulkActionsBtn.disabled = true;
    }
}

function openBulkActionsMenu() {
    const menu = document.getElementById('bulkActionsMenu');
    if (menu) {
        menu.classList.toggle('hidden');
    }
}

// Close menu when clicking outside
document.addEventListener('click', function(e) {
    const menu = document.getElementById('bulkActionsMenu');
    const btn = document.getElementById('bulkActionsBtn');
    if (menu && btn && !menu.contains(e.target) && !btn.contains(e.target)) {
        menu.classList.add('hidden');
    }
});

function toggleInvoiceReferenceField() {
    const statusSelect = document.getElementById('bulkPaidSelect');
    const referenceField = document.getElementById('invoiceReferenceField');
    if (!statusSelect || !referenceField) return;
    
    if (statusSelect.value === 'true') {
        referenceField.classList.remove('hidden');
    } else {
        referenceField.classList.add('hidden');
        const referenceInput = document.getElementById('bulkInvoiceReference');
        if (referenceInput) referenceInput.value = '';
    }
}

function showBulkPaidDialog() {
    const checkboxes = document.querySelectorAll('.entry-checkbox:checked');
    if (checkboxes.length === 0) {
        alert('{{ _("Please select at least one time entry") }}');
        return false;
    }
    document.getElementById('bulkPaidDialog').classList.remove('hidden');
    // Reset form fields
    const statusSelect = document.getElementById('bulkPaidSelect');
    const referenceField = document.getElementById('invoiceReferenceField');
    const referenceInput = document.getElementById('bulkInvoiceReference');
    if (statusSelect) statusSelect.value = 'true';
    if (referenceField) referenceField.classList.remove('hidden');
    if (referenceInput) referenceInput.value = '';
    // Close the menu
    document.getElementById('bulkActionsMenu').classList.add('hidden');
    return false;
}

function closeBulkPaidDialog() {
    document.getElementById('bulkPaidDialog').classList.add('hidden');
    // Reset form fields
    const statusSelect = document.getElementById('bulkPaidSelect');
    const referenceField = document.getElementById('invoiceReferenceField');
    const referenceInput = document.getElementById('bulkInvoiceReference');
    if (statusSelect) statusSelect.value = 'true';
    if (referenceField) referenceField.classList.add('hidden');
    if (referenceInput) referenceInput.value = '';
}

function submitBulkPaid() {
    const checkboxes = document.querySelectorAll('.entry-checkbox:checked');
    const form = document.getElementById('bulkPaidForm');
    const paidValue = document.getElementById('bulkPaidSelect').value;
    
    // Clear existing entry IDs and invoice reference
    form.querySelectorAll('input[name="entry_ids[]"]').forEach(input => input.remove());
    form.querySelectorAll('input[name="invoice_reference"]').forEach(input => input.remove());
    
    // Add selected entry IDs to form
    checkboxes.forEach(cb => {
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = 'entry_ids[]';
        input.value = cb.value;
        form.appendChild(input);
    });
    
    // Add invoice reference if provided and status is paid
    const referenceInput = document.getElementById('bulkInvoiceReference');
    if (paidValue === 'true' && referenceInput && referenceInput.value.trim()) {
        const refInput = document.createElement('input');
        refInput.type = 'hidden';
        refInput.name = 'invoice_reference';
        refInput.value = referenceInput.value.trim();
        form.appendChild(refInput);
    }
    
    document.getElementById('bulkPaidValue').value = paidValue;
    form.submit();
}

function showBulkDeleteConfirm() {
    const checkboxes = document.querySelectorAll('.entry-checkbox:checked');
    if (checkboxes.length === 0) {
        alert('{{ _("Please select at least one time entry") }}');
        return false;
    }
    const count = checkboxes.length;
    const msg = `{{ _("Are you sure you want to delete") }} ${count} {{ _("time entry/entries") }}? {{ _("This action cannot be undone.") }}`;
    
    // Show custom dialog with reason field
    document.getElementById('bulkDeleteMessage').textContent = msg;
    document.getElementById('bulkDeleteReasonInput').value = '';
    document.getElementById('bulkDeleteDialog').classList.remove('hidden');
    
    // Close the menu
    document.getElementById('bulkActionsMenu').classList.add('hidden');
    return false;
}

function closeBulkDeleteDialog() {
    document.getElementById('bulkDeleteDialog').classList.add('hidden');
}

function confirmBulkDelete() {
    const checkboxes = document.querySelectorAll('.entry-checkbox:checked');
    const form = document.getElementById('bulkDeleteForm');
    const reasonInput = document.getElementById('bulkDeleteReasonInput');
    
    // Set reason in form
    document.getElementById('bulkDeleteReason').value = reasonInput.value.trim();
    
    // Clear existing entry IDs
    form.querySelectorAll('input[name="entry_ids[]"]').forEach(input => input.remove());
    
    // Add selected entry IDs to form
    checkboxes.forEach(cb => {
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = 'entry_ids[]';
        input.value = cb.value;
        form.appendChild(input);
    });
    
    // Close dialog and submit
    closeBulkDeleteDialog();
    form.submit();
}

// Time Entries Filter Handler - AJAX filtering
(function() {
    'use strict';
    
    let filterTimeout = null;
    let searchTimeout = null;
    let activeController = null;
    let latestRequestId = 0;
    let lastUrl = null;       // last successful URL
    let inFlightUrl = null;   // URL currently being fetched

    function updateExportLink(filterUrl) {
        const btn = document.getElementById('exportCsvBtn');
        const pdfBtn = document.getElementById('exportPdfBtn');
        if (!btn && !pdfBtn) return;
        const base = btn ? (btn.getAttribute('data-export-base') || '/time-entries/export/csv') : '/time-entries/export/csv';
        const pdfBase = pdfBtn ? (pdfBtn.getAttribute('data-export-base') || '/time-entries/export/pdf') : '/time-entries/export/pdf';
        const qsIndex = String(filterUrl || '').indexOf('?');
        const qs = qsIndex >= 0 ? String(filterUrl).slice(qsIndex + 1) : '';
        if (btn) btn.href = qs ? `${base}?${qs}` : base;
        if (pdfBtn) pdfBtn.href = qs ? `${pdfBase}?${qs}` : pdfBase;
    }
    
    function getFilterParams() {
        const form = document.getElementById('timeEntriesFilterForm');
        if (!form) return {};
        
        const params = {};
        
        // Get search input value directly (more reliable than FormData for text inputs) (Issue #489)
        const searchInput = form.querySelector('input[name="search"]');
        if (searchInput) {
            const searchValue = searchInput.value.trim();
            if (searchValue) {
                params.search = searchValue;
            }
        }
        
        // Explicitly read filter fields that may be hidden (e.g. client_select uses hidden input when locked)
        ['user_id', 'project_id', 'client_id', 'start_date', 'end_date', 'paid', 'billable'].forEach(function(name) {
            const el = form.querySelector('[name="' + name + '"]');
            if (!el || !(el.tagName === 'SELECT' || el.type === 'hidden' || el.type === 'date' || el.type === 'text')) return;
            // Skip client_id when auto-selected (single/locked client) - user didn't explicitly choose it
            if (name === 'client_id' && el.getAttribute('data-auto-client') === 'true') return;
            const val = (el.value || '').trim();
            if (val) params[name] = val;
        });
        
        // Collect remaining from FormData (custom_field_*, etc.)
        const formData = new FormData(form);
        for (const [key, value] of formData.entries()) {
            const trimmed = String(value || '').trim();
            if (trimmed && trimmed !== '') {
                params[key] = trimmed;
            }
        }
        // Fallback: ensure any select or hidden input not yet in params is included
        form.querySelectorAll('select, input[type="hidden"], input[type="date"], input[type="text"]').forEach(function(el) {
            const name = el.name;
            if (!name || params[name] !== undefined) return;
            if (name === 'client_id' && el.getAttribute('data-auto-client') === 'true') return;
            const val = (el.value || '').trim();
            if (val) params[name] = val;
        });
        // Remove client_id when it was auto-selected (single/locked client) - user didn't explicitly choose it
        const clientEl = form.querySelector('[name="client_id"]');
        if (clientEl && clientEl.getAttribute('data-auto-client') === 'true' && 'client_id' in params) {
            delete params.client_id;
        }
        
        if (typeof console !== 'undefined' && console.debug) {
            console.debug('[Time Entries] Filter params:', params);
        }
        return params;
    }
    
    function buildFilterUrl() {
        const params = getFilterParams();
        const queryString = new URLSearchParams(params).toString();
        return queryString ? `/time-entries?${queryString}` : '/time-entries';
    }
    
    function applyFilters() {
        const url = buildFilterUrl();
        const container = document.getElementById('timeEntriesListContainer');
        
        if (!container) {
            console.error('[Time Entries] timeEntriesListContainer not found');
            return;
        }
        if (typeof console !== 'undefined' && console.debug) {
            console.debug('[Time Entries] Applying filters, URL:', url);
        }

        // Avoid duplicate requests: prevent re-fetching the same URL while it's already in flight,
        // and also skip if we already successfully loaded this URL.
        if (inFlightUrl === url || lastUrl === url) {
            return;
        }
        inFlightUrl = url;
        
        // Show loading state
        container.style.opacity = '0.5';
        container.style.pointerEvents = 'none';
        
        // Update URL
        if (window.history && window.history.pushState) {
            window.history.pushState({}, '', url);
        }
        updateExportLink(url);

        // Cancel in-flight request (prevents stale updates)
        try {
            if (activeController) {
                activeController.abort();
            }
        } catch (_) {}
        activeController = new AbortController();
        const requestId = ++latestRequestId;
        
        // Fetch filtered results
        fetch(url, {
            method: 'GET',
            headers: {
                'X-Requested-With': 'XMLHttpRequest',
                'Accept': 'text/html'
            },
            credentials: 'same-origin',
            signal: activeController.signal
        })
        .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            return response.text();
        })
        .then(html => {
            // Ignore stale responses
            if (requestId !== latestRequestId) return;

            const tempDiv = document.createElement('div');
            tempDiv.innerHTML = html.trim();
            
            const newContainer = tempDiv.querySelector('#timeEntriesListContainer');
            
            let parsed = false;
            if (newContainer) {
                container.innerHTML = newContainer.innerHTML;
                parsed = true;
            } else {
                // Fallback: try DOMParser for full HTML documents (Issue #489)
                try {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(html, 'text/html');
                    const fallbackContainer = doc.getElementById('timeEntriesListContainer');
                    if (fallbackContainer) {
                        container.innerHTML = fallbackContainer.innerHTML;
                        parsed = true;
                    } else {
                        if (typeof console !== 'undefined' && console.warn) {
                            console.warn('[Time Entries] Filter response missing #timeEntriesListContainer');
                        }
                        if (inFlightUrl === url) inFlightUrl = null;
                    }
                } catch (parseErr) {
                    if (typeof console !== 'undefined' && console.warn) {
                        console.warn('[Time Entries] Failed to parse filter response:', parseErr);
                    }
                    if (inFlightUrl === url) inFlightUrl = null;
                }
            }
            
            // Re-initialize bulk actions after content update
            updateBulkActions();

            if (parsed) lastUrl = url;
        })
        .catch(error => {
            if (error && error.name === 'AbortError') {
                return; // Expected when rapidly changing filters
            }
            console.error('Filter error:', error);
            container.style.opacity = '';
            container.style.pointerEvents = '';
            // Allow retrying the same URL after failures.
            if (inFlightUrl === url) inFlightUrl = null;
            if (window.toastManager) {
                window.toastManager.show('Failed to filter time entries. Please refresh the page.', 'error');
            } else if (window.showToast) {
                window.showToast('Failed to filter time entries. Please refresh the page.', 'error');
            }
        })
        .finally(() => {
            // Only clear loading state for the latest request
            if (requestId !== latestRequestId) return;
            container.style.opacity = '';
            container.style.pointerEvents = '';
            if (inFlightUrl === url) inFlightUrl = null;
        });
    }
    
    function debouncedApplyFilters(delay = 100) {
        if (filterTimeout) {
            clearTimeout(filterTimeout);
        }
        filterTimeout = setTimeout(applyFilters, delay);
    }
    
    function debouncedSearch(delay = 500) {
        if (searchTimeout) {
            clearTimeout(searchTimeout);
        }
        searchTimeout = setTimeout(applyFilters, delay);
    }
    
    function initTimeEntriesFilters() {
        const form = document.getElementById('timeEntriesFilterForm');
        if (!form) {
            console.error('Time entries filter form not found');
            return;
        }

        // Initialize export links from current form/URL (Issue #555: keep export in sync with filters)
        try {
            updateExportLink(buildFilterUrl());
            // Fallback: if page was loaded with query params, use them for export href (e.g. right-click Open in new tab)
            if (window.location.search) {
                const csvBtn = document.getElementById('exportCsvBtn');
                const pdfBtn = document.getElementById('exportPdfBtn');
                const base = csvBtn ? (csvBtn.getAttribute('data-export-base') || '/time-entries/export/csv') : '/time-entries/export/csv';
                const pdfBase = pdfBtn ? (pdfBtn.getAttribute('data-export-base') || '/time-entries/export/pdf') : '/time-entries/export/pdf';
                const qs = window.location.search.slice(1);
                if (csvBtn) csvBtn.href = base + (qs ? '?' + qs : '');
                if (pdfBtn) pdfBtn.href = pdfBase + (qs ? '?' + qs : '');
            }
        } catch (_) {}

        // Header "Apply filters" button (Issue #555: visible filter action)
        const applyFiltersBtn = document.getElementById('applyFiltersBtn');
        if (applyFiltersBtn) {
            applyFiltersBtn.addEventListener('click', function() {
                const filterBody = document.getElementById('filterBody');
                const icon = document.getElementById('filterToggleIcon');
                if (filterBody && filterBody.classList.contains('hidden')) {
                    filterBody.classList.remove('hidden');
                    if (icon) { icon.classList.remove('fa-chevron-down'); icon.classList.add('fa-chevron-up'); }
                    var t = document.getElementById('toggleFilters');
                    if (t) t.setAttribute('aria-expanded', 'true');
                }
                if (filterTimeout) clearTimeout(filterTimeout);
                if (searchTimeout) clearTimeout(searchTimeout);
                lastUrl = null;
                applyFilters();
            });
        }

        // Export CSV/PDF: always use current form params on click (Issue #555: export respects date/filters)
        const exportCsvBtn = document.getElementById('exportCsvBtn');
        const exportPdfBtn = document.getElementById('exportPdfBtn');
        function buildExportUrl(base) {
            const params = getFilterParams();
            const qs = new URLSearchParams(params).toString();
            return qs ? base + '?' + qs : base;
        }
        if (exportCsvBtn) {
            exportCsvBtn.addEventListener('click', function(e) {
                e.preventDefault();
                const base = this.getAttribute('data-export-base') || '/time-entries/export/csv';
                window.location.href = buildExportUrl(base);
            });
        }
        if (exportPdfBtn) {
            exportPdfBtn.addEventListener('click', function(e) {
                e.preventDefault();
                const base = this.getAttribute('data-export-base') || '/time-entries/export/pdf';
                window.location.href = buildExportUrl(base);
            });
        }

        // Event delegation so filters keep working (Issue #489: include text inputs for custom fields)
        form.addEventListener('change', (e) => {
            const t = e.target;
            if (!t || !(t instanceof Element)) return;
            if (t.matches('select') || t.matches('input[type="date"]') || t.matches('input[type="text"]')) {
                updateExportLink(buildFilterUrl());  // Issue #555: export href reflects current form
                debouncedApplyFilters(100);
            }
        });

        form.addEventListener('input', (e) => {
            const t = e.target;
            if (!t || !(t instanceof Element)) return;
            if (t.matches('input[name="search"]')) {
                updateExportLink(buildFilterUrl());  // Issue #555: export href reflects current form
                debouncedSearch(500);
            }
        });

        // Submit search on Enter
        form.addEventListener('keydown', (e) => {
            const t = e.target;
            if (!t || !(t instanceof Element)) return;
            if (e.key === 'Enter' && t.matches('input[name="search"]')) {
                e.preventDefault();
                if (searchTimeout) clearTimeout(searchTimeout);
                applyFilters();
            }
        });
        
        // Prevent form submission (use AJAX instead)
        form.addEventListener('submit', (e) => {
            e.preventDefault();
            e.stopPropagation();
            if (searchTimeout) {
                clearTimeout(searchTimeout);
            }
            if (filterTimeout) {
                clearTimeout(filterTimeout);
            }
            // Ensure we run even if URL did not change due to lastUrl caching
            lastUrl = null;
            applyFilters();
        });
    }

    // Initialize immediately if DOM is already parsed, otherwise on DOMContentLoaded.
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initTimeEntriesFilters);
    } else {
        initTimeEntriesFilters();
    }
})();
</script>
<script src="{{ url_for('static', filename='time-entries-inline-edit.js') }}?v={{ app_version }}"></script>
{% endblock %}

