import { AfterContentInit, ChangeDetectionStrategy, Component, computed, ContentChildren, input, output, QueryList, ViewChild } from '@angular/core';
import { FAST_KENDO_COMMON } from '../../app.config';
import { CellClickEvent, ColumnBase, DataStateChangeEvent, FilterableSettings, GridComponent, GridDataResult, PagerSettings, SelectableSettings, SortSettings } from '@progress/kendo-angular-grid';
import { CompositeFilterDescriptor, SortDescriptor } from '@progress/kendo-data-query';
import { FastTipDirective } from '../elements/fast-tip.directive';
import * as util from '../utils/util';

const resolvedPromise = Promise.resolve(null); //fancy setTimeout

@Component({
  selector: 'fast-grid',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [FAST_KENDO_COMMON, FastTipDirective],
  template: `
  <ng-template #tooltipGridTemplate>
    @for(text of tooltipItem.split(' • '); track $index) {
      <div><span>{{ text }}</span></div>
    }
  </ng-template>

  @if (gridBinding() !== undefined) {
    <kendo-grid fast-tip #testTooltip="fast-tip" tipEvent="none" [tipContent]="tooltipGridTemplate"
      [kendoGridBinding]="gridBinding()"
      #gridDirective="kendoGrid"
      [data]="data()"
      [filterable]="filterable()"
      [selectable]="selectable()"
      [sortable]="sortable()"
      [selectedKeys]="selectedKeys()"
      [kendoGridSelectBy]="selectBy()"
      [loading]="loading()"
      [class]="conditionalClasses()"
      [pageable]="pageable()"
      [pageSize]="pageSize()"
      [skip]="skip()"
      [sort]="sort()"
      [filter]="filter()"
      (cellClick)="cellClick.emit($event)"
      (dataStateChange)="dataStateChange.emit($event)"
      (mouseover)="showGridTooltip($event, testTooltip)">
    </kendo-grid>
  } @else {
    <kendo-grid fast-tip #testTooltip="fast-tip" tipEvent="none" [tipContent]="tooltipGridTemplate"
      #gridDirective="kendoGrid"
      [data]="data()"
      [filterable]="filterable()"
      [selectable]="selectable()"
      [sortable]="sortable()"
      [selectedKeys]="selectedKeys()"
      [kendoGridSelectBy]="selectBy()"
      [loading]="loading()"
      [class]="conditionalClasses()"
      [pageable]="pageable()"
      [pageSize]="pageSize()"
      [skip]="skip()"
      [sort]="sort()"
      [filter]="filter()"
      (cellClick)="cellClick.emit($event)"
      (dataStateChange)="dataStateChange.emit($event)"
      (mouseover)="showGridTooltip($event, testTooltip)">
    </kendo-grid>
  }
  `
})
export class FastGridComponent implements AfterContentInit {
  // grid necessities, along w/ data
  @ContentChildren(ColumnBase) columns: QueryList<ColumnBase>;
  @ViewChild(GridComponent) grid: GridComponent;
  gridBinding = input<unknown[]>();
  data = input<Array<unknown> | GridDataResult | null>();

  // main directive inputs and outputs, default to null
  selectable = input<SelectableSettings>(null);
  sortable = input<SortSettings>(null);
  loading = input<boolean>(false);
  selectedKeys = input<unknown[]>(null);
  selectBy = input<string>();
  filterable = input<FilterableSettings>();
  pageable = input<boolean | PagerSettings>(false);
  pageSize = input<number>();
  skip = input<number>();
  sort = input<SortDescriptor[]>();
  filter = input<CompositeFilterDescriptor>();

  tooltipItem: string;

  cellClick = output<CellClickEvent>();
  dataStateChange = output<DataStateChangeEvent>();

  ngAfterContentInit() {
    resolvedPromise.then(() => {
      this.grid.columns.reset(this.columns.toArray());
    });
  }

  // stylized conditional classes input
  conditionalClasses = computed(() => {
    const classes = [] as string[];

    classes.push(...this.getCommonClasses());
    classes.push(...this.getLightClasses());
    classes.push(...this.getDarkClasses());

    const conditionalClasses = this.getConditionalClassesFromArrays(classes);
    return conditionalClasses;
  });


  getConditionalClassesFromArrays(classArray: string[]): { [key: string]: boolean } {
    const classes: { [key: string]: boolean } = {};
    classArray.forEach(className => {
      classes[className] = true;
    });
    return classes;
  }

