import { Compare, type SugarElement } from '@ephox/sugar';

import type { AlloyComponent } from '../api/component/ComponentApi';
import * as AlloyEvents from '../api/events/AlloyEvents';
import * as SystemEvents from '../api/events/SystemEvents';
import * as AlloyLogger from '../log/AlloyLogger';

import type { FocusingEvent } from './SimulatedEvent';

// The purpose of this check is to ensure that a simulated focus call is not going
// to recurse infinitely. Essentially, if the originator of the focus call is the same
// as the element receiving it, and it wasn't its own target, then stop the focus call
// and log a warning.
const isRecursive = (component: AlloyComponent, originator: SugarElement<Node>, target: SugarElement<Node>): boolean =>
  Compare.eq(originator, component.element) && !Compare.eq(originator, target);

const events: AlloyEvents.AlloyEventRecord = AlloyEvents.derive([
  AlloyEvents.can<FocusingEvent>(SystemEvents.focus(), (component, simulatedEvent) => {
    // originator may not always be there. Will need to check this.
    const event = simulatedEvent.event;
    const originator = event.originator;
    const target = event.target;
    if (isRecursive(component, originator, target)) {
      // eslint-disable-next-line no-console
      console.warn(
        SystemEvents.focus() + ' did not get interpreted by the desired target. ' +
        '\nOriginator: ' + AlloyLogger.element(originator) +
        '\nTarget: ' + AlloyLogger.element(target) +
        '\nCheck the ' + SystemEvents.focus() + ' event handlers'
      );
      return false;
    } else {
      return true;
    }
  })
]);

export {
  events
};
