/**
 * Tap2Order – Main Application JavaScript
 * Admin panel functionality
 * Vanilla JS (no jQuery dependency for core features)
 */

/* ===========================================================
   1. CSRF Token Management
   =========================================================== */
const CSRF = {
  token: null,

  init() {
    const meta = document.querySelector('meta[name="csrf-token"]');
    if (meta) {
      this.token = meta.getAttribute('content');
    }
  },

  get() {
    if (!this.token) this.init();
    return this.token;
  },

  set(token) {
    this.token = token;
  }
};

/* ===========================================================
   2. AJAX Setup with CSRF Header
   =========================================================== */
function ajaxRequest(url, options = {}) {
  const defaults = {
    method: 'POST',
    headers: {
      'X-CSRF-TOKEN': CSRF.get(),
      'X-Requested-With': 'XMLHttpRequest',
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    },
    credentials: 'same-origin'
  };

  const config = { ...defaults, ...options };

  if (options.headers) {
    config.headers = { ...defaults.headers, ...options.headers };
  }

  if (config.body && typeof config.body === 'object' && !(config.body instanceof FormData)) {
    config.body = JSON.stringify(config.body);
  }

  if (config.body instanceof FormData) {
    delete config.headers['Content-Type'];
  }

  return fetch(url, config).then(async response => {
    const data = await response.json().catch(() => null);
    if (!response.ok) {
      const error = data || { message: 'Request failed' };
      error.status = response.status;
      throw error;
    }
    return data;
  });
}

/* ===========================================================
   3. Toast Notifications
   =========================================================== */
const Toast = {
  container: null,

  init() {
    this.container = document.getElementById('toast-container');
    if (!this.container) {
      this.container = document.createElement('div');
      this.container.id = 'toast-container';
      this.container.className = 'toast-container';
      document.body.appendChild(this.container);
    }
  },

  show(message, type = 'info', duration = 4000) {
    if (!this.container) this.init();

    const icons = {
      success: 'fas fa-check-circle',
      error: 'fas fa-times-circle',
      warning: 'fas fa-exclamation-triangle',
      info: 'fas fa-info-circle'
    };

    const toast = document.createElement('div');
    toast.className = `toast toast-${type}`;
    toast.innerHTML = `
      <i class="toast-icon ${icons[type] || icons.info}"></i>
      <span class="toast-message">${message}</span>
      <button class="toast-close" onclick="this.parentElement.remove()">&times;</button>
    `;

    this.container.appendChild(toast);

    setTimeout(() => {
      if (toast.parentElement) {
        toast.style.animation = 'toastFadeOut 0.3s ease forwards';
        setTimeout(() => toast.remove(), 300);
      }
    }, duration);

    return toast;
  },

  success(message, duration) {
    return this.show(message, 'success', duration);
  },

  error(message, duration) {
    return this.show(message, 'error', duration);
  },

  warning(message, duration) {
    return this.show(message, 'warning', duration);
  },

  info(message, duration) {
    return this.show(message, 'info', duration);
  }
};

/* ===========================================================
   4. Confirm Delete Modals / SweetAlert Wrapper
   =========================================================== */
function confirmAction(options = {}) {
  const defaults = {
    title: 'Are you sure?',
    text: 'This action cannot be undone.',
    icon: 'warning',
    showCancelButton: true,
    confirmButtonColor: '#e74c3c',
    cancelButtonColor: '#6c757d',
    confirmButtonText: 'Yes, delete it!',
    cancelButtonText: 'Cancel'
  };

  const config = { ...defaults, ...options };

  return new Promise((resolve) => {
    if (typeof Swal !== 'undefined') {
      Swal.fire(config).then(result => resolve(result.isConfirmed));
    } else {
      const confirmed = window.confirm(`${config.title}\n${config.text}`);
      resolve(confirmed);
    }
  });
}

function confirmDelete(url, itemName = 'this item') {
  return confirmAction({
    title: `Delete ${itemName}?`,
    text: `You are about to delete ${itemName}. This action cannot be undone.`,
    confirmButtonText: 'Yes, delete it!'
  }).then(confirmed => {
    if (!confirmed) return null;
    return ajaxRequest(url, { method: 'DELETE' });
  }).then(data => {
    if (data) {
      Toast.success('Deleted successfully!');
      if (data.redirect) {
        setTimeout(() => window.location.href = data.redirect, 1000);
      } else {
        setTimeout(() => window.location.reload(), 1000);
      }
    }
    return data;
  }).catch(err => {
    Toast.error(err.message || 'Failed to delete');
  });
}

