import { expect, Locator } from '@playwright/test';
import BasePage from '../../Base';
import { DashboardPage } from '..';
import { ToolbarPage } from '../common/Toolbar';
import { getTextExcludeIconText } from '../../../tests/utils/general';
import { TopbarPage } from '../common/Topbar';

export class WebhookFormPage extends BasePage {
  readonly dashboard: DashboardPage;
  readonly topbar: TopbarPage;
  readonly toolbar: ToolbarPage;
  readonly addNewButton: Locator;
  readonly saveButton: Locator;
  readonly testButton: Locator;

  constructor(dashboard: DashboardPage) {
    super(dashboard.rootPage);
    this.dashboard = dashboard;
    this.toolbar = dashboard.grid.toolbar;
    this.topbar = dashboard.grid.topbar;
    this.addNewButton = this.dashboard.get().locator('.nc-btn-create-webhook');
    this.saveButton = this.get().getByTestId('nc-save-webhook');
    this.testButton = this.get().locator('button:has-text("Test Webhook")');
  }

  get() {
    return this.rootPage.locator(`.nc-modal-webhook-create-edit`);
  }

  async create({
    title,
    event,
    operation,
    url = 'http://localhost:9090/hook',
  }: {
    title: string;
    event: string;
    operation?: string;
    url?: string;
  }) {
    await this.dashboard.grid.topbar.openDetailedTab();
    await this.dashboard.details.clickWebhooksTab();
    // wait for tab transition
    await this.rootPage.waitForTimeout(200);
    await this.dashboard.details.clickAddWebhook();
    await this.get().waitFor({ state: 'visible' });

    await this.configureHeader({
      key: 'Content-Type',
      value: 'application/json',
    });

    await this.configureWebhook({ title, event, operation, url });
    await this.save();
    await this.close();
  }

  async configureWebhook({
    title,
    event,
    operation,
    url,
  }: {
    title?: string;
    event?: string;
    operation?: string;
    url?: string;
  }) {
    if (title) {
      await this.get().locator(`.nc-text-field-hook-title`).fill(title);
    }
    if (event) {
      await this.get().locator(`[data-testid="nc-dropdown-hook-event"]`).click();
      const modal = this.rootPage.locator(`.nc-modal-hook-event`);
      await modal.locator(`.ant-select-item:has-text("${event}")`).click();
    }

    if (operation && operation !== 'trigger') {
      const dropdownHookOperation = this.get().locator(`[data-testid="nc-dropdown-hook-operation"]`);
      await dropdownHookOperation.click();
      const modal = this.rootPage.locator(`[data-testid="nc-dropdown-hook-operation-modal"]`);
      await modal.waitFor({ state: 'visible' });

      const sendMeEverythingLocator = modal.locator(
        `[data-testid="nc-dropdown-hook-operation-option"][data-testvalue="sendMeEverything"] input`
      );

      await sendMeEverythingLocator.waitFor({ state: 'visible' });

      // If it is already checked, then uncheck it to uncheck all operations
      if (await sendMeEverythingLocator.isChecked()) {
        await sendMeEverythingLocator.click();
      } else {
        // If it is not checked, then check it to check all operations and then uncheck it to uncheck all operations
        await sendMeEverythingLocator.click();
        await sendMeEverythingLocator.click();
      }

      await modal.locator(`[data-testid="nc-dropdown-hook-operation-option"][data-testvalue="${operation}"]`).click();
      // close the dropdown
      await dropdownHookOperation.click();
      await modal.waitFor({ state: 'hidden' });
    }
    if (url) {
      await this.get().locator(`.nc-text-field-hook-url-path`).fill(url);
    }
  }

  async addCondition({
    column,
    operator,
    value,
    save,
  }: {
    column: string;
    operator: string;
    value: string;
    save: boolean;
  }) {
    await this.get().locator(`.nc-check-box-hook-condition`).waitFor({ state: 'visible' });
    await this.get().locator(`.nc-check-box-hook-condition`).click();
    await this.get().locator(`button:has-text("Add Filter")`).first().click();
    const modal = this.get().locator(`.menu-filter-dropdown`).last();

    await modal.locator('.nc-filter-field-select').waitFor({ state: 'visible', timeout: 4000 });
    await modal.locator('.nc-filter-field-select').click();
    const modalField = this.dashboard.rootPage.locator('.nc-dropdown-toolbar-field-list:visible');
    await modalField.locator(`.ant-select-item:has-text("${column}")`).click();

    await modal.locator('.nc-filter-operation-select').click();
    const modalOp = this.dashboard.rootPage.locator('.nc-dropdown-filter-comp-op:visible');
    await modalOp.locator(`.ant-select-item:has-text("${operator}")`).click();

    if (operator != 'is null' && operator != 'is not null') {
      await modal.locator('.nc-filter-value-select > input').fill(value);
    }

    if (save) {
      await this.save();
      await this.close();
    }
  }

