// File: PageObjectSearchableTable.ts
// Author: Vinicius Martins Ferraz
// Date: 10/07/2023

import { TextCompareStrategy } from '../page-element/page-element';
import { PageElementAny } from '../page-element/page-element-any';
import { PageElementTable } from '../page-element/page-element-table';
import { PageObject } from './page-object';
import { PageElementMatIcon } from '../page-element/page-element-mat-icon';
import { IAbstractObject } from '@vmfvmf/kraftos-lib';
import { IEntityFactory } from './i-entity-factory';
import { Form } from '../page-element/form';
import { SearchPageStruct } from './i-page-structure';
import { FormField } from '../form-field/form-field';
import { PageElementButton } from '../page-element/page-element-button';

export const DEFAULT_TABLE_ID = '#default-table-name-id';

export abstract class PageObjectSearchableTable<I extends IAbstractObject> extends PageObject {

  protected abstract iEntityFactory: IEntityFactory<I>;

  form: Form;
  resultTable: PageElementTable<I>;

  constructor(searchPageStruct: SearchPageStruct, title: string, protected endpoint: string, url: string = endpoint) {
    super(searchPageStruct, title, url);
    this.form = new Form(searchPageStruct.filters),
    this.resultTable = searchPageStruct.resultTable;
  }

  get filters() {
    return this.form.fields;
  }

  get allItems(): I[] {
    return this.resultTable.initialData;
  }

  get newButton() {
    return new PageElementMatIcon({ id: 'app-new-button', iconName: 'create_new_folder', tooltip: "Create" });
  }

  get matPanelFilterTitle() {
    return new PageElementAny({ id: 'mat-panel-title', text: 'Filter', textCompareStrategy: TextCompareStrategy.INCLUDES });
  }

  matPanelFilterIcon = new PageElementAny({ id: 'mat-panel-title mat-icon', text: 'filter_list' });
  matPanelFilterDescription = new PageElementAny({ id: 'mat-panel-description', text: 'Use filtros para ajudar na pesquisa', textCompareStrategy: TextCompareStrategy.INCLUDES  });
  matExpansionPanelFilterButton = new PageElementButton({ id: 'mat-expansion-panel' });

  searchButton = new PageElementButton({
    id: '#searchButton',
    tooltip: 'Search!',
    iconName: 'search'
  });

  clearFiltersButton = new PageElementButton({
    id: '#clearFiltersButton',
    tooltip: 'Clear!',
    iconName: 'clear'
  });

  get frstItem() {
    return this.resultTable.firstRow;
  }

  get showHideFiltersButton(): PageElementButton {
    return this.matExpansionPanelFilterButton;
  }

  public search(params?: I) {
    if (params) {
      this.form.setFieldsValues(params);
    }

    cy.intercept({
      method: 'GET',
      url: `/api/${this.endpoint}/**`,
    }).as('dataGetSearchResult');

    this.searchButton.click();

    cy.wait('@dataGetSearchResult').its('response.statusCode').should('equal', 200);
    cy.wait(300);
  }

  get paginator() {
    return this.resultTable.paginator;
  }

  paginatorSelectPage(value: string) {
    this.paginator!.paginatorPageSelect.selectByValue(value);
  }

  ValidateNoResultSearch(): void {
    this.resultTable.validateEmptyTableOrNoResult();
  }

  public validatePaginatorResult(pageNumber: number =  this.paginator!.currentPage, total: number = this.allItems.length) {
    let start = 1 + ((pageNumber - 1) *  this.paginator!.itemsPerPage);
    let end = 0;
    if (total > 0 && total > start + this.paginator!.itemsPerPage -1) {
      end = start + this.paginator!.itemsPerPage -1;
    } else if (total > 0) {
      end = total;
    }
    this.paginator!.validatePositionText(start, end, total);
  }

  public override validatePage(): void {
    this.showHideFiltersButton.click();
    super.validatePage();

    this.matPanelFilterTitle.validateDefaultFieldValues();
    this.matPanelFilterIcon.validateDefaultFieldValues();
    this.matPanelFilterDescription.validateDefaultFieldValues();

    this.showHideFiltersButton.validateDefaultFieldValues();
    this.clearFiltersButton.validateDefaultFieldValues();
    this.searchButton.validateDefaultFieldValues();
    this.newButton.validateDefaultFieldValues();
    this.resultTable.validateDefaultFieldValues();
  }

  validate1stSearchResult(iAbs: I): void {
    this.resultTable.setFrstRowValuesFromObject(iAbs);
    this.frstItem!.validateDefaultFieldValues();
  }

  validateTableSearchResult(iAbstractObjects: I[] = this.allItems): void {
    this.resultTable.validateTableResultWithInterfaceObjects(iAbstractObjects);
    this.paginator?.validateNavigateButtons();
  }