/* ===========================================================
   5. DataTable Initialization Helper
   =========================================================== */
function initDataTable(selector, options = {}) {
  if (typeof jQuery === 'undefined' || typeof jQuery.fn.DataTable === 'undefined') {
    console.warn('DataTables not loaded');
    return null;
  }

  const defaults = {
    responsive: true,
    pageLength: 25,
    order: [[0, 'desc']],
    language: {
      search: '<i class="fas fa-search"></i>',
      searchPlaceholder: 'Search...',
      lengthMenu: 'Show _MENU_ per page',
      info: 'Showing _START_ - _END_ of _TOTAL_',
      infoEmpty: 'No records found',
      infoFiltered: '(filtered from _MAX_)',
      paginate: { previous: '<i class="fas fa-chevron-left"></i>', next: '<i class="fas fa-chevron-right"></i>' },
      zeroRecords: '<div class="empty-state"><i class="fas fa-inbox"></i><p>No matching records found</p></div>'
    },
    dom: '<"row"<"col-sm-6"l><"col-sm-6"f>>rtip',
    drawCallback: function () {
      const info = this.api().page.info();
      if (info.recordsDisplay === 0) {
        $(this).closest('.dataTables_wrapper').find('.dataTables_paginate').hide();
      } else {
        $(this).closest('.dataTables_wrapper').find('.dataTables_paginate').show();
      }
    }
  };

  const config = { ...defaults, ...options };
  return jQuery(selector).DataTable(config);
}

/* ===========================================================
   6. Image Preview on File Select
   =========================================================== */
function initImagePreview(inputSelector, previewSelector) {
  const input = document.querySelector(inputSelector);
  const preview = document.querySelector(previewSelector);
  if (!input || !preview) return;

  input.addEventListener('change', function () {
    const file = this.files[0];
    if (!file) return;

    if (!file.type.startsWith('image/')) {
      Toast.warning('Please select an image file');
      this.value = '';
      return;
    }

    const reader = new FileReader();
    reader.onload = function (e) {
      preview.src = e.target.result;
      preview.classList.add('show');
    };
    reader.readAsDataURL(file);
  });
}

/* ===========================================================
   7. Form Validation Helpers
   =========================================================== */
function validateRequired(form) {
  let valid = true;
  const required = form.querySelectorAll('[required]');

  required.forEach(field => {
    field.classList.remove('is-invalid');
    const feedback = field.parentElement.querySelector('.invalid-feedback');
    if (feedback) feedback.remove();

    if (!field.value.trim()) {
      valid = false;
      field.classList.add('is-invalid');
      const msg = document.createElement('div');
      msg.className = 'invalid-feedback';
      msg.textContent = 'This field is required';
      field.parentElement.appendChild(msg);
    }
  });

  return valid;
}

function validateEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function validatePhone(phone) {
  return /^[\d\s\-+()]{7,15}$/.test(phone);
}

function clearValidation(form) {
  form.querySelectorAll('.is-invalid').forEach(el => el.classList.remove('is-invalid'));
  form.querySelectorAll('.invalid-feedback').forEach(el => el.remove());
}

/* ===========================================================
   8. Toggle Status (AJAX)
   =========================================================== */
function toggleStatus(url, element) {
  ajaxRequest(url)
    .then(data => {
      Toast.success(data.message || 'Status updated');
      if (element) {
        const badge = element.closest('tr')?.querySelector('.badge-status');
        if (badge && data.status) {
          badge.className = `badge-status ${data.status}`;
          badge.textContent = data.status.charAt(0).toUpperCase() + data.status.slice(1);
        }
      }
      if (data.reload) window.location.reload();
    })
    .catch(err => {
      Toast.error(err.message || 'Failed to update status');
    });
}

/* ===========================================================
   9. Auto-Refresh Function
   =========================================================== */
let autoRefreshTimers = {};

