import { By, Key } from 'selenium-webdriver';
import { OjComboboxOneBase } from './OjComboboxOneBase';

/**
 * The component WebElement for [oj-combobox-one](../../jsdocs/oj.ojComboboxOne.html).
 * Do not instantiate this class directly, instead, use
 * [ojComboboxOne](../functions/elements.ojComboboxOne-1.html).
 */
export class OjComboboxOne extends OjComboboxOneBase {
  /**
   * Sets the value of "value" property.
   * The value of the element.
   * @param value The value to set for "value"
   * @override
   */
  async changeValue(value: any) {
    // Call focus() on the root element
    await this.getDriver().executeScript('arguments[0].focus()', this);
    // Only mutate if not readonly/disabled
    const readonly = await this.getReadonly();
    const disabled = await this.getDisabled();
    if (!(readonly || disabled)) {
      await this.whenBusyContextReady();
      const isValueSet = await this.getDriver().executeAsyncScript(
        `
        var element = arguments[0];
        var value = arguments[1];

        // Last argument will the done function
        var doneFunc = arguments[arguments.length - 1];
        
        var onSuccess = doneFunc.bind(null, true);
        var onFailure = doneFunc.bind(null, false);
        var onError = doneFunc.bind(null, false);
        
        require(['ojs/ojcustomelement-utils'], function (utils) {
          // Retrieve the widget instance from the element
          var bridge = utils.CustomElementUtils.getElementBridge(element);
          var widget = bridge._WIDGET_INSTANCE.combobox;
          widget._selectItemByValue(value)
            .then(onSuccess, onFailure)
            .catch(onFailure);
        });
      `,
        this,
        value
      );

      // If failed to set value, fallback to setProperty
      if (isValueSet === false) {
        console.warn('Failed to update value by interaction. Falling back to setProperty.');
        await this._changeValueFallback(value);
      }
    }
  }

  /**
   * Clears the value
   * @override
   */
  async clear(): Promise<void> {
    const input = await this.findElement(By.css('.oj-combobox-input'));
    await input.clear();
    await input.sendKeys(Key.ENTER);
  }

  /**
   * This is a fallback mechanism for setting a value which
   * uses the setProperty method to update the value.
   *
   * @param value The value to be set
   */
  private _changeValueFallback(value: any): Promise<void> {
    return this.setProperty<any>('value', value);
  }
}