  // make sure to put classes totally separately, otherwise it will not work (i.e. "flex flex-col h-full" will not work, but "flex" "flex-col" "h-full" will work)
  getCommonClasses() {
    return [
      "flex",
      "flex-col",
      "h-full",
      "[&_.k-grid-header_.k-header]:text-md",
      "[&_.k-grid-header_.k-header]:h-3",
      "[&_.k-grid-header_.k-header]:pb-1",
      "[&_.k-filter-row]:h-3",
      "[&_.k-grid-header_.k-grid-header-wrap_.k-filter-row_td]:p-1",
      "[&_.k-input-inner]:h-6.5",
      "[&_tbody_td]:p-1.5",
      "[&_.k-grid-content]:whitespace-nowrap",
      "[&_.k-grid-content-locked]:whitespace-nowrap",
      "[&_.k-input-inner]:font-bold",
      "[&_.k-grid-header_.k-filtercell_.k-filtercell-wrapper_.k-filtercell-operator]:hidden",
      "[&_.k-grid-header_.k-header>.k-link]:text-clip",
      "[&_.k-grid-header_.k-header.k-filterable>.k-cell-inner>.k-link_.k-sort-icon]:m-0",
      "[&_.k-grid-header_.k-header.k-filterable>.k-cell-inner>.k-link_.k-sort-icon_.k-icon]:ml-0",
      "[&_.k-grid-header_.k-header.k-filterable>.k-cell-inner>.k-link_.k-sort-icon_.k-icon]:absolute",
      "[&_.k-grid-header_.k-header.k-filterable>.k-cell-inner>.k-link_.k-sort-icon_.k-icon]:top-0",
      "[&_.k-grid-header_.k-header.k-filterable>.k-cell-inner>.k-link_.k-sort-icon_.k-icon]:right-4",
      "[&_.k-grid-header_.k-header.k-filterable>.k-cell-inner>.k-link_.k-sort-icon_.k-icon]:font-bold",
      "[&_.k-grid-header_.k-header.k-filterable>.k-cell-inner>.k-link_.k-sort-icon_.k-icon]:pointer-events-none",
      "[&_.k-grid-header-wrap_.k-header.k-filterable_.k-sort-order]:m-0",
      "[&_.k-grid-header-wrap_.k-header.k-filterable_.k-sort-order]:absolute",
      "[&_.k-grid-header-wrap_.k-header.k-filterable_.k-sort-order]:top-0",
      "[&_.k-grid-header-wrap_.k-header.k-filterable_.k-sort-order]:right-2.5",
      "[&_.k-grid-header-wrap_.k-header.k-filterable_.k-sort-order]:font-bold",
      "[&_.k-grid-header-wrap_.k-header.k-filterable_.k-sort-order]:pointer-events-none",
      "[&_.k-svg-i-filter]:mt-1",
      "[&_.k-svg-i-filter]:-mr-2",
      "[&_.k-grid-filter-menu]:w-6",
      "[&_.k-grid_.k-grid-filter-popup_.k-filter-menu_.k-filter-menu-container_kendo-grid-numeric-filter-menu]:gap-2",
      "[&_.k-grid_.k-grid-filter-popup_.k-filter-menu_.k-filter-menu-container_kendo-grid-numeric-filter-menu]:flex",
      "[&_.k-grid_.k-grid-filter-popup_.k-filter-menu_.k-filter-menu-container_kendo-grid-numeric-filter-menu]:flex-col",
      "[&_.k-grid_.k-table-th.k-filterable_.k-cell-inner_.k-grid-filter-menu]:flex",
      "[&_.k-grid_.k-table-th.k-filterable_.k-cell-inner_.k-grid-filter-menu]:mr-0",
      "[&_.k-grid_.k-filter-row_td]:px-0",
      "[&_.k-grid_.k-filter-row_td]:py-1",
      "[&_kendo-pager-input]:flex"
    ]
  }

  getLightClasses() {
    return [
      "[&_.k-grid-filter-menu]:hover:bg-base-white-1000",
      "[&_.k-sort-order]:hover:text-alt-blue-1000",
      "[&_.k-svg-i-sort-asc-small]:hover:text-alt-blue-1000",
      "[&_.k-svg-i-sort-desc-small]:hover:text-alt-blue-1000",
      "[&_.k-button-text]:text-base-black-1000",
      "[&_.k-grid-filter-menu.k-grid-header-menu.k-active]:bg-base-gray-500/50",
      "[&_.k-grid-filter-menu.k-grid-header-menu.k-active_.k-svg-i-filter.k-svg-icon.k-icon]:text-base-black-1000"];
  }

  getDarkClasses() {
    return [
      "dark:[&_.k-grid-filter-menu]:hover:bg-alt-blue-250",
      "dark:[&_.k-sort-order]:text-base-yellow-250",
      "dark:[&_.k-svg-i-sort-asc-small]:text-base-yellow-250",
      "dark:[&_.k-svg-i-sort-desc-small]:text-base-yellow-250",
      "dark:[&_.k-sort-order]:hover:text-base-yellow-750",
      "dark:[&_.k-svg-i-sort-asc-small]:hover:text-base-yellow-750",
      "dark:[&_.k-svg-i-sort-desc-small]:hover:text-base-yellow-750",
      "dark:[&_.k-selected]:bg-alt-blue-250",
      "dark:[&_.k-button-text]:text-base-white-500"];
  }

  showGridTooltip(e: MouseEvent, tooltip: FastTipDirective) {
    let previousTableCellId: string = null;
    const element = e.target as HTMLElement;

    const td = element.closest('td');
    const th = element.closest('th');
    const tableCellElem = th ?? td;
    const textElem = tableCellElem ? util.getTextElemFromTableCell(tableCellElem) : null;
    const isTextClipped = textElem ? util.isClipped(textElem, 14) : null;

    if (!tableCellElem || !textElem || !isTextClipped) {
      tooltip.hide();
      this.tooltipItem = null;
      return;
    };

    const parentRow = tableCellElem.parentElement as HTMLTableRowElement;
    const currentTableCellId = `cell-${parentRow.rowIndex}-${tableCellElem.cellIndex}`;
    if (previousTableCellId !== currentTableCellId) {
      tooltip.hide();
      this.tooltipItem = null;
      previousTableCellId = currentTableCellId;
    }
    setTimeout(() => {
      this.tooltipItem = textElem.innerText;
      if (this.tooltipItem != null) {
        tooltip.show(tableCellElem);
      }
    });
  }
}
