import { NileGrid } from './nile-grid';
import { applyAfterResize } from './nile-grid.resize'

/** listenToEventListeners
 * @param nileGrid Grid element to attach listeners on
 * @param onResize Handler for 'nile-column-resize'
 * @param slotEl Slot element to watch for 'slotchange'
 * @param _attachObserverAndLayout Callback to reattach observer + layout
 * @returns void
 */
export const listenToEventListeners = (
  nileGrid: NileGrid,
  onResize: any,
  slotEl: any,
  _attachObserverAndLayout: any
) => {
  nileGrid.addEventListener('nile-column-resize', onResize);
  nileGrid.addEventListener('nile-resize-start', (e) => {
    e.stopPropagation();
    nileGrid.resizeBaseColumnWidths = [...nileGrid.columnWidths];
    nileGrid.resizeStart.style.display = 'block';
  });
  nileGrid.addEventListener('nile-resize-end', (e: CustomEvent) => {
    e.stopPropagation();
    applyAfterResize(nileGrid, (e as CustomEvent).detail!.col);
    nileGrid.resizeBaseColumnWidths = [];
    nileGrid.resizeStart.style.display = 'none';
    nileGrid.resizeEnd.style.display = 'none';
  });
  slotEl.addEventListener('slotchange', () => _attachObserverAndLayout());
  nileGrid.addEventListener('scroll', () => scrollEventHandler(nileGrid));
};

/** removeEventListeners
 * @param nileGrid Grid element to detach listeners from
 * @param onResize Handler previously attached to 'nile-column-resize'
 * @param slotEl Slot element to remove 'slotchange' from
 * @param _attachObserverAndLayout Callback reference used during attach
 * @returns void
 */
export const removeEventListeners = (
  nileGrid: NileGrid,
  onResize: any,
  slotEl: any,
  _attachObserverAndLayout: any
) => {
  nileGrid.removeEventListener('nile-column-resize', onResize);
  nileGrid.removeEventListener('nile-resize-start', () => {
    nileGrid.resizeStart.style.display = 'block';
  });
  nileGrid.removeEventListener('nile-resize-end', () => {
    nileGrid.resizeStart.style.display = 'none';
    nileGrid.resizeEnd.style.display = 'none';
  });
  slotEl.removeEventListener('slotchange', () => _attachObserverAndLayout());
  nileGrid.removeEventListener('scroll', () => scrollEventHandler(nileGrid));
};

/** getHead
 * @param slotEl Slot element containing assigned nodes
 * @returns <nile-grid-head> element or null
 */
export const getHead = (slotEl: any) => {
  const nodes = slotEl?.assignedElements() ?? [];
  return (
    (nodes.find(
      (n: any) => n.tagName.toLowerCase() === 'nile-grid-head'
    ) as HTMLElement) || null
  );
};

/** getBody
 * @param slotEl Slot element containing assigned nodes
 * @returns <nile-grid-body> element or null
 */
export const getBody = (slotEl: any) => {
  const nodes = slotEl?.assignedElements() ?? [];
  return (
    (nodes.find(
      (n: any) => n.tagName.toLowerCase() === 'nile-grid-body'
    ) as HTMLElement) || null
  );
};

export const scrollEventHandler = (el: NileGrid) => {
  const maxY = Math.max(1, el.scrollHeight - el.clientHeight);
  const maxX = Math.max(1, el.scrollWidth - el.clientWidth);

  const percentageY = Math.round((el.scrollTop / maxY) * 100);
  const percentageX = Math.round((el.scrollLeft / maxX) * 100);

  el.emit('nile-scroll', {
    bubbles: true,
    composed: true,
    detail: {
      horizontalScroll: percentageX,
      verticalScroll: percentageY,
      left: el.scrollLeft,
      top: el.scrollTop
    }
  });
};

/** copyArrayValuesInPlace
 * @param target Target array
 * @param source Source array
 * @returns void
 */
export function copyArrayValuesInPlace(
  target: number[],
  source: number[]
) {
  const count = Math.min(target.length, source.length);
  for (let i = 0; i < count; i++) {
    target[i] = source[i];
  }
}