function startAutoRefresh(key, url, callback, interval = 30000) {
  stopAutoRefresh(key);
  autoRefreshTimers[key] = setInterval(() => {
    fetch(url, {
      headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' },
      credentials: 'same-origin'
    })
      .then(r => r.json())
      .then(data => callback(data))
      .catch(() => {});
  }, interval);
}

function stopAutoRefresh(key) {
  if (autoRefreshTimers[key]) {
    clearInterval(autoRefreshTimers[key]);
    delete autoRefreshTimers[key];
  }
}

function stopAllAutoRefresh() {
  Object.keys(autoRefreshTimers).forEach(stopAutoRefresh);
}

/* ===========================================================
   10. Format Currency
   =========================================================== */
function formatCurrency(amount, currency = 'USD', decimals = 2) {
  const num = parseFloat(amount);
  if (isNaN(num)) return '0.00';

  const formatted = num.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  const symbols = { USD: '$', EUR: '€', GBP: '£', LKR: 'Rs', INR: '₹', AED: 'د.إ', SAR: '﷼' };
  const symbol = symbols[currency] || currency + ' ';
  return symbol + formatted;
}

/* ===========================================================
   11. Time Ago Display
   =========================================================== */
function timeAgo(dateString) {
  const now = new Date();
  const date = new Date(dateString);
  const seconds = Math.floor((now - date) / 1000);

  const intervals = [
    { label: 'year', seconds: 31536000 },
    { label: 'month', seconds: 2592000 },
    { label: 'week', seconds: 604800 },
    { label: 'day', seconds: 86400 },
    { label: 'hour', seconds: 3600 },
    { label: 'minute', seconds: 60 }
  ];

  for (const interval of intervals) {
    const count = Math.floor(seconds / interval.seconds);
    if (count >= 1) {
      return `${count} ${interval.label}${count > 1 ? 's' : ''} ago`;
    }
  }

  return 'Just now';
}

/* ===========================================================
   12. Drag and Drop Sorting
   =========================================================== */
function initSortable(selector, url) {
  const el = document.querySelector(selector);
  if (!el) return;

  let draggedItem = null;

  el.querySelectorAll('[draggable="true"]').forEach(item => {
    item.addEventListener('dragstart', (e) => {
      draggedItem = item;
      item.style.opacity = '0.4';
      e.dataTransfer.effectAllowed = 'move';
    });

    item.addEventListener('dragend', () => {
      item.style.opacity = '1';
      el.querySelectorAll('[draggable="true"]').forEach(i => {
        i.classList.remove('drag-over');
      });
    });

    item.addEventListener('dragover', (e) => {
      e.preventDefault();
      e.dataTransfer.dropEffect = 'move';
      item.classList.add('drag-over');
    });

    item.addEventListener('dragleave', () => {
      item.classList.remove('drag-over');
    });

    item.addEventListener('drop', (e) => {
      e.preventDefault();
      item.classList.remove('drag-over');

      if (draggedItem !== item) {
        const allItems = [...el.querySelectorAll('[draggable="true"]')];
        const draggedIndex = allItems.indexOf(draggedItem);
        const targetIndex = allItems.indexOf(item);

        if (draggedIndex < targetIndex) {
          item.parentNode.insertBefore(draggedItem, item.nextSibling);
        } else {
          item.parentNode.insertBefore(draggedItem, item);
        }

        const order = [...el.querySelectorAll('[draggable="true"]')].map((item, idx) => ({
          id: item.dataset.id,
          position: idx
        }));

        ajaxRequest(url, { body: { order } })
          .then(() => Toast.success('Order updated'))
          .catch(() => Toast.error('Failed to update order'));
      }
    });
  });
}

/* ===========================================================
   13. Responsive Sidebar Toggle
   =========================================================== */
function toggleSidebar() {
  const sidebar = document.querySelector('.sidebar');
  const overlay = document.querySelector('.sidebar-overlay');

  if (sidebar) {
    sidebar.classList.toggle('mobile-open');
    if (overlay) overlay.classList.toggle('show');
    document.body.style.overflow = sidebar.classList.contains('mobile-open') ? 'hidden' : '';
  }
}

function toggleSidebarCollapse() {
  document.querySelector('.app-wrapper')?.classList.toggle('sidebar-collapsed');
  localStorage.setItem('sidebarCollapsed', document.querySelector('.app-wrapper')?.classList.contains('sidebar-collapsed'));
}

