import { Utility } from '../../core/utility';
import { AUTO_SUBMIT_BUTTON_UTIL_SELECTOR } from './auto-submit-button';
import { AUTO_SUBMIT_INPUT_UTIL_SELECTOR } from './auto-submit-input';

const NAVIGATE_AWAY_PROMPT_INITIALIZED_CLASS = 'navigate-away-prompt--initialized';
const NAVIGATE_AWAY_PROMPT_UTIL_OPTOUT = '[uw-no-navigate-away-prompt]';

@Utility({
  selector: 'form',
})
export class NavigateAwayPrompt {

  _element;

  _touched = false;
  _unloadDueToSubmit = false;

  constructor(element) {
    if (!element) {
      throw new Error('Navigate Away Prompt utility needs to be passed an element!');
    }

    this._element = element;

    if (this._element.classList.contains(NAVIGATE_AWAY_PROMPT_INITIALIZED_CLASS)) {
      return false;
    }

    // ignore forms that get submitted automatically
    if (this._element.querySelector(AUTO_SUBMIT_BUTTON_UTIL_SELECTOR) || this._element.querySelector(AUTO_SUBMIT_INPUT_UTIL_SELECTOR)) {
      return false;
    }

    if (this._element.matches(NAVIGATE_AWAY_PROMPT_UTIL_OPTOUT)) {
      return false;
    }

    window.addEventListener('beforeunload', this._beforeUnloadHandler);

    this._element.addEventListener('submit', () => {
      this._unloadDueToSubmit = true;
    });
    this._element.addEventListener('change', () => {
      this._touched = true;
      this._unloadDueToSubmit = false;
    });

    // mark initialized
    this._element.classList.add(NAVIGATE_AWAY_PROMPT_INITIALIZED_CLASS);

  }

  destroy() {
    window.removeEventListener('beforeunload', this._beforeUnloadHandler);
  }

  _beforeUnloadHandler = (event) => {
    // allow the event to happen if the form was not touched by the
    // user or the unload event was initiated by a form submit
    if (!this._touched || this._unloadDueToSubmit) {
      return false;
    }

    // cancel the unload event. This is the standard to force the prompt to appear.
    event.preventDefault();
    // chrome
    event.returnValue = true;
    // for all non standard compliant browsers we return a truthy value to activate the prompt.
    return true;
  }
}
