import { expect } from '@/core/fixtures';
import {
  AbstractFormInputWidget,
  FormInputFindOptions,
} from './AbstractFormInputWidget';
import { Page } from 'playwright';
import { AbstractLocator, AbstractWidget } from '../AbstractWidget';
import { widgetStep } from '@/core/utils';

export type CheckboxFindOptions = FormInputFindOptions & {
  labelPosition?: 'top' | 'right' | 'left';
};

export class CheckboxInput extends AbstractFormInputWidget<boolean> {
  type = 'formCheckboxInput';

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

  find() {
    const { label, fieldName } = this.findOptions;
    const selectors: string[] = [];
    if (fieldName) selectors.push(`[name="${fieldName}"]`);
    if (label) selectors.push(`[data-label="${label}"]`);

    return this.makeLocator(selectors);
  }

  @widgetStep
  async change(val?: boolean) {
    if (val) await this.check();
    else await this.uncheck();
  }

  @widgetStep
  async check() {
    await this.inputLocator.check();
  }

  @widgetStep
  async uncheck() {
    await this.inputLocator.uncheck();
  }

  @widgetStep
  async hasValue(val: boolean) {
    if (val) await expect(this.inputLocator).toBeChecked();
    else await expect(this.inputLocator).not.toBeChecked();
  }

  @widgetStep
  async hasNotValue(val: boolean) {
    if (val) await expect(this.inputLocator).not.toBeChecked();
    else await expect(this.inputLocator).toBeChecked();
  }

  @widgetStep
  async isEmpty() {
    await expect(this.inputLocator).not.toBeChecked();
  }

  get inputLocator() {
    return this.l;
  }
}

export class RadioInput extends AbstractFormInputWidget<string> {
  type = 'formRadioInput';

  /**
   *
   * @param val (label string)
   */
  @widgetStep
  async change(val?: string) {
    if (val) await this.l.getByLabel(val).check();
  }

  /**
   *
   * @param val (value string OR id)
   */
  @widgetStep
  async changeByValue(val?: string) {
    if (val) await this.l.locator(`input[value="${val}"]`).check();
  }

  @widgetStep
  async hasValue(val: string) {
    await expect(this.l.locator(`input[value="${val}"]`)).toBeChecked();
  }

  @widgetStep
  async hasNotValue(val: string) {
    await expect(this.l.locator(`input[value="${val}"]`)).not.toBeChecked();
  }

  @widgetStep
  async hasLabelValue(val: string) {
    await expect(this.l.getByLabel(val)).toBeChecked();
  }

  @widgetStep
  async hasNotLabelValue(val: string) {
    await expect(this.l.getByLabel(val)).not.toBeChecked();
  }

  @widgetStep
  isEmpty(): void {
    throw new Error('Method not implemented.');
  }
}

export class RadioButtonGroupInput extends AbstractFormInputWidget<string> {
  type = 'formRadioInput';

  /**
   *
   * @param val (label string)
   */
  @widgetStep
  async change(val?: string) {
    if (val) await this.l.locator(`button[label="${val}"]`).click();
  }

  @widgetStep
  async hasValue(val: string) {
    await expect(this.l.locator(`button[label="${val}"]`)).toHaveAttribute(
      'data-selected',
      'true'
    );
  }

  @widgetStep
  async hasNotValue(val: string) {
    await expect(this.l.locator(`button[label="${val}"]`)).toHaveAttribute(
      'data-selected',
      'false'
    );
  }

  @widgetStep
  isEmpty(): void {
    throw new Error('Method not implemented.');
  }
}