document.addEventListener('DOMContentLoaded', () => {
  if (localStorage.getItem('sidebarCollapsed') === 'true') {
    document.querySelector('.app-wrapper')?.classList.add('sidebar-collapsed');
  }

  document.querySelectorAll('.sidebar-toggle').forEach(btn => {
    btn.addEventListener('click', toggleSidebar);
  });

  document.querySelector('.sidebar-overlay')?.addEventListener('click', toggleSidebar);
});

/* ===========================================================
   14. Notification Polling
   =========================================================== */
let notificationPollingTimer = null;

function startNotificationPolling(url, interval = 60000) {
  stopNotificationPolling();

  function poll() {
    fetch(url, {
      headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' },
      credentials: 'same-origin'
    })
      .then(r => r.json())
      .then(data => {
        if (data.count !== undefined) {
          const badge = document.querySelector('.notification-count');
          if (badge) {
            badge.textContent = data.count;
            badge.style.display = data.count > 0 ? 'flex' : 'none';
          }
        }
      })
      .catch(() => {});
  }

  poll();
  notificationPollingTimer = setInterval(poll, interval);
}

function stopNotificationPolling() {
  if (notificationPollingTimer) {
    clearInterval(notificationPollingTimer);
    notificationPollingTimer = null;
  }
}

/* ===========================================================
   15. Print Function
   =========================================================== */
function printElement(selector) {
  const element = document.querySelector(selector);
  if (!element) return;

  const printWindow = window.open('', '_blank');
  printWindow.document.write(`
    <!DOCTYPE html>
    <html>
    <head>
      <title>Print</title>
      <style>
        body { font-family: Arial, sans-serif; font-size: 12px; color: #000; }
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 6px 8px; border: 1px solid #ddd; text-align: left; font-size: 11px; }
        th { background: #f0f0f0; font-weight: bold; }
        .no-print { display: none; }
        @media print { body { margin: 0; } }
      </style>
    </head>
    <body>${element.innerHTML}</body>
    </html>
  `);
  printWindow.document.close();
  printWindow.focus();
  setTimeout(() => {
    printWindow.print();
    printWindow.close();
  }, 500);
}

/* ===========================================================
   16. Date Range Picker Initialization
   =========================================================== */
function initDateRangePicker(selector, callback) {
  if (typeof jQuery === 'undefined' || typeof jQuery.fn.daterangepicker === 'undefined') return;

  const defaults = {
    autoUpdateInput: false,
    locale: {
      cancelLabel: 'Clear',
      applyLabel: 'Apply',
      format: 'YYYY-MM-DD'
    },
    ranges: {
      'Today': [moment(), moment()],
      'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
      'Last 7 Days': [moment().subtract(6, 'days'), moment()],
      'Last 30 Days': [moment().subtract(29, 'days'), moment()],
      'This Month': [moment().startOf('month'), moment().endOf('month')],
      'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
    }
  };

  jQuery(selector).daterangepicker(defaults, (start, end) => {
    const startStr = start.format('YYYY-MM-DD');
    const endStr = end.format('YYYY-MM-DD');
    jQuery(selector).val(`${startStr} to ${endStr}`);
    if (callback) callback(startStr, endStr);
  });

  jQuery(selector).on('apply.daterangepicker', function (ev, picker) {
    jQuery(this).val(`${picker.startDate.format('YYYY-MM-DD')} to ${picker.endDate.format('YYYY-MM-DD')}`);
  });

  jQuery(selector).on('cancel.daterangepicker', function () {
    jQuery(this).val('');
    if (callback) callback(null, null);
  });
}

/* ===========================================================
   17. Chart Initialization Helpers
   =========================================================== */
