import { expect, Locator, Page } from '@playwright/test';
import { UITypes } from 'nocodb-sdk';
import BasePage from '../../Base';
import { getTextExcludeIconText } from '../../../tests/utils/general';
import { CellPageObject } from '../common/Cell';

export class SurveyFormPage extends BasePage {
  readonly cell: CellPageObject;

  readonly formHeading: Locator;
  readonly formSubHeading: Locator;
  readonly fillFormButton: Locator;
  readonly submitConfirmationButton: Locator;
  readonly submitButton: Locator;
  readonly nextButton: Locator;
  readonly nextSlideButton: Locator;
  readonly prevSlideButton: Locator;
  readonly darkModeButton: Locator;
  readonly formFooter: Locator;

  constructor(rootPage: Page) {
    super(rootPage);
    this.cell = new CellPageObject(this);
    this.formHeading = this.get().locator('[data-testid="nc-survey-form__heading"]');
    this.formSubHeading = this.get().locator('[data-testid="nc-survey-form__sub-heading"]');
    this.fillFormButton = this.get().locator('[data-testid="nc-survey-form__fill-form-btn"]');
    this.submitConfirmationButton = this.get().locator('[data-testid="nc-survey-form__btn-submit-confirm"]');
    this.submitButton = this.rootPage.locator(
      '.nc-survery-form__confirmation_modal [data-testid="nc-survey-form__btn-submit"]'
    );
    this.nextButton = this.get().locator('[data-testid="nc-survey-form__btn-next"]');
    this.nextSlideButton = this.get().locator('[data-testid="nc-survey-form__icon-next"]');
    this.prevSlideButton = this.get().locator('[data-testid="nc-survey-form__icon-prev"]');
    this.darkModeButton = this.get().locator('[data-testid="nc-form-dark-mode"]');
    this.formFooter = this.get().locator('[data-testid="nc-survey-form__footer"]');
  }

  get() {
    return this.rootPage.locator('html >> .nc-form-view');
  }

  async validateHeaders({ heading, subHeading }: { heading: string; subHeading: string }) {
    await expect(this.get()).toBeVisible();
    await expect(this.formHeading).toHaveText(heading);
    await expect(this.formSubHeading).toHaveText(subHeading);
  }

  async validate({ fieldLabel, footer }: { fieldLabel: string; footer: string }) {
    await expect(this.get()).toBeVisible();

    await expect(this.formFooter).toHaveText(footer);

    const locator = this.get().locator(`[data-testid="nc-form-column-label"]`);
    let fieldText = await getTextExcludeIconText(locator);

    // replace whitespace with ' ' for fieldLabel & fieldText
    fieldLabel = fieldLabel.replace(/\u00A0/g, ' ');
    fieldText = fieldText.replace(/\u00A0/g, ' ');

    expect(fieldText).toBe(fieldLabel);

    // parse footer text ("1 / 3") to identify if last slide
    let isLastSlide = false;
    const footerText = await this.formFooter.innerText();
    const slideNumber = footerText.split(' / ')[0];
    const totalSlides = footerText.split(' / ')[1];
    if (slideNumber === totalSlides) {
      isLastSlide = true;
    }
    if (isLastSlide) {
      await expect(this.submitConfirmationButton).toBeVisible();
    } else {
      await expect(this.nextButton).toBeVisible();
    }
  }

  async fill(param: { fieldLabel: string; type?: string; value?: string; skipNavigation?: boolean }) {
    await this.get().locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"]`).click();

    if (param.type === 'SingleLineText') {
      await this.get().locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"] >> input`).fill(param.value);
    } else if (param.type === 'DateTime') {
      await this.get().locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"] >> input`).first().click();
      const modal = this.rootPage.locator('.nc-picker-datetime');
      await expect(modal).toBeVisible();
      await modal.locator('.nc-date-picker-now-btn').click();
      await modal.waitFor({ state: 'hidden' });
    } else if (param.type === UITypes.LongText) {
      await this.get()
        .locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"] >> textarea`)
        .waitFor({ state: 'visible' });
      await this.get().locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"] >> textarea`).click();

      await this.get()
        .locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"] >> textarea`)
        .fill(param.value);
    } else {
      await this.get()
        .locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"] >> input`)
        .waitFor({ state: 'visible' });

      await this.get().locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"] >> input`).fill(param.value);

      if ([UITypes.Date, UITypes.Time, UITypes.Year, UITypes.DateTime].includes(param.type)) {
        // press enter key
        await this.get().locator(`[data-testid="nc-survey-form__input-${param.fieldLabel}"] >> input`).press('Enter');
      }
    }

    await this.get().locator(`[data-testid="nc-form-column-label"]`).click();

    if (!param.skipNavigation) {
      await this.nextButton.click();
    }
    // post next button click, allow transitions to complete
    await this.rootPage.waitForTimeout(100);
  }

  async validateSuccessMessage(param: { message: string; showAnotherForm?: boolean; isCustomMsg?: boolean }) {
    await this.get().locator('[data-testid="nc-survey-form__success-msg"]').waitFor({ state: 'visible' });

    if (param.isCustomMsg) {
      await this.get()
        .locator('[data-testid="nc-survey-form__success-msg"]')
        .locator('.tiptap.ProseMirror')
        .waitFor({ state: 'visible' });
    }

    await this.rootPage.waitForTimeout(200);
    await expect(
      this.get().locator(`[data-testid="nc-survey-form__success-msg"]:has-text("${param.message}")`)
    ).toBeVisible();

    if (param.showAnotherForm) {
      await expect(this.get().locator(`button:has-text("Submit Another Form")`)).toBeVisible();
    }
  }

  async clickFillForm() {
    await this.fillFormButton.click();
  }

  async confirmAndSubmit() {
    await this.submitConfirmationButton.click();
    await this.submitButton.waitFor({ state: 'visible' });

    await this.submitButton.click();

    await this.submitButton.waitFor({ state: 'hidden' });
  }

  async getFormFieldErrors() {
    const fieldErrorEl = this.get().locator('.ant-form-item-explain');
    return {
      locator: fieldErrorEl,
      verify: async ({ hasError, hasErrorMsg }: { hasError?: boolean; hasErrorMsg?: string | RegExp }) => {
        if (hasError !== undefined) {
          if (hasError) {
            await expect(fieldErrorEl.locator('.ant-form-item-explain-error').first()).toBeVisible();
          } else {
            await expect(fieldErrorEl.locator('.ant-form-item-explain-error').first()).not.toBeVisible();
          }
        }

        if (hasErrorMsg !== undefined) {
          await expect(fieldErrorEl.locator('.ant-form-item-explain-error').first()).toBeVisible();

          await expect(
            fieldErrorEl.locator('.ant-form-item-explain-error').filter({ hasText: hasErrorMsg }).first()
          ).toHaveText(hasErrorMsg);
        }
      },
    };
  }
}
