import { Locator, Page } from 'playwright';
import { AbstractLocator, AbstractWidget } from '../AbstractWidget';
import {
  TableModalAction,
  TableSingleAction,
  TableSingleActionFindOptions,
} from '../parts';
import { TBody, THead } from '../TableWidget';
import {
  CellFindOptions,
  ColumnFilterFindOptions,
  DataTableFindOptions,
} from './types';
import { MultiselectFilter } from './filter';
import { widgetStep } from '@/core/utils';
import { expect } from '@/core/fixtures';
import { getLocator } from '@/core/locators';

export class DataTableWidget extends AbstractWidget {
  type = 'dataTable';

  constructor(
    protected findOptions: DataTableFindOptions,
    protected readonly page: Page,
    protected readonly parent?: AbstractWidget,
    protected readonly parentLocator?: AbstractLocator
  ) {
    super(findOptions, page, parent, parentLocator);
  }

  find() {
    const { widgetLid, dataTableName, resource } = this.findOptions;
    const selectors: string[] = [];
    if (widgetLid) selectors.push(`[data-widgetlid="${widgetLid}"]`);
    if (dataTableName) selectors.push(`[data-name="${dataTableName}"]`);
    if (resource) selectors.push(`[data-recources="${resource}"]`);
    return this.makeLocator(selectors);
  }

  @widgetStep
  async filterRowSwitcherIsVisible() {
    await expect(
      getLocator('table.dataTable.filterSwitcher', this.l)
    ).toBeVisible();
  }

  @widgetStep
  async openFilterRow() {
    await this.filterRowSwitcherIsVisible();
    const switcher = getLocator('table.dataTable.filterSwitcher', this.l);
    const hasClass = await switcher.evaluate(
      (ele, className) => ele?.classList.contains(className) ?? false,
      'active'
    );

    if (!hasClass) {
      await switcher.click();
    }
  }
  singleAction(findOptions: TableSingleActionFindOptions) {
    return new TableSingleAction(findOptions, this, this.page);
  }

  modalAction(findOptions: TableSingleActionFindOptions) {
    return new TableModalAction(findOptions, this, this.page);
  }

  cell(findOptions?: CellFindOptions) {
    return new DataTableCell(findOptions || {}, this, this.page);
  }

  multiselectFilter(findOptions: ColumnFilterFindOptions) {
    return new MultiselectFilter(findOptions, this.page, this);
  }

  get emptyMessage() {
    return this.l.locator('[role="alert"]', {
      hasText: 'Nebyly nalezeny žádné záznamy',
    });
  }

  @widgetStep
  async isEmpty() {
    await expect(this.emptyMessage).toBeVisible();
  }
  @widgetStep
  async isNotEmpty() {
    await expect(this.emptyMessage).not.toBeVisible();
  }

  get head() {
    return new THead(this.page, this);
  }
  get body() {
    return new TBody(this.page, this);
  }
  get table() {
    return this.l.locator('table');
  }
}

class DataTableCell extends AbstractLocator {
  constructor(
    protected readonly findOptions: CellFindOptions,
    protected readonly dataTable: DataTableWidget,
    page: Page
  ) {
    super(page);
  }
  find() {
    const { columnId, text, exact } = this.findOptions;
    let cellLocator: Locator = this.dataTable.l.locator('table tbody tr td');

    if (columnId)
      cellLocator = this.dataTable.l.locator(
        `table tbody tr td[data-col="${columnId}"]`
      );
    if (text)
      cellLocator = cellLocator.filter({
        hasText: exact ? new RegExp(`^${text}$`) : text,
      });

    return cellLocator.first();
  }
}