const ChartHelper = {
  defaultColors: ['#e74c3c', '#3498db', '#27ae60', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22', '#34495e'],

  defaults() {
    return {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        legend: {
          position: 'bottom',
          labels: { padding: 16, usePointStyle: true, font: { family: "'Inter', sans-serif", size: 12 } }
        },
        tooltip: {
          backgroundColor: '#343a40',
          titleFont: { family: "'Inter', sans-serif", size: 13 },
          bodyFont: { family: "'Inter', sans-serif", size: 12 },
          padding: 10,
          cornerRadius: 8
        }
      }
    };
  },

  bar(canvasId, labels, datasets, options = {}) {
    const ctx = document.getElementById(canvasId);
    if (!ctx) return null;

    return new Chart(ctx.getContext('2d'), {
      type: 'bar',
      data: {
        labels,
        datasets: datasets.map((ds, i) => ({
          label: ds.label || '',
          data: ds.data || [],
          backgroundColor: ds.color || this.defaultColors[i],
          borderRadius: 6,
          borderSkipped: false,
          ...ds
        }))
      },
      options: { ...this.defaults(), ...options }
    });
  },

  line(canvasId, labels, datasets, options = {}) {
    const ctx = document.getElementById(canvasId);
    if (!ctx) return null;

    return new Chart(ctx.getContext('2d'), {
      type: 'line',
      data: {
        labels,
        datasets: datasets.map((ds, i) => ({
          label: ds.label || '',
          data: ds.data || [],
          borderColor: ds.color || this.defaultColors[i],
          backgroundColor: (ds.color || this.defaultColors[i]) + '15',
          tension: 0.4,
          fill: true,
          pointRadius: 3,
          pointHoverRadius: 6,
          ...ds
        }))
      },
      options: { ...this.defaults(), ...options }
    });
  },

  doughnut(canvasId, labels, data, options = {}) {
    const ctx = document.getElementById(canvasId);
    if (!ctx) return null;

    return new Chart(ctx.getContext('2d'), {
      type: 'doughnut',
      data: {
        labels,
        datasets: [{
          data,
          backgroundColor: this.defaultColors.slice(0, data.length),
          borderWidth: 2,
          borderColor: '#fff'
        }]
      },
      options: {
        ...this.defaults(),
        cutout: '68%',
        plugins: {
          ...this.defaults().plugins,
          legend: { ...this.defaults().plugins.legend, position: 'bottom' }
        },
        ...options
      }
    });
  }
};

/* ===========================================================
   18. Activity Log Polling
   =========================================================== */
let activityLogTimer = null;

function startActivityLogPolling(containerSelector, url, interval = 15000) {
  stopActivityLogPolling();

  const container = document.querySelector(containerSelector);
  if (!container) return;

  function poll() {
    fetch(url, {
      headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' },
      credentials: 'same-origin'
    })
      .then(r => r.json())
      .then(data => {
        if (data.html) {
          container.innerHTML = data.html;
        }
      })
      .catch(() => {});
  }

  activityLogTimer = setInterval(poll, interval);
}

function stopActivityLogPolling() {
  if (activityLogTimer) {
    clearInterval(activityLogTimer);
    activityLogTimer = null;
  }
}

/* ===========================================================
   19. Password Toggle Visibility
   =========================================================== */
function togglePasswordVisibility(inputId) {
  const input = document.getElementById(inputId);
  if (!input) return;

  const icon = input.parentElement?.querySelector('.toggle-password');
  if (input.type === 'password') {
    input.type = 'text';
    if (icon) {
      icon.classList.remove('fa-eye');
      icon.classList.add('fa-eye-slash');
    }
  } else {
    input.type = 'password';
    if (icon) {
      icon.classList.remove('fa-eye-slash');
      icon.classList.add('fa-eye');
    }
  }
}

document.addEventListener('click', (e) => {
  if (e.target.classList.contains('toggle-password')) {
    const input = e.target.closest('.input-group')?.querySelector('input') ||
                  e.target.closest('div')?.querySelector('input');
    if (input) {
      const isPassword = input.type === 'password';
      input.type = isPassword ? 'text' : 'password';
      e.target.classList.toggle('fa-eye', !isPassword);
      e.target.classList.toggle('fa-eye-slash', isPassword);
    }
  }
});

/* ===========================================================
   20. Slug Generator from Name Field
   =========================================================== */
function initSlugGenerator(nameSelector, slugSelector) {
  const nameInput = document.querySelector(nameSelector);
  const slugInput = document.querySelector(slugSelector);
  if (!nameInput || !slugInput) return;

  nameInput.addEventListener('input', function () {
    slugInput.value = this.value
      .toLowerCase()
      .trim()
      .replace(/[^\w\s-]/g, '')
      .replace(/[\s_]+/g, '-')
      .replace(/-+/g, '-')
      .replace(/^-+|-+$/g, '');
  });
}