  async toggleIncludeUser({ save }: { save: boolean }) {
    await this.get().locator(`.nc-check-box-include-user`).click();

    if (save) {
      await this.save();
      await this.close();
    }
  }

  async deleteCondition(p: { save: boolean }) {
    await this.get().locator(`.nc-filter-item-remove-btn`).click();
    if (p.save) {
      await this.save();
      await this.close();
    }
  }

  async save() {
    const saveAction = async () => await this.saveButton.click();

    await this.waitForResponse({
      uiAction: saveAction,
      requestUrlPathToMatch: 'operation=hook',
      httpMethodsToMatch: ['POST', 'PATCH'],
    });

    // await this.verifyToast({ message: 'Webhook details updated successfully' });
  }

  async test() {
    await this.testButton.click();
    await this.verifyToast({ message: 'Webhook tested successfully' });
  }

  async delete({ index, wfr = true }: { index: number; wfr?: boolean }) {
    await this.dashboard.grid.topbar.openDetailedTab({ waitForResponse: wfr });
    await this.dashboard.details.clickWebhooksTab();
    await this.dashboard.details.webhook.deleteHook({ index });
    await this.rootPage.locator('div.ant-modal.active').locator('button:has-text("Delete")').click();
  }

  async close() {
    // type esc key
    // await this.get().press('Escape');
    // await this.get().waitFor({ state: 'hidden' });
    await this.dashboard.grid.topbar.openDataTab();
  }

  async open({ index }: { index: number }) {
    await this.dashboard.grid.topbar.openDetailedTab();
    await this.dashboard.details.clickWebhooksTab();

    const rowItem = await this.dashboard.details.webhook.getItem({ index });
    await rowItem.waitFor({ state: 'visible' });
    await rowItem.scrollIntoViewIfNeeded();

    await rowItem.click({
      force: true,
    });

    await this.get().waitFor({ state: 'visible' });
  }

  async openForm({ index }: { index: number }) {
    await this.dashboard.get().locator(`.nc-hook`).nth(index).click();
  }

  async click({ index }: { index: number }) {
    await this.dashboard.get().locator(`.nc-hook`).nth(index).click();
  }

  async configureHeader({ key, value }: { key: string; value: string }) {
    // hardcode "Content-type: application/json"
    await this.get().locator(`.ant-tabs-tab-btn:has-text("Headers")`).click();
    await this.rootPage.waitForTimeout(500);

    await this.get().locator('.nc-input-hook-header-key input').click();
    await this.rootPage.waitForTimeout(500);

    // kludge, as the dropdown is not visible even after scroll into view
    await this.rootPage.locator('.nc-input-hook-header-key input').pressSequentially(key);
    await this.rootPage
      .locator('.ant-select-dropdown:visible')
      .locator(`.ant-select-item:has-text("${key}")`)
      .scrollIntoViewIfNeeded();
    await this.rootPage
      .locator('.ant-select-dropdown:visible')
      .locator(`.ant-select-item:has-text("${key}")`)
      .click({ force: true });

    await this.get().locator('.nc-webhook-header-value-input').clear();
    await this.get().locator('.nc-webhook-header-value-input').type(value);
    await this.get().press('Enter');

    // find out if the checkbox is already checked
    const isChecked = await this.get()
      .locator('.nc-hook-header-checkbox')
      .locator('input.ant-checkbox-input')
      .isChecked();
    if (!isChecked) await this.get().locator('.nc-hook-header-checkbox').locator('input.ant-checkbox-input').click();
  }

  async verifyForm({
    title,
    hookEvent,
    url,
    notificationType,
    urlMethod,
    condition,
  }: {
    title: string;
    hookEvent: string;
    url: string;
    notificationType: string;
    urlMethod: string;
    condition: boolean;
  }) {
    await expect.poll(async () => await this.get().locator('input.nc-text-field-hook-title').inputValue()).toBe(title);
    await expect(this.get().locator('.nc-text-field-hook-event >> .ant-select-selection-item')).toHaveText(hookEvent);

    const locator = this.get().locator('.nc-select-hook-notification-type >> .ant-select-selection-item');
    const text = await getTextExcludeIconText(locator);
    expect(text).toBe(notificationType);

    await expect(this.get().locator('.nc-select-hook-url-method >> .ant-select-selection-item')).toHaveText(urlMethod);
    await expect.poll(async () => await this.get().locator('input.nc-text-field-hook-url-path').inputValue()).toBe(url);

    const conditionCheckbox = this.get().locator('label.nc-check-box-hook-condition >> input[type="checkbox"]');
    if (condition) {
      await expect(conditionCheckbox).toBeChecked();
    } else {
      await expect(conditionCheckbox).not.toBeChecked();
    }
  }

  async goBackFromForm() {
    await this.get().locator('svg.nc-icon-hook-navigate-left').click();
  }
}
