import { Locator, Page } from 'playwright';
import { widgetStep } from '../utils';
import { WidgetFindOptions } from './types';
import { expect } from '../fixtures';
import { WidgetHelper } from '../WidgetHelper';

export abstract class AbstractLocator {
  private _locator: null | Locator = null;

  constructor(protected readonly page: Page) {}

  protected abstract find(): Locator;

  get child() {
    return new WidgetHelper(this.page, undefined, this);
  }

  get locator(): Locator {
    if (!this._locator) {
      this._locator = this.find();
    }
    return this._locator;
  }

  get l() {
    if (!this.locator) throw new Error('Locator is not yet initialized');
    return this.locator;
  }

  @widgetStep
  async click() {
    await this.l.click();
    return this;
  }

  @widgetStep
  async ele() {
    return (await this.l.all())[0];
  }

  @widgetStep
  async isVisible() {
    await expect(this.l).toBeVisible();
  }
  @widgetStep
  async isNotVisible() {
    await expect(this.l).not.toBeVisible();
  }

  @widgetStep
  async visible(yes = true) {
    if (yes) await this.isVisible();
    else await this.isNotVisible();
  }
}

export abstract class AbstractWidget extends AbstractLocator {
  abstract readonly type: string;

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

  protected abstract find(): Locator;

  private makeSelectors(additional: string[] = []) {
    const initial = [`[data-w="${this.type}"]`];
    if (this.findOptions.widgetLid)
      initial.push(`[data-widgetlid="${this.findOptions.widgetLid}"]`);

    return [...initial, ...additional];
  }

  protected makeLocator(
    additionalSelectors: string[] = [],
    options: { has?: Locator; hasText?: string | RegExp } = {}
  ) {
    const { index } = this.findOptions;
    const allSelectors = this.makeSelectors(additionalSelectors).join('');

    let parent: Locator | Page = this.page;
    if (this.parentLocator) parent = this.parentLocator.l;
    else if (this.parent) parent = this.parent.l;

    let locator = parent.locator(allSelectors, options);
    if (typeof index == 'number') locator = locator.nth(index);

    return locator;
  }

  get child() {
    return new WidgetHelper(this.page, this);
  }
}
// core(page).button().byIcon('broom').click().then()
