(function () {
  const body = document.body;
  const menuButton = document.getElementById('mobileMenuBtn');
  const sidebarBackdrop = document.getElementById('sidebarBackdrop');
  const FLUENT_ICON_FILES = Object.freeze({
    add: 'add_20_regular.svg',
    add_box: 'box_24_regular.svg',
    apps: 'apps_24_regular.svg',
    archive: 'archive_24_regular.svg',
    attach_file: 'attach_20_regular.svg',
    campaign: 'megaphone_20_regular.svg',
    check_circle: 'checkmark_circle_20_filled.svg',
    close: 'dismiss_20_regular.svg',
    dashboard: 'grid_24_regular.svg',
    database_off: 'database_warning_20_regular.svg',
    delete: 'delete_20_regular.svg',
    deployed_code: 'cube_24_regular.svg',
    description: 'document_24_regular.svg',
    download: 'arrow_download_20_regular.svg',
    draft: 'document_24_regular.svg',
    edit: 'edit_20_regular.svg',
    error: 'error_circle_20_filled.svg',
    forward_to_inbox: 'mail_arrow_forward_20_regular.svg',
    group: 'people_24_regular.svg',
    inventory_2: 'box_24_regular.svg',
    library_books: 'library_24_regular.svg',
    link_off: 'link_dismiss_20_regular.svg',
    login: 'arrow_enter_20_regular.svg',
    logout: 'sign_out_20_regular.svg',
    mark_email_unread: 'mail_unread_24_regular.svg',
    memory: 'memory_16_regular.svg',
    menu: 'navigation_20_regular.svg',
    notifications: 'alert_20_regular.svg',
    notifications_none: 'alert_off_20_regular.svg',
    note_add: 'document_add_24_regular.svg',
    person_add: 'person_add_20_regular.svg',
    precision_manufacturing: 'bot_24_filled.svg',
    save: 'save_20_regular.svg',
    search_off: 'search_24_regular.svg',
    send: 'send_20_regular.svg',
    stars: 'star_20_filled.svg',
    swap_horiz: 'arrow_swap_20_regular.svg',
    sync: 'arrow_sync_20_regular.svg',
    upgrade: 'arrow_up_20_regular.svg',
    upload: 'arrow_upload_20_regular.svg',
    upload_file: 'document_arrow_up_24_regular.svg',
    visibility: 'eye_20_regular.svg',
    warning: 'warning_20_filled.svg'
  });

  function applyFluentIcon(element, iconName) {
    if (!element) return;
    const fileName = FLUENT_ICON_FILES[iconName] || 'question_20_regular.svg';
    element.classList.remove('material-symbols-outlined');
    element.classList.add('fluent-icon');
    element.style.setProperty('--fluent-icon-url', `url("/vendor/fluent-icons/${fileName}")`);
    element.setAttribute('aria-hidden', 'true');
    element.textContent = '';
  }

  function hydrateFluentIcons(root) {
    root.querySelectorAll('.material-symbols-outlined').forEach((element) => {
      applyFluentIcon(element, element.textContent.trim());
    });
  }

  function initNotiflix() {
    if (!window.Notiflix) return;

    window.Notiflix.Notify.init({
      width: '320px',
      position: 'right-top',
      distance: '16px',
      timeout: 2600,
      borderRadius: '4px',
      fontFamily: 'Montserrat Variable, Montserrat, sans-serif',
      fontSize: '13px',
      messageMaxLength: 180,
      clickToClose: true,
      pauseOnHover: true,
      cssAnimationStyle: 'from-right',
      useIcon: true,
      zindex: 5000,
      success: {
        background: '#2e7d32',
        textColor: '#ffffff'
      },
      failure: {
        background: '#c62828',
        textColor: '#ffffff'
      },
      warning: {
        background: '#9a5b00',
        textColor: '#ffffff'
      },
      info: {
        background: '#223771',
        textColor: '#ffffff'
      }
    });

    window.Notiflix.Confirm.init({
      width: '360px',
      borderRadius: '4px',
      fontFamily: 'Montserrat Variable, Montserrat, sans-serif',
      titleColor: '#161824',
      titleFontSize: '16px',
      messageColor: '#565b70',
      messageFontSize: '13px',
      okButtonBackground: '#223771',
      okButtonColor: '#ffffff',
      cancelButtonBackground: '#eeedf6',
      cancelButtonColor: '#3c4054',
      backOverlayColor: 'rgba(15, 23, 42, 0.42)',
      zindex: 5001,
      cssAnimationStyle: 'zoom'
    });
  }

  function notify(type, message) {
    if (!message) return;

    if (!window.Notiflix) {
      console.info(message);
      return;
    }

    const Notify = window.Notiflix.Notify;

    if (type === 'success') {
      Notify.success(message);
      return;
    }

    if (type === 'failure') {
      Notify.failure(message);
      return;
    }

    if (type === 'warning') {
      Notify.warning(message);
      return;
    }

    Notify.info(message);
  }

  function confirmAction(message, onConfirm) {
    if (!window.Notiflix) {
      if (window.confirm(message || 'Xác nhận thao tác?') && typeof onConfirm === 'function') {
        onConfirm();
      }
      return;
    }

    window.Notiflix.Confirm.show(
      'Xác nhận thao tác',
      message,
      'Xác nhận',
      'Hủy',
      () => {
        if (typeof onConfirm === 'function') {
        onConfirm();
        return;
      }
      notify('success', 'Đã xác nhận thao tác');
      },
      () => {
        notify('info', 'Đã hủy thao tác');
      }
    );
  }

  function setMobileNav(open) {
    body.classList.toggle('mobile-nav-open', open);
    if (menuButton) {
      menuButton.setAttribute('aria-expanded', open ? 'true' : 'false');
    }
  }

  function openModal(id) {
    const modal = document.getElementById(id);
    if (!modal) return;

    modal.classList.add('open');
    const focusTarget = modal.querySelector('input, select, textarea, button');
    if (focusTarget) {
      window.setTimeout(() => focusTarget.focus(), 60);
    }
  }

  function closeModal(modal) {
    if (!modal) return;
    modal.classList.remove('open');
  }

  function applyTableFilters(tableId) {
    const table = document.getElementById(tableId);
    if (!table) return;

    const searchInput = document.querySelector(`[data-table-search="${tableId}"]`);
    const query = searchInput ? searchInput.value.trim().toLowerCase() : '';
    const selects = document.querySelectorAll(`[data-filter-select][data-filter-table="${tableId}"]`);

    table.querySelectorAll('tbody tr').forEach((row) => {
      const matchesSearch = !query || (row.dataset.search || '').includes(query);
      let matchesSelects = true;

      selects.forEach((select) => {
        const column = select.dataset.filterColumn;
        const value = select.value;
        if (value && row.dataset[column] !== value) {
          matchesSelects = false;
        }
      });

      row.hidden = !(matchesSearch && matchesSelects);
    });
  }

  function formatFileSize(bytes) {
    if (!Number.isFinite(bytes) || bytes <= 0) return '0 B';

    const units = ['B', 'KB', 'MB', 'GB'];
    const index = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
    const value = bytes / Math.pow(1024, index);

    return `${value.toFixed(value >= 10 || index === 0 ? 0 : 1)} ${units[index]}`;
  }

  function isAllowedPackageFile(file) {
    if (!file) return false;

    const name = file.name.toLowerCase();
    const allowedExtensions = ['.deb', '.tar', '.tar.gz', '.tgz', '.zip', '.gz'];

    return allowedExtensions.some((extension) => name.endsWith(extension));
  }

  function renderSelectedFile(zone, file) {
    const preview = zone.querySelector('[data-file-preview]');
    const fileName = zone.querySelector('[data-file-name]');
    const fileMeta = zone.querySelector('[data-file-meta]');

    if (!preview || !fileName || !fileMeta) return;

    if (!file) {
      preview.hidden = true;
      fileName.textContent = 'Chưa chọn file';
      fileMeta.textContent = '';
      zone.classList.remove('has-file');
      return;
    }

    fileName.textContent = file.name;
    fileMeta.textContent = `${formatFileSize(file.size)} • ${file.type || 'package file'}`;
    preview.hidden = false;
    zone.classList.add('has-file');
    notify('success', `Đã chọn file: ${file.name}`);
  }

  function setInputFiles(input, files) {
    try {
      input.files = files;
    } catch (error) {
      console.info('Browser does not allow assigning dropped files to input.files.', error);
    }
  }

  function handlePackageFiles(zone, files) {
    const input = zone.querySelector('[data-file-input]');
    const file = files && files[0];

    if (!input || !file) return;

    if (!isAllowedPackageFile(file)) {
      notify('warning', 'File chưa đúng định dạng. Vui lòng chọn .deb, .tar, .tgz, .zip hoặc .gz.');
      return;
    }

    setInputFiles(input, files);
    renderSelectedFile(zone, file);
  }

  function initFileDropzones() {
    document.querySelectorAll('[data-file-dropzone]').forEach((zone) => {
      const input = zone.querySelector('[data-file-input]');
      const browseButton = zone.querySelector('[data-file-browse]');
      const clearButton = zone.querySelector('[data-file-clear]');

      if (!input) return;

      if (browseButton) {
        browseButton.addEventListener('click', () => input.click());
      }

      if (clearButton) {
        clearButton.addEventListener('click', () => {
          input.value = '';
          renderSelectedFile(zone, null);
          notify('info', 'Đã bỏ file đã chọn');
        });
      }

      input.addEventListener('change', () => {
        handlePackageFiles(zone, input.files);
      });

      ['dragenter', 'dragover'].forEach((eventName) => {
        zone.addEventListener(eventName, (event) => {
          event.preventDefault();
          event.stopPropagation();
          zone.classList.add('dragover');
        });
      });

      ['dragleave', 'drop'].forEach((eventName) => {
        zone.addEventListener(eventName, (event) => {
          event.preventDefault();
          event.stopPropagation();
          zone.classList.remove('dragover');
        });
      });

      zone.addEventListener('drop', (event) => {
        handlePackageFiles(zone, event.dataTransfer.files);
      });
    });
  }

  function updateRegisterSubmit(form) {
    const submitButton = form.querySelector('[data-register-submit]');
    if (!submitButton) return;

    const uniqueInputs = form.querySelectorAll('[data-unique-check]');
    const isBlocked = Array.from(uniqueInputs).some((input) => (
      input.dataset.uniqueStatus === 'error' || input.dataset.uniqueStatus === 'checking'
    ));

    submitButton.disabled = isBlocked;
  }

  function setUniqueState(input, state, message) {
    const field = input.closest('.form-field');
    const form = input.closest('[data-register-form]');
    const feedback = form
      ? form.querySelector(`[data-unique-feedback="${input.dataset.uniqueCheck}"]`)
      : null;

    input.dataset.uniqueStatus = state;

    if (field) {
      field.classList.toggle('has-error', state === 'error');
      field.classList.toggle('has-success', state === 'success');
    }

    if (feedback) {
      feedback.textContent = message || '';
      feedback.style.display = message ? 'block' : '';
    }

    input.setCustomValidity(state === 'error' ? message : '');

    if (form) {
      updateRegisterSubmit(form);
    }
  }

  function checkUniqueInput(input) {
    const field = input.dataset.uniqueCheck;
    const value = input.value.trim();

    if (!field || !value) {
      setUniqueState(input, 'idle', '');
      return;
    }

    if (field === 'email' && !input.validity.valid) {
      setUniqueState(input, 'idle', '');
      return;
    }

    const requestId = String(Date.now());
    input.dataset.uniqueRequestId = requestId;
    setUniqueState(input, 'checking', 'Đang kiểm tra...');

    fetch(`/register/check?field=${encodeURIComponent(field)}&value=${encodeURIComponent(value)}`, {
      headers: {
        Accept: 'application/json'
      }
    })
      .then((response) => response.ok ? response.json() : Promise.reject(new Error('Cannot check field')))
      .then((data) => {
        if (input.dataset.uniqueRequestId !== requestId) return;

        setUniqueState(
          input,
          data.available ? 'success' : 'error',
          data.message || (data.available ? 'Có thể sử dụng.' : 'Đã tồn tại.')
        );
      })
      .catch((error) => {
        console.info('Cannot check registration field:', error);
        if (input.dataset.uniqueRequestId === requestId) {
          setUniqueState(input, 'idle', '');
        }
      });
  }

  function initRegistrationUniqueChecks() {
    document.querySelectorAll('[data-register-form]').forEach((form) => {
      const timers = new Map();

      form.querySelectorAll('[data-unique-check]').forEach((input) => {
        input.addEventListener('input', () => {
          window.clearTimeout(timers.get(input));
          setUniqueState(input, 'idle', '');
          timers.set(input, window.setTimeout(() => checkUniqueInput(input), 450));
        });

        input.addEventListener('blur', () => {
          window.clearTimeout(timers.get(input));
          checkUniqueInput(input);
        });

        if (input.value.trim()) {
          checkUniqueInput(input);
        }
      });

      form.addEventListener('submit', (event) => {
        const blockedInput = form.querySelector('[data-unique-status="error"], [data-unique-status="checking"]');
        if (!blockedInput) return;

        event.preventDefault();
        notify('warning', blockedInput.dataset.uniqueStatus === 'checking'
          ? 'Đang kiểm tra username/email, vui lòng chờ một chút.'
          : 'Vui lòng đổi username/email đang bị trùng.');
        blockedInput.focus();
      });
    });
  }

  function getUserDataFromRow(row) {
    return {
      id: row.dataset.userId || '',
      name: row.dataset.userName || '',
      username: row.dataset.userUsername || '',
      email: row.dataset.userEmail || '',
      fullName: row.dataset.userFullName || '',
      role: row.dataset.userRole || 'User',
      status: row.dataset.userStatus || '',
      isActive: row.dataset.userActive === 'true',
      createdAt: row.dataset.userCreatedAt || '',
      updatedAt: row.dataset.userUpdatedAt || '',
      packageCount: row.dataset.userPackageCount || '0',
      applicationCount: row.dataset.userApplicationCount || '0',
      documentCount: row.dataset.userDocumentCount || '0'
    };
  }

  function parseJsonAttribute(value, fallback) {
    try {
      return JSON.parse(value || '');
    } catch (error) {
      return fallback;
    }
  }

  function getAppDataFromTrigger(trigger) {
    return {
      id: trigger.dataset.appId || '',
      code: trigger.dataset.appCode || '',
      name: trigger.dataset.appName || '',
      version: trigger.dataset.appVersion || '',
      status: trigger.dataset.appStatus || 'Draft',
      openUrl: trigger.dataset.appOpenUrl || '',
      notes: trigger.dataset.appNotes || '',
      packages: parseJsonAttribute(trigger.dataset.appPackages, [])
    };
  }

  function findEditAppVersionSelect(form, packageId) {
    return Array.from(form.querySelectorAll('[data-edit-app-version]'))
      .find((select) => select.dataset.editAppVersion === packageId);
  }

  function setEditAppPackageEnabled(form, checkbox) {
    const select = findEditAppVersionSelect(form, checkbox.dataset.editAppPackage);
    if (select) {
      select.disabled = !checkbox.checked;
    }
  }

  function setEditAppField(form, field, value) {
    const input = form.querySelector(`[data-edit-app-field="${field}"]`);
    if (input) {
      input.value = value || '';
    }
  }

  function openAppEdit(trigger) {
    const app = getAppDataFromTrigger(trigger);
    const form = document.getElementById('editAppForm');
    if (!form || !app.id) return;

    form.action = `/applications/${encodeURIComponent(app.id)}/edit`;
    setEditAppField(form, 'appCode', app.code);
    setEditAppField(form, 'appName', app.name);
    setEditAppField(form, 'appVersion', app.version);
    setEditAppField(form, 'status', app.status);
    setEditAppField(form, 'openUrl', app.openUrl);
    setEditAppField(form, 'notes', app.notes);

    form.querySelectorAll('[data-edit-app-package]').forEach((checkbox) => {
      checkbox.checked = false;
      setEditAppPackageEnabled(form, checkbox);
    });

    app.packages.forEach((packageItem) => {
      const packageId = packageItem.packageId || '';
      const checkbox = Array.from(form.querySelectorAll('[data-edit-app-package]'))
        .find((input) => input.dataset.editAppPackage === packageId);
      const select = findEditAppVersionSelect(form, packageId);

      if (checkbox) {
        checkbox.checked = true;
      }

      if (select) {
        select.disabled = false;
        select.value = packageItem.selectedVersionId || '';
      }
    });

    openModal('editAppModal');
  }

  function openPackageUpdate(packageId) {
    const modalId = 'updatePackageModal';
    const modal = document.getElementById(modalId);
    const packageSelect = modal ? modal.querySelector('select[name="packageId"]') : null;

    if (packageSelect && packageId) {
      packageSelect.value = packageId;
    }

    openModal(modalId);
  }

  function setText(selector, value) {
    const element = document.querySelector(selector);
    if (element) {
      element.textContent = value || '';
    }
  }

  function openUserDetail(row) {
    const user = getUserDataFromRow(row);

    setText('[data-user-detail="name"]', user.name);
    setText('[data-user-detail="username"]', user.username);
    setText('[data-user-detail="email"]', user.email);
    setText('[data-user-detail="role"]', user.role);
    setText('[data-user-detail="status"]', user.status);
    setText('[data-user-detail="createdAt"]', user.createdAt);
    setText('[data-user-detail="updatedAt"]', user.updatedAt || 'Chưa cập nhật');
    setText(
      '[data-user-detail="ownedData"]',
      `${user.packageCount} packages, ${user.applicationCount} apps, ${user.documentCount} tài liệu`
    );

    openModal('userDetailModal');
  }

  function openUserEdit(row) {
    const user = getUserDataFromRow(row);
    const form = document.getElementById('editUserForm');
    if (!form) return;

    form.action = `/users/${encodeURIComponent(user.id)}/edit`;
    form.querySelector('[data-edit-user-field="username"]').value = user.username;
    form.querySelector('[data-edit-user-field="fullName"]').value = user.fullName;
    form.querySelector('[data-edit-user-field="email"]').value = user.email;
    form.querySelector('[data-edit-user-field="role"]').value = user.role;
    form.querySelector('[data-edit-user-field="isActive"]').checked = user.isActive;
    form.querySelector('[data-edit-user-field="newPassword"]').value = '';
    form.querySelector('[data-edit-user-field="confirmPassword"]').value = '';

    openModal('editUserModal');
  }

  function validateProfileForm(form, shouldNotify) {
    const email = form.querySelector('[data-profile-email]');
    const confirmEmail = form.querySelector('[data-profile-confirm-email]');
    const newPassword = form.querySelector('[data-profile-new-password]');
    const confirmPassword = form.querySelector('[data-profile-confirm-password]');
    const emailFeedback = form.querySelector('[data-profile-feedback="email"]');
    const passwordFeedback = form.querySelector('[data-profile-feedback="password"]');

    const emailMismatch = Boolean(email && confirmEmail
      && email.value.trim().toLowerCase() !== confirmEmail.value.trim().toLowerCase());
    const passwordMismatch = Boolean(newPassword && confirmPassword
      && (newPassword.value || confirmPassword.value)
      && newPassword.value !== confirmPassword.value);

    if (confirmEmail) {
      confirmEmail.setCustomValidity(emailMismatch ? 'Confirm email mới chưa khớp.' : '');
      const field = confirmEmail.closest('.form-field');
      if (field) {
        field.classList.toggle('has-error', emailMismatch);
      }
    }

    if (emailFeedback) {
      emailFeedback.textContent = emailMismatch ? 'Confirm email mới chưa khớp.' : '';
      emailFeedback.style.display = emailMismatch ? 'block' : '';
    }

    if (confirmPassword) {
      confirmPassword.setCustomValidity(passwordMismatch ? 'Xác nhận mật khẩu mới chưa khớp.' : '');
      const field = confirmPassword.closest('.form-field');
      if (field) {
        field.classList.toggle('has-error', passwordMismatch);
      }
    }

    if (passwordFeedback) {
      passwordFeedback.textContent = passwordMismatch ? 'Xác nhận mật khẩu mới chưa khớp.' : '';
      passwordFeedback.style.display = passwordMismatch ? 'block' : '';
    }

    if (shouldNotify && emailMismatch) {
      notify('warning', 'Confirm email mới chưa khớp.');
    } else if (shouldNotify && passwordMismatch) {
      notify('warning', 'Xác nhận mật khẩu mới chưa khớp.');
    }

    return !emailMismatch && !passwordMismatch;
  }

  function initProfileForms() {
    document.querySelectorAll('[data-profile-form]').forEach((form) => {
      form.querySelectorAll('input').forEach((input) => {
        input.addEventListener('input', () => validateProfileForm(form, false));
      });

      form.addEventListener('submit', (event) => {
        if (!validateProfileForm(form, true)) {
          event.preventDefault();
        }
      });
    });
  }

  function initEditAppForms() {
    document.querySelectorAll('#editAppForm [data-edit-app-package]').forEach((checkbox) => {
      const form = checkbox.closest('form');
      setEditAppPackageEnabled(form, checkbox);
      checkbox.addEventListener('change', () => setEditAppPackageEnabled(form, checkbox));
    });
  }

  function formatNotificationTime(value) {
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) return '';

    const elapsedSeconds = Math.max(0, Math.floor((Date.now() - date.getTime()) / 1000));
    if (elapsedSeconds < 60) return 'Vừa xong';
    if (elapsedSeconds < 3600) return `${Math.floor(elapsedSeconds / 60)} phút trước`;
    if (elapsedSeconds < 86400) return `${Math.floor(elapsedSeconds / 3600)} giờ trước`;
    if (elapsedSeconds < 604800) return `${Math.floor(elapsedSeconds / 86400)} ngày trước`;

    return new Intl.DateTimeFormat('vi-VN', {
      day: '2-digit',
      month: '2-digit',
      year: 'numeric',
      hour: '2-digit',
      minute: '2-digit'
    }).format(date);
  }

  function getNotificationIcon(notification) {
    if (notification.isSystem) return 'campaign';
    if (notification.severity === 'success') return 'check_circle';
    if (notification.severity === 'warning') return 'warning';
    if (notification.severity === 'error') return 'error';
    if (notification.entityType === 'package') return 'inventory_2';
    if (notification.entityType === 'application') return 'apps';
    return 'notifications';
  }

  async function notificationRequest(url, options = {}) {
    const response = await fetch(url, {
      cache: 'no-store',
      credentials: 'same-origin',
      ...options,
      headers: {
        Accept: 'application/json',
        ...(options.body ? { 'Content-Type': 'application/json' } : {}),
        ...(options.headers || {})
      }
    });
    const data = await response.json().catch(() => ({}));

    if (!response.ok) {
      throw new Error(data.error || 'Không thể xử lý thông báo.');
    }

    return data;
  }

  function initNotificationCenter() {
    const center = document.querySelector('[data-notification-center]');
    if (!center) return;

    const toggle = center.querySelector('[data-notification-toggle]');
    const panel = center.querySelector('[data-notification-panel]');
    const badge = center.querySelector('[data-notification-badge]');
    const summary = center.querySelector('[data-notification-summary]');
    const list = center.querySelector('[data-notification-list]');
    const empty = center.querySelector('[data-notification-empty]');
    const readAllButton = center.querySelector('[data-notification-read-all]');
    const filterButtons = center.querySelectorAll('[data-notification-filter]');
    const knownNotificationIds = new Set();
    let currentFilter = 'all';
    let initialized = false;
    let loading = false;
    let reloadPending = false;

    function setPanelOpen(open) {
      panel.hidden = !open;
      toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
    }

    function setEmptyState(title, message, visible) {
      const titleElement = empty.querySelector('strong');
      const messageElement = empty.querySelector('span:last-child');
      if (titleElement) titleElement.textContent = title;
      if (messageElement) messageElement.textContent = message;
      empty.hidden = !visible;
    }

    function updateUnreadCount(count) {
      const unreadCount = Math.max(0, Number(count) || 0);
      badge.textContent = unreadCount > 99 ? '99+' : String(unreadCount);
      badge.hidden = unreadCount === 0;
      summary.textContent = unreadCount > 0 ? `${unreadCount} thông báo chưa đọc` : 'Không có thông báo chưa đọc';
      readAllButton.disabled = unreadCount === 0;
    }

    function renderNotifications(notifications) {
      list.replaceChildren();
      setEmptyState(
        currentFilter === 'unread' ? 'Không có thông báo chưa đọc' : 'Chưa có thông báo',
        'Các cập nhật quan trọng sẽ xuất hiện tại đây.',
        notifications.length === 0
      );

      notifications.forEach((notification) => {
        const item = document.createElement('button');
        item.type = 'button';
        item.className = `notification-item tone-${notification.severity || 'info'}${notification.isRead ? '' : ' unread'}`;
        item.dataset.notificationId = notification.id;

        const icon = document.createElement('span');
        icon.className = 'notification-item-icon';
        const iconGlyph = document.createElement('span');
        applyFluentIcon(iconGlyph, getNotificationIcon(notification));
        icon.appendChild(iconGlyph);

        const copy = document.createElement('span');
        copy.className = 'notification-item-copy';
        const title = document.createElement('strong');
        title.textContent = notification.title;
        const message = document.createElement('span');
        message.textContent = notification.message;
        const time = document.createElement('time');
        time.dateTime = notification.createdAt || '';
        time.textContent = formatNotificationTime(notification.createdAt);
        copy.append(title, message, time);

        const unreadDot = document.createElement('span');
        unreadDot.className = 'notification-unread-dot';
        unreadDot.setAttribute('aria-label', notification.isRead ? 'Đã đọc' : 'Chưa đọc');

        item.append(icon, copy, unreadDot);
        item.addEventListener('click', async () => {
          try {
            if (!notification.isRead) {
              await notificationRequest(`/api/notifications/${encodeURIComponent(notification.id)}/read`, {
                method: 'POST'
              });
              notification.isRead = true;
              item.classList.remove('unread');
              await loadNotifications(false);
            }
          } catch (error) {
            notify('warning', error.message);
          }

          if (
            notification.actionUrl
            && notification.actionUrl.startsWith('/')
            && !notification.actionUrl.startsWith('//')
          ) {
            window.location.assign(notification.actionUrl);
          }
        });

        list.appendChild(item);
      });
    }

    async function loadNotifications(announceNew = true) {
      if (loading) {
        reloadPending = true;
        return;
      }
      loading = true;

      try {
        const data = await notificationRequest(
          `/api/notifications?limit=20&unreadOnly=${currentFilter === 'unread' ? 'true' : 'false'}`
        );

        if (!data.available) {
          badge.hidden = true;
          summary.textContent = 'Chưa kích hoạt trong database';
          readAllButton.disabled = true;
          list.replaceChildren();
          setEmptyState(
            'Thông báo chưa khả dụng',
            'Admin cần chạy migration 04_notifications.sql.',
            true
          );
          return;
        }

        const notifications = Array.isArray(data.notifications) ? data.notifications : [];
        if (initialized && announceNew) {
          const importantNotification = notifications.find((notification) => (
            !knownNotificationIds.has(notification.id)
            && !notification.isRead
            && ['warning', 'error'].includes(notification.severity)
          ));

          if (importantNotification) {
            notify(
              importantNotification.severity === 'error' ? 'failure' : 'warning',
              importantNotification.title
            );
          }
        }

        notifications.forEach((notification) => knownNotificationIds.add(notification.id));
        initialized = true;
        updateUnreadCount(data.unreadCount);
        renderNotifications(notifications);
      } catch (error) {
        summary.textContent = 'Không thể tải thông báo';
        setEmptyState('Không thể tải thông báo', 'Vui lòng thử lại sau.', true);
      } finally {
        loading = false;
        if (reloadPending) {
          reloadPending = false;
          loadNotifications(false);
        }
      }
    }

    async function refreshUnreadCount() {
      try {
        const data = await notificationRequest('/api/notifications?countOnly=true');
        if (!data.available) {
          badge.hidden = true;
          summary.textContent = 'Chưa kích hoạt trong database';
          readAllButton.disabled = true;
          return;
        }

        updateUnreadCount(data.unreadCount);
      } catch (error) {
        console.info('Cannot refresh notification count:', error);
      }
    }

    toggle.addEventListener('click', () => {
      const open = panel.hidden;
      setPanelOpen(open);
      if (open) loadNotifications(false);
    });

    readAllButton.addEventListener('click', async () => {
      readAllButton.disabled = true;
      try {
        await notificationRequest('/api/notifications/read-all', { method: 'POST' });
        await loadNotifications(false);
      } catch (error) {
        notify('failure', error.message);
      }
    });

    filterButtons.forEach((button) => {
      button.addEventListener('click', () => {
        currentFilter = button.dataset.notificationFilter;
        filterButtons.forEach((candidate) => {
          const active = candidate === button;
          candidate.classList.toggle('active', active);
          candidate.setAttribute('aria-selected', active ? 'true' : 'false');
        });
        loadNotifications(false);
      });
    });

    document.addEventListener('click', (event) => {
      if (!panel.hidden && !center.contains(event.target)) {
        setPanelOpen(false);
      }
    });

    document.addEventListener('keydown', (event) => {
      if (event.key === 'Escape' && !panel.hidden) {
        setPanelOpen(false);
        toggle.focus();
      }
    });

    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') {
        if (panel.hidden) refreshUnreadCount();
        else loadNotifications(true);
      }
    });

    document.addEventListener('notifications:refresh', () => {
      if (panel.hidden) refreshUnreadCount();
      else loadNotifications(false);
    });

    const broadcastButton = center.querySelector('[data-modal-open="systemNotificationModal"]');
    if (broadcastButton) {
      broadcastButton.addEventListener('click', () => setPanelOpen(false));
    }

    window.setInterval(() => {
      if (document.visibilityState !== 'visible') return;
      if (panel.hidden) refreshUnreadCount();
      else loadNotifications(true);
    }, 30000);

    refreshUnreadCount();
  }

  function initSystemNotificationForm() {
    const form = document.querySelector('[data-system-notification-form]');
    if (!form) return;

    form.addEventListener('submit', (event) => {
      event.preventDefault();
      if (!form.reportValidity()) return;

      confirmAction('Gửi thông báo này tới tất cả tài khoản đang hoạt động?', async () => {
        const submitButton = form.querySelector('[data-system-notification-submit]');
        const formData = new FormData(form);
        submitButton.disabled = true;

        try {
          const result = await notificationRequest('/api/notifications/broadcasts', {
            method: 'POST',
            body: JSON.stringify({
              title: formData.get('title'),
              severity: formData.get('severity'),
              message: formData.get('message'),
              actionUrl: formData.get('actionUrl')
            })
          });

          closeModal(form.closest('.modal-backdrop'));
          form.reset();
          notify('success', `Đã gửi thông báo tới ${result.recipientCount || 0} người dùng.`);
          document.dispatchEvent(new CustomEvent('notifications:refresh'));
        } catch (error) {
          notify('failure', error.message);
        } finally {
          submitButton.disabled = false;
        }
      });
    });
  }

  hydrateFluentIcons(document);
  initNotiflix();
  initFileDropzones();
  initRegistrationUniqueChecks();
  initProfileForms();
  initEditAppForms();
  initNotificationCenter();
  initSystemNotificationForm();

  if (body.dataset.notice) {
    notify(body.dataset.noticeType || 'info', body.dataset.notice);
    const url = new URL(window.location.href);
    if (url.searchParams.has('notice') || url.searchParams.has('noticeType')) {
      url.searchParams.delete('notice');
      url.searchParams.delete('noticeType');
      window.history.replaceState({}, document.title, `${url.pathname}${url.search}${url.hash}`);
    }
    delete body.dataset.notice;
    delete body.dataset.noticeType;
  }

  if (menuButton) {
    menuButton.addEventListener('click', () => {
      setMobileNav(!body.classList.contains('mobile-nav-open'));
    });
  }

  if (sidebarBackdrop) {
    sidebarBackdrop.addEventListener('click', () => setMobileNav(false));
  }

  document.querySelectorAll('[data-table-search]').forEach((input) => {
    input.addEventListener('input', () => applyTableFilters(input.dataset.tableSearch));
  });

  document.querySelectorAll('[data-filter-select]').forEach((select) => {
    select.addEventListener('change', () => applyTableFilters(select.dataset.filterTable));
  });

  document.addEventListener('click', (event) => {
    const appEditButton = event.target.closest('[data-app-edit]');
    if (appEditButton) {
      openAppEdit(appEditButton);
      return;
    }

    const packageUpdateButton = event.target.closest('[data-package-update]');
    if (packageUpdateButton) {
      openPackageUpdate(packageUpdateButton.dataset.packageUpdate);
      return;
    }

    const refreshButton = event.target.closest('[data-refresh-page]');
    if (refreshButton) {
      window.location.reload();
      return;
    }

    const userViewButton = event.target.closest('[data-user-view]');
    if (userViewButton) {
      const row = userViewButton.closest('tr');
      if (row) {
        openUserDetail(row);
      }
      return;
    }

    const userEditButton = event.target.closest('[data-user-edit]');
    if (userEditButton) {
      const row = userEditButton.closest('tr');
      if (row) {
        openUserEdit(row);
      }
      return;
    }

    const modalOpenButton = event.target.closest('[data-modal-open]');
    if (modalOpenButton) {
      openModal(modalOpenButton.dataset.modalOpen);
      return;
    }

    const modalCloseButton = event.target.closest('[data-modal-close]');
    if (modalCloseButton) {
      closeModal(modalCloseButton.closest('.modal-backdrop'));
    }

    const modalBackdrop = event.target.classList.contains('modal-backdrop') ? event.target : null;
    if (modalBackdrop) {
      closeModal(modalBackdrop);
    }

    const toastButton = event.target.closest('[data-toast]');
    if (toastButton) {
      notify(toastButton.dataset.toastType || 'info', toastButton.dataset.toast);
    }

    const confirmButton = event.target.closest('[data-confirm]');
    if (confirmButton) {
      confirmAction(confirmButton.dataset.confirm);
    }
  });

  document.addEventListener('submit', (event) => {
    const form = event.target.closest('form[data-confirm-submit]');
    if (!form || form.dataset.confirmed === 'true') return;

    event.preventDefault();
    confirmAction(form.dataset.confirmSubmit, () => {
      form.dataset.confirmed = 'true';
      form.submit();
    });
  });

  document.addEventListener('keydown', (event) => {
    if (event.key !== 'Escape') return;

    const openModalNode = document.querySelector('.modal-backdrop.open');
    if (openModalNode) {
      closeModal(openModalNode);
      return;
    }

    setMobileNav(false);
  });
})();