  validateTableSearchResultPaginated(iAbstractObjects: I[] = this.allItems): void {
    this.resultTable.validateTableResultPaginatedWithInterfaceObjects(iAbstractObjects);
    this.paginator!.validateNavigateButtons();
  }

  validateSearchForEachFilter() {
    this.filters.forEach((f: any) => {
      const target = this.allItems[Math.floor(Math.random()*this.allItems.length)];

      let value = (<any>target)[f.entityPropertyName!];

      f.setValue(value);

      cy.intercept({
        method: 'GET',
        url: `/api/${this.endpoint}/**`,
      }).as('dataGetSearchResult');

      this.searchButton.click();

      cy.wait('@dataGetSearchResult').its('response.statusCode').should('equal', 200);
      cy.wait(300);

      const result = this.allItems.filter(i => (<any>i)[f.entityPropertyName!] == (<any>target)[f.entityPropertyName!]);
      this.validateTableSearchResult(result);
      if (this.paginator) this.validatePaginatorResult(1, result.length);

      this.clearFiltersButton.click();
    });
  }

  validateSearchAllFilterCombination() {
    const target = this.allItems[Math.floor(Math.random()*this.allItems.length)];

    let result = [...this.allItems];

    this.filters.forEach((f: any) => {
      f.setValue((<any>target)[f.entityPropertyName!]);
      result = result
        .filter(i => (<any>i)[f.entityPropertyName!] == (<any>target)[f.entityPropertyName!]);
    });

    cy.intercept({
      method: 'GET',
      url: `/api/${this.endpoint}/**`,
    }).as('dataGetSearchResult');

    this.searchButton.click();

    cy.wait('@dataGetSearchResult').its('response.statusCode').should('equal', 200);
    cy.wait(300);

    this.validateTableSearchResult(result);
    if (this.paginator) this.validatePaginatorResult(1, result.length);

    this.clearFiltersButton.click();
  }

  validateSearchFilterCombination() {
    let filterNumber = 2;
    if (this.filters.length < 3) {
      cy.log('validateSearchFilterCombination skipped. Not sufficient filters.');
      return;
    }
    if (this.filters.length > 3) {
      filterNumber = Math.floor(Math.random()*(this.allItems.length-2)) + 1;
    }

    for (let i = 0; i < 3; i++) {
      let targetFilters = new Array<FormField>();

      do {
        let targetFilter = this.filters[Math.floor(Math.random()*(this.filters.length))];
        if (targetFilter && !targetFilters.includes(targetFilter)) targetFilters.push(targetFilter);
      } while (targetFilters.length < filterNumber);

      const target = this.getRandomItemFromAllItems();
      targetFilters.forEach(f => f.setValue((<any>target)[f.entityPropertyName!]));


      let result = [...this.allItems];

      targetFilters
      .forEach(f => result = result
        .filter(i => (<any>i)[f.entityPropertyName!] == (<any>target)[f.entityPropertyName!])
      );

      cy.intercept({
        method: 'GET',
        url: `/api/${this.endpoint}/**`,
      }).as('dataGetSearchResult');

      this.searchButton.click();

      cy.wait('@dataGetSearchResult').its('response.statusCode').should('equal', 200);
      cy.wait(300);

      this.validateTableSearchResult(result);
      if (this.paginator) this.validatePaginatorResult(1, result.length);

      this.clearFiltersButton.click();
    }
  }

  getRandomItemFromAllItems(): any {
    return this.allItems[Math.floor(Math.random()*this.allItems.length)];
  }

  validateNoResultSearch() {
    this.filters.forEach((f:any) => f.setValue((<any>this.iEntityFactory?.NO_RESULT_SEARCH)[f.entityPropertyName!]));

    cy.intercept({
      method: 'GET',
      url: `/api/${this.endpoint}/**`,
    }).as('dataGetSearchResult');

    this.searchButton.click();

    cy.wait('@dataGetSearchResult').its('response.statusCode').should('equal', 200);
    cy.wait(300);

    this.resultTable.validateEmptyTableOrNoResult();

    this.clearFiltersButton.click();
  }

   clickDeleteFrstItem(confirmar: boolean = false): void {
    this.frstItem!.buttonDeleteClick();
    if (confirmar) {
      //  this.clickSim();
    } else {
      //  this.clickNao();
    }
  }

   clickSelectFrstItem(): void {
    //  this.table().clickCheckFrstItem();
  }

   clickBatchDelete(confirmar: boolean = true): void {
    //  this.table().clickBatchDelete();
    // if (confirmar) {
    //   //  this.clickSim();
    // } else {
    //   //  this.clickNao();
    // }
  }
}
