/**
 * Sidebar bookmarks panel actions:
 * - Reorder root navigation (groups + ungrouped bookmarks) via up/down
 * - Reorder bookmarks inside groups (up/down)
 * - Edit/Delete groups and bookmarks with confirm dialog
 */
import { showAsyncFlash } from '/js/components/app-async-flash.js';
import { warnOnce, resolveHost } from '/js/core/app-dom.js';
import { confirmDialog } from '/js/core/app-confirm-dialog.js';
import { postForm } from '/js/core/app-http.js';

export function initBookmarkPanel(root = document, options = {}) {
  const host = resolveHost(root);
  const panelSelector = String(options.selector || '[data-aside-panel="bookmarks"]').trim() || '[data-aside-panel="bookmarks"]';
  const panel = host.matches?.(panelSelector) ? host : host.querySelector(panelSelector);
  if (!(panel instanceof HTMLElement)) {
    return { destroy: () => {} };
  }
  if (panel.dataset.bookmarkPanelBound === '1' && panel._bookmarkPanelApi) {
    return panel._bookmarkPanelApi;
  }

  const reorderUrl = String(panel.dataset.bookmarkReorderUrl || '').trim();
  const groupDeleteUrl = String(panel.dataset.bookmarkGroupDeleteUrl || '').trim();
  const bookmarkDeleteUrl = String(panel.dataset.bookmarkDeleteUrl || '').trim();
  if (!reorderUrl || !groupDeleteUrl || !bookmarkDeleteUrl) {
    warnOnce('UI_DATA_MISSING', 'Missing bookmark panel endpoint metadata', { module: 'bookmark-panel' });
    return { destroy: () => {} };
  }

  const documentRoot = document.documentElement;
  const csrfKey = String(documentRoot.dataset.csrfKey || '').trim();
  const csrfToken = String(documentRoot.dataset.csrfToken || '').trim();
  if (!csrfKey || !csrfToken) {
    warnOnce('UI_DATA_MISSING', 'Missing CSRF metadata for bookmark panel', { module: 'bookmark-panel' });
    return { destroy: () => {} };
  }
  const abortController = new AbortController();
  const { signal } = abortController;
  const timerIds = [];

  const messageDeleteConfirm = panel.dataset.bookmarkMsgGroupDeleteConfirm || 'Delete group and keep bookmarks?';
  const messageGroupDeleted = panel.dataset.bookmarkMsgGroupDeleted || 'Group deleted';
  const messageGroupDeleteFailed = panel.dataset.bookmarkMsgGroupDeleteFailed || 'Group delete failed';
  const messageBookmarkDeleteConfirm = panel.dataset.bookmarkMsgBookmarkDeleteConfirm || 'Delete this bookmark?';
  const messageBookmarkDeleted = panel.dataset.bookmarkMsgBookmarkDeleted || 'Bookmark deleted';
  const messageBookmarkDeleteFailed = panel.dataset.bookmarkMsgBookmarkDeleteFailed || 'Bookmark action failed';
  const messageGroupActionFailed = panel.dataset.bookmarkMsgGroupActionFailed || messageGroupDeleteFailed;
  const messageBookmarkActionFailed = panel.dataset.bookmarkMsgBookmarkActionFailed || messageBookmarkDeleteFailed;
  const messageReorderFailed = panel.dataset.bookmarkMsgReorderFailed || 'Reorder failed';
  const labelDelete = panel.dataset.bookmarkLabelDelete || 'Delete';

  const moduleContext = { module: 'bookmark-panel' };

  panel.querySelectorAll('[data-bookmark-item-action], [data-bookmark-group-action]').forEach((button) => {
    if (!(button instanceof HTMLButtonElement)) {
      return;
    }
    button.dataset.baseDisabled = button.disabled ? '1' : '0';
  });

  let pending = false;

  const actionMenus = () => Array.from(panel.querySelectorAll('[data-bookmark-action-menu]'))
    .filter((menu) => menu instanceof HTMLDetailsElement);

  const closeActionMenus = (except = null) => {
    actionMenus().forEach((menu) => {
      if (menu === except) {
        return;
      }
      menu.open = false;
    });
  };

  const panelActionButtons = () => Array.from(
    panel.querySelectorAll('[data-bookmark-item-action], [data-bookmark-group-action]')
  ).filter((button) => button instanceof HTMLButtonElement);

  const setPending = (nextPending) => {
    pending = nextPending;
    panelActionButtons().forEach((button) => {
      const baselineDisabled = button.dataset.baseDisabled === '1';
      button.disabled = nextPending || baselineDisabled;
    });
  };

  const reportError = (code, message, details = {}) => {
    warnOnce(code, message, { ...moduleContext, ...details });
    showAsyncFlash('error', message);
  };

  const runReload = (successMessage = '') => {
    if (String(successMessage).trim() !== '') {
      showAsyncFlash('success', successMessage, 2500);
    }
    const timerId = window.setTimeout(() => window.location.reload(), 450);
    timerIds.push(timerId);
  };

  const directChildren = (container, className) => {
    if (!(container instanceof HTMLElement)) {
      return [];
    }
    return Array.from(container.children).filter(
      (child) => child instanceof HTMLElement && child.classList.contains(className)
    );
  };

  const swapInList = (items, currentItem, direction) => {
    const currentIndex = items.indexOf(currentItem);
    if (currentIndex < 0) {
      return [];
    }
    const nextIndex = direction === 'up' ? currentIndex - 1 : currentIndex + 1;
    if (nextIndex < 0 || nextIndex >= items.length) {
      return [];
    }
    const reordered = items.slice();
    const temp = reordered[currentIndex];
    reordered[currentIndex] = reordered[nextIndex];
    reordered[nextIndex] = temp;
    return reordered;
  };

  const buildPairs = (items, dataKey) => {
    const pairs = [];
    for (let index = 0; index < items.length; index += 1) {
      const item = items[index];
      const id = Number.parseInt(item.dataset[dataKey] || '', 10);
      if (id <= 0) {
        return [];
      }
      pairs.push({
        id,
        sort_order: index + 1
      });
    }
    return pairs;
  };

  const buildRootPairs = (items) => {
    const pairs = [];
    for (let index = 0; index < items.length; index += 1) {
      const item = items[index];
      const kind = String(item.dataset.bookmarkRootKind || '').trim();
      const id = Number.parseInt(item.dataset.bookmarkRootId || '', 10);
      if ((kind !== 'group' && kind !== 'bookmark') || id <= 0) {
        return [];
      }
      pairs.push({
        kind,
        id,
        sort_order: index + 1
      });
    }
    return pairs;
  };

  const submitReorder = async (type, pairs) => {
    if (pairs.length === 0) {
      return;
    }

    const body = new FormData();
    body.set(csrfKey, csrfToken);
    body.set('type', type);
    body.set('items', JSON.stringify(pairs));

    setPending(true);
    try {
      const json = await postForm(reorderUrl, body);
      if (!json.ok) {
        reportError('FETCH_FAILED', messageReorderFailed, { error: json.error, type });
        return;
      }

      runReload();
    } catch (error) {
      reportError('FETCH_ERROR', messageReorderFailed, { error, status: error?.status, type });
    } finally {
      setPending(false);
    }
  };

  const reorderGroup = async (button) => {
    const groupItem = button.closest('.app-sidebar-bookmark-root-item.app-sidebar-bookmark-group');
    if (!(groupItem instanceof HTMLElement)) {
      return;
    }
    const container = groupItem.parentElement;
    const rootItems = directChildren(container, 'app-sidebar-bookmark-root-item');
    if (rootItems.length < 2) {
      return;
    }

    const action = String(button.dataset.bookmarkGroupAction || '').trim();
    const direction = action === 'move-up' ? 'up' : action === 'move-down' ? 'down' : '';
    if (!direction) {
      return;
    }

    const reorderedRootItems = swapInList(rootItems, groupItem, direction);
    if (reorderedRootItems.length === 0) {
      return;
    }

    const pairs = buildRootPairs(reorderedRootItems);
    if (pairs.length !== reorderedRootItems.length) {
      reportError('UI_INVALID_STATE', messageReorderFailed, { action, target: 'root' });
      return;
    }

    await submitReorder('root', pairs);
  };

  const reorderBookmark = async (button) => {
    const bookmarkItem = button.closest('.app-sidebar-bookmark-item');
    if (!(bookmarkItem instanceof HTMLElement)) {
      return;
    }

    const action = String(button.dataset.bookmarkItemAction || '').trim();
    const direction = action === 'move-up' ? 'up' : action === 'move-down' ? 'down' : '';
    if (!direction) {
      return;
    }

    const scope = String(button.dataset.bookmarkItemActionScope || '').trim();
    if (scope === 'root') {
      const rootItem = bookmarkItem.closest('.app-sidebar-bookmark-root-item');
      if (!(rootItem instanceof HTMLElement)) {
        return;
      }
      const container = rootItem.parentElement;
      const rootItems = directChildren(container, 'app-sidebar-bookmark-root-item');
      if (rootItems.length < 2) {
        return;
      }

      const reorderedRootItems = swapInList(rootItems, rootItem, direction);
      if (reorderedRootItems.length === 0) {
        return;
      }

      const rootPairs = buildRootPairs(reorderedRootItems);
      if (rootPairs.length !== reorderedRootItems.length) {
        reportError('UI_INVALID_STATE', messageReorderFailed, { action, target: 'root' });
        return;
      }

      await submitReorder('root', rootPairs);
      return;
    }

    const container = bookmarkItem.parentElement;
    const bookmarks = directChildren(container, 'app-sidebar-bookmark-item');
    if (bookmarks.length < 2) {
      return;
    }

    const reorderedBookmarks = swapInList(bookmarks, bookmarkItem, direction);
    if (reorderedBookmarks.length === 0) {
      return;
    }

    const pairs = buildPairs(reorderedBookmarks, 'bookmarkId');
    if (pairs.length !== reorderedBookmarks.length) {
      reportError('UI_INVALID_STATE', messageReorderFailed, { action, target: 'bookmarks' });
      return;
    }

    await submitReorder('bookmarks', pairs);
  };

  const deleteGroup = async (button) => {
    const groupItem = button.closest('.app-sidebar-bookmark-group');
    if (!(groupItem instanceof HTMLElement)) {
      return;
    }
    const groupId = Number.parseInt(groupItem.dataset.bookmarkGroupId || '', 10);
    if (groupId <= 0) {
      reportError('UI_INVALID_STATE', messageGroupDeleteFailed, { reason: 'invalid_group_id' });
      return;
    }

    const approved = await confirmDialog.confirm({
      message: messageDeleteConfirm,
      confirmLabel: labelDelete,
      actionKind: 'delete',
      variant: 'danger',
      focus: 'cancel'
    });
    if (!approved) {
      return;
    }

    const body = new FormData();
    body.set(csrfKey, csrfToken);
    body.set('id', String(groupId));

    setPending(true);
    try {
      const json = await postForm(groupDeleteUrl, body);
      if (!json.ok) {
        reportError('FETCH_FAILED', messageGroupDeleteFailed, { error: json.error, groupId });
        return;
      }

      runReload(messageGroupDeleted);
    } catch (error) {
      reportError('FETCH_ERROR', messageGroupDeleteFailed, { error, status: error?.status, groupId });
    } finally {
      setPending(false);
    }
  };

  const deleteBookmark = async (button) => {
    const bookmarkItem = button.closest('.app-sidebar-bookmark-item');
    if (!(bookmarkItem instanceof HTMLElement)) {
      return;
    }
    const bookmarkId = Number.parseInt(bookmarkItem.dataset.bookmarkId || '', 10);
    if (bookmarkId <= 0) {
      reportError('UI_INVALID_STATE', messageBookmarkDeleteFailed, { reason: 'invalid_bookmark_id' });
      return;
    }

    const approved = await confirmDialog.confirm({
      message: messageBookmarkDeleteConfirm,
      confirmLabel: labelDelete,
      actionKind: 'delete',
      variant: 'danger',
      focus: 'cancel'
    });
    if (!approved) {
      return;
    }

    const body = new FormData();
    body.set(csrfKey, csrfToken);
    body.set('id', String(bookmarkId));

    setPending(true);
    try {
      const json = await postForm(bookmarkDeleteUrl, body);
      if (!json.ok) {
        reportError('FETCH_FAILED', messageBookmarkDeleteFailed, { error: json.error, bookmarkId });
        return;
      }

      runReload(messageBookmarkDeleted);
    } catch (error) {
      reportError('FETCH_ERROR', messageBookmarkDeleteFailed, { error, status: error?.status, bookmarkId });
    } finally {
      setPending(false);
    }
  };

  const editGroup = (button) => {
    const groupItem = button.closest('.app-sidebar-bookmark-group');
    if (!(groupItem instanceof HTMLElement)) {
      return;
    }
    const groupId = Number.parseInt(groupItem.dataset.bookmarkGroupId || '', 10);
    const groupName = String(groupItem.dataset.bookmarkGroupName || '').trim();
    const groupIcon = String(groupItem.dataset.bookmarkGroupIcon || 'bi-folder').trim() || 'bi-folder';
    if (groupId <= 0 || !groupName) {
      reportError('UI_INVALID_STATE', messageGroupActionFailed, { reason: 'invalid_group_payload' });
      return;
    }

    document.dispatchEvent(new CustomEvent('app:bookmark-group-edit', {
      detail: {
        id: groupId,
        name: groupName,
        icon: groupIcon
      }
    }));
  };

  const editBookmark = (button) => {
    const bookmarkItem = button.closest('.app-sidebar-bookmark-item');
    if (!(bookmarkItem instanceof HTMLElement)) {
      return;
    }

    const bookmarkId = Number.parseInt(bookmarkItem.dataset.bookmarkId || '', 10);
    const bookmarkName = String(bookmarkItem.dataset.bookmarkName || '').trim();
    const groupId = Number.parseInt(bookmarkItem.dataset.bookmarkGroupId || '', 10);
    if (bookmarkId <= 0 || !bookmarkName) {
      reportError('UI_INVALID_STATE', messageBookmarkActionFailed, { reason: 'invalid_bookmark_payload' });
      return;
    }

    document.dispatchEvent(new CustomEvent('app:bookmark-edit', {
      detail: {
        id: bookmarkId,
        name: bookmarkName,
        groupId: groupId > 0 ? String(groupId) : ''
      }
    }));
  };

  panel.addEventListener('click', (event) => {
    const target = event.target instanceof HTMLElement ? event.target : null;
    if (!target) {
      return;
    }

    const menuSummary = target.closest('[data-bookmark-action-menu] > summary');
    if (menuSummary instanceof HTMLElement) {
      if (pending) {
        event.preventDefault();
        event.stopPropagation();
        return;
      }
      const menu = menuSummary.parentElement;
      if (menu instanceof HTMLDetailsElement) {
        event.preventDefault();
        event.stopPropagation();
        const shouldOpen = !menu.open;
        closeActionMenus(menu);
        menu.open = shouldOpen;
      }
      return;
    }

    if (pending) {
      return;
    }

    const groupActionButton = target.closest('[data-bookmark-group-action]');
    if (groupActionButton instanceof HTMLButtonElement) {
      event.preventDefault();
      event.stopPropagation();
      closeActionMenus();

      const action = String(groupActionButton.dataset.bookmarkGroupAction || '').trim();
      if (action === 'edit') {
        editGroup(groupActionButton);
        return;
      }
      if (action === 'delete') {
        void deleteGroup(groupActionButton);
        return;
      }
      if (action === 'move-up' || action === 'move-down') {
        void reorderGroup(groupActionButton);
      }
      return;
    }

    const itemActionButton = target.closest('[data-bookmark-item-action]');
    if (itemActionButton instanceof HTMLButtonElement) {
      event.preventDefault();
      event.stopPropagation();
      closeActionMenus();
      const action = String(itemActionButton.dataset.bookmarkItemAction || '').trim();
      if (action === 'edit') {
        editBookmark(itemActionButton);
        return;
      }
      if (action === 'delete') {
        void deleteBookmark(itemActionButton);
        return;
      }
      if (action === 'move-up' || action === 'move-down') {
        void reorderBookmark(itemActionButton);
      }
    }
  }, { signal });

  document.addEventListener('click', (event) => {
    if (!(event.target instanceof Node)) {
      return;
    }
    const clickedInsideMenu = actionMenus().some((menu) => menu.contains(event.target));
    if (!clickedInsideMenu) {
      closeActionMenus();
    }
  }, { signal });

  const destroy = () => {
    abortController.abort();
    timerIds.forEach((timerId) => window.clearTimeout(timerId));
    timerIds.length = 0;
    delete panel.dataset.bookmarkPanelBound;
    delete panel._bookmarkPanelApi;
  };
  const api = { destroy };
  panel.dataset.bookmarkPanelBound = '1';
  panel._bookmarkPanelApi = api;
  return api;
}