/* ===========================================================
   21. Duplicate Detection
   =========================================================== */
function checkDuplicate(url, value, excludeId = null) {
  return new Promise((resolve) => {
    const params = new URLSearchParams({ value });
    if (excludeId) params.append('exclude_id', excludeId);

    fetch(`${url}?${params.toString()}`, {
      headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' },
      credentials: 'same-origin'
    })
      .then(r => r.json())
      .then(data => resolve(data.exists === true))
      .catch(() => resolve(false));
  });
}

/* ===========================================================
   22. Loading Overlay Show/Hide
   =========================================================== */
function showLoading() {
  let overlay = document.getElementById('loading-overlay');
  if (!overlay) {
    overlay = document.createElement('div');
    overlay.id = 'loading-overlay';
    overlay.className = 'loading-overlay show';
    overlay.innerHTML = '<div class="spinner"></div>';
    document.body.appendChild(overlay);
  } else {
    overlay.classList.add('show');
  }
}

function hideLoading() {
  const overlay = document.getElementById('loading-overlay');
  if (overlay) overlay.classList.remove('show');
}

/* ===========================================================
   23. Form Reset Helper
   =========================================================== */
function resetForm(formSelector) {
  const form = document.querySelector(formSelector);
  if (!form) return;

  form.reset();
  clearValidation(form);

  form.querySelectorAll('.image-preview').forEach(preview => {
    preview.classList.remove('show');
    preview.src = '';
  });

  form.querySelectorAll('.select2').forEach(select => {
    if (typeof jQuery !== 'undefined' && jQuery.fn.select2) {
      jQuery(select).val(null).trigger('change');
    }
  });
}

/* ===========================================================
   24. AJAX Form Submit Helper
   =========================================================== */
function submitForm(formSelector, options = {}) {
  const form = document.querySelector(formSelector);
  if (!form) return Promise.reject('Form not found');

  if (!validateRequired(form)) {
    Toast.warning('Please fill in all required fields');
    return Promise.reject('Validation failed');
  }

  const formData = new FormData(form);
  const url = form.action || window.location.href;

  showLoading();

  return fetch(url, {
    method: form.method || 'POST',
    body: formData,
    headers: {
      'X-CSRF-TOKEN': CSRF.get(),
      'X-Requested-With': 'XMLHttpRequest',
      'Accept': 'application/json'
    },
    credentials: 'same-origin'
  })
    .then(async response => {
      const data = await response.json().catch(() => null);
      if (!response.ok) {
        throw data || { message: 'Request failed' };
      }
      return data;
    })
    .then(data => {
      hideLoading();
      Toast.success(data.message || 'Saved successfully!');

      if (options.onSuccess) options.onSuccess(data);
      if (data.redirect) setTimeout(() => window.location.href = data.redirect, 800);
      if (data.reload) setTimeout(() => window.location.reload(), 800);

      return data;
    })
    .catch(err => {
      hideLoading();
      const message = err.message || 'Something went wrong';

      if (err.errors) {
        Object.keys(err.errors).forEach(field => {
          const input = form.querySelector(`[name="${field}"]`);
          if (input) {
            input.classList.add('is-invalid');
            let feedback = input.parentElement.querySelector('.invalid-feedback');
            if (!feedback) {
              feedback = document.createElement('div');
              feedback.className = 'invalid-feedback';
              input.parentElement.appendChild(feedback);
            }
            feedback.textContent = Array.isArray(err.errors[field]) ? err.errors[field][0] : err.errors[field];
          }
        });
        Toast.error('Please fix the errors below');
      } else {
        Toast.error(message);
      }

      throw err;
    });
}

/* ===========================================================
   25. DataTable Export Functions
   =========================================================== */
