import remoteInvocationRegistry from '../../../../../helpers/remote-invocation/remote-invocation-registry';
import domNodeSubjectFactory from '../../../../../helpers/change-manager/subject/dom-node-subject/dom-node-subject-factory';
import { VegaInternalPopoverUpdateTarget } from '../../../../../helpers/event-manager/event-id/vega-internal-event-id';
import { TableSettingType, } from '../setting-event-handlers/setting-event-handler.abstract';
import { RowOperationEventHandler } from '../setting-event-handlers/row-operation';
import { CaptionOperationEventHandler } from '../setting-event-handlers/caption-operation';
import { ColumnOperationEventHandler } from '../setting-event-handlers/column-operation';
import { DomNodeSubjectObserverFactory } from '../../../../../helpers/change-manager/subject/dom-node-subject/dom-node-subject-observer-factory';
import { VegaPopoverHide, VegaPopoverShow, } from '../../../../../helpers/event-manager/event-id/vega-event-id';
import { MergeCellsOperationEventHandler } from '../setting-event-handlers/merge-cells-operation';
import { SplitCellOperationEventHandler } from '../setting-event-handlers/split-cell-operation';
import { TablePopoverBaseRenderer } from './table-popover-base-renderer';
/**
 * Centralizes the popover rendering and interaction logic for table settings.
 */
export class TableSettingPopoverRenderer extends TablePopoverBaseRenderer {
  constructor() {
    super(...arguments);
    this.settingHandlers = [
      new RowOperationEventHandler(),
      new CaptionOperationEventHandler(),
      new ColumnOperationEventHandler(),
      new MergeCellsOperationEventHandler(),
      new SplitCellOperationEventHandler(),
    ];
    /**
     * Show table setting popover when table is clicked.
     * Only the popover belonging to the nearest table will be shown,
     * which avoids outer tables showing their popover when an inner (nested) table is clicked.
     *
     * @param {MouseEvent} event - The MouseEvent that triggered the table action
     * @param {HTMLElement} trigger - The element that can triggered the popover open.
     */
    this.handleTableClick = (event, trigger) => {
      const target = event.target;
      const ownTrigger = target.closest('table');
      if (trigger !== ownTrigger) {
        void this.popoverRef.hide();
        void this.tableDynamicPopover.hide();
        return;
      }
      void this.tableDynamicPopover.hide();
      if (!this.popoverShow) {
        remoteInvocationRegistry.call(domNodeSubjectFactory.getSubject(this.popoverRef, VegaInternalPopoverUpdateTarget), ownTrigger);
        void this.popoverRef.show();
      }
    };
    /**
     * Sync the selected cells from the table selection to the table setting component.
     */
    this.syncSelectedCells = () => {
      if (this.tableSettingRef) {
        const selectedCells = this.getTableSelectedCells();
        this.tableSettingRef.selectedCells = selectedCells;
      }
    };
    /**
     * Receive setting menu click events.
     *
     * @param {CustomEvent<Array<string>>} event - The custom event emitted from the setting menu.
     */
    this.handleSettingMenuClick = (event) => {
      const handler = this.settingHandlers.find((handler) => handler.canHandle(event.detail));
      if (handler) {
        const extensionContext = this.getTableExtensionContext();
        extensionContext && handler.execute(event.detail, extensionContext, this.tableData);
        if (event.detail[0] === TableSettingType.CAPTION) {
          this.updateTableSettingCaption();
        }
      }
      if (event.detail[0] === TableSettingType.TABLE || event.detail[0] === TableSettingType.CELL) {
        void this.popoverRef.hide();
        void this.tableDynamicPopover.show(event.detail[0]);
      }
    };
    /**
     * Handles the popover show event to sync the selected table cells to the table setting component.
     */
    this.handleTableSettingPopoverShow = () => {
      this.syncSelectedCells();
      this.popoverShow = true;
    };
  }
  /**
   * Render the popover host and inject the table-setting component with refs wired up.
   *
   * @param {VegaRTECreateElementFunction} h - The create element function.
   * @param {RTETableBlock} renderData - The table block to render.
   * @param {() => HTMLElement} getTableRef - Current table DOM reference
   * @param {TableDynamicPopoverRenderer} tableDynamicPopover - Renderer used to show
   *  the secondary table popover (for example, table-properties-specific settings).
   * @returns {VegaRTERenderResult} The rendered popover structure.
   */
  render(h, renderData, getTableRef, tableDynamicPopover) {
    this.tableData = renderData;
    this.tableDynamicPopover = tableDynamicPopover;
    return h('vega-popover', {
      trigger: 'click',
      isScreenPosition: true,
      class: 'rte-table-setting-popover',
      // eslint-disable-next-line jsdoc/require-jsdoc
      ref: (popover) => {
        this.popoverRef = popover;
        if (this.popoverRef) {
          DomNodeSubjectObserverFactory.addUniqueObserverToNode(popover, VegaPopoverShow, this.handleTableSettingPopoverShow);
          DomNodeSubjectObserverFactory.addUniqueObserverToNode(popover, VegaPopoverHide, () => (this.popoverShow = false));
        }
      },
    }, [
      h('div', { slot: 'popover' }, [
        h('vega-rich-text-table-setting', {
          // eslint-disable-next-line jsdoc/require-jsdoc
          ref: (ref) => {
            this.tableSettingRef = ref;
            if (ref) {
              ref.target = getTableRef();
            }
          },
          selectedCells: this.getTableSelectedCells(),
          onVegaClick: this.handleSettingMenuClick,
        }),
      ]),
    ]);
  }
  /**
   * Updates the table setting component caption state to match the given table data.
   */
  updateTableSettingCaption() {
    const hasCaption = this.tableData.hasCaption();
    if (this.tableSettingRef && this.tableSettingRef.hasCaption !== hasCaption) {
      this.tableSettingRef.hasCaption = hasCaption;
    }
  }
  /**
   * Collects and returns the currently selected table cells.
   *
   * @returns {RTETableCellBlock[]} The array of currently selected table cell blocks.
   */
  getTableSelectedCells() {
    let selectedCells = [];
    const extensionContext = this.getTableExtensionContext();
    if (extensionContext && extensionContext.tableSelection) {
      const { tableSelection } = extensionContext;
      selectedCells = tableSelection.getSelectedCells();
    }
    return selectedCells;
  }
}