function exportTableToCSV(selector, filename = 'export.csv') {
  const table = document.querySelector(selector);
  if (!table) return;

  const rows = [];
  table.querySelectorAll('tr').forEach(row => {
    const cols = [];
    row.querySelectorAll('th, td').forEach(cell => {
      let text = cell.innerText.replace(/"/g, '""').trim();
      cols.push(`"${text}"`);
    });
    rows.push(cols.join(','));
  });

  const csvContent = rows.join('\n');
  const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' });
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = filename;
  link.click();
  URL.revokeObjectURL(link.href);
  Toast.success('Exported to CSV');
}

function exportTableToPDF(selector, title = 'Report') {
  if (typeof html2pdf !== 'undefined') {
    const element = document.querySelector(selector);
    if (!element) return;
    html2pdf().set({
      margin: 10,
      filename: `${title}.pdf`,
      image: { type: 'jpeg', quality: 0.98 },
      html2canvas: { scale: 2 },
      jsPDF: { unit: 'mm', format: 'a4', orientation: 'landscape' }
    }).from(element).save();
    Toast.success('Exported to PDF');
  } else if (typeof jQuery !== 'undefined' && jQuery.fn.tableExport) {
    jQuery(selector).tableExport({ type: 'pdf', filename: title });
  } else {
    Toast.warning('PDF export library not loaded');
  }
}

/* ===========================================================
   26. Dropdown Menu Handling
   =========================================================== */
document.addEventListener('click', (e) => {
  const toggle = e.target.closest('[data-dropdown-toggle]');
  if (toggle) {
    e.preventDefault();
    const menuId = toggle.getAttribute('data-dropdown-toggle');
    const menu = document.getElementById(menuId);
    if (menu) {
      document.querySelectorAll('.dropdown-menu.show').forEach(m => {
        if (m !== menu) m.classList.remove('show');
      });
      menu.classList.toggle('show');
    }
    return;
  }

  if (!e.target.closest('.dropdown-menu')) {
    document.querySelectorAll('.dropdown-menu.show').forEach(m => m.classList.remove('show'));
  }
});

/* ===========================================================
   27. Active Menu Highlight
   =========================================================== */
document.addEventListener('DOMContentLoaded', () => {
  const currentPath = window.location.pathname;
  document.querySelectorAll('.sidebar-menu a').forEach(link => {
    const href = link.getAttribute('href');
    if (href && currentPath.startsWith(href) && href !== '/') {
      link.classList.add('active');
    } else if (href === currentPath) {
      link.classList.add('active');
    }
  });
});

/* ===========================================================
   28. Keyboard Shortcuts
   =========================================================== */
document.addEventListener('keydown', (e) => {
  // Ctrl/Cmd + K = focus search
  if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
    e.preventDefault();
    const search = document.querySelector('.search-bar input, input[name="search"]');
    if (search) search.focus();
  }

  // Escape = close modals
  if (e.key === 'Escape') {
    document.querySelectorAll('.modal-dialog.show').forEach(modal => {
      modal.classList.remove('show');
    });
    document.querySelectorAll('.modal-backdrop.show').forEach(backdrop => {
      backdrop.classList.remove('show');
    });
    document.querySelectorAll('.dropdown-menu.show').forEach(menu => {
      menu.classList.remove('show');
    });
  }
});

/* ===========================================================
   29. Window Before Unload Warning
   =========================================================== */
let formDirty = false;

document.addEventListener('DOMContentLoaded', () => {
  document.querySelectorAll('form').forEach(form => {
    form.addEventListener('input', () => { formDirty = true; });
    form.addEventListener('submit', () => { formDirty = false; });
  });
});

window.addEventListener('beforeunload', (e) => {
  if (formDirty) {
    e.preventDefault();
    e.returnValue = '';
  }
});

/* ===========================================================
   30. Init on DOM Ready
   =========================================================== */
document.addEventListener('DOMContentLoaded', () => {
  CSRF.init();
  Toast.init();

  // Init image previews
  document.querySelectorAll('[data-preview]').forEach(input => {
    const target = input.dataset.preview;
    initImagePreview(`#${input.id}`, target);
  });

  // Init slug generators
  document.querySelectorAll('[data-slug-source]').forEach(slugInput => {
    const source = slugInput.dataset.slugSource;
    initSlugGenerator(source, `#${slugInput.id}`);
  });

  // Tooltips (if Bootstrap loaded)
  if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip) {
    document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => {
      new bootstrap.Tooltip(el);
    });
  }

  console.log('Tap2Order Admin initialized');
});
