/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

const intersectionObserverMock = {callback: null, observedTargets: []};

/**
 * This is a broken polyfill.
 * It is only intended to provide bare minimum test coverage.
 * More meaningful tests will require the use of fixtures.
 */
export function mockIntersectionObserver() {
  intersectionObserverMock.callback = null;
  intersectionObserverMock.observedTargets = [];

  class IntersectionObserver {
    constructor() {
      intersectionObserverMock.callback = arguments[0];
    }

    disconnect() {
      intersectionObserverMock.callback = null;
      intersectionObserverMock.observedTargets.splice(0);
    }

    observe(target) {
      intersectionObserverMock.observedTargets.push(target);
    }

    unobserve(target) {
      const index = intersectionObserverMock.observedTargets.indexOf(target);
      if (index >= 0) {
        intersectionObserverMock.observedTargets.splice(index, 1);
      }
    }
  }

  window.IntersectionObserver = IntersectionObserver;

  return intersectionObserverMock;
}

export function simulateIntersection(...entries) {
  intersectionObserverMock.callback(
    entries.map(([target, rect, ratio]) => ({
      boundingClientRect: {
        top: rect.y,
        left: rect.x,
        width: rect.width,
        height: rect.height,
      },
      intersectionRatio: ratio,
      target,
    })),
  );
}

/**
 * Stub out getBoundingClientRect for the specified target.
 * This API is required by the test selectors but it isn't implemented by jsdom.
 */
export function setBoundingClientRect(target, {x, y, width, height}) {
  target.getBoundingClientRect = function () {
    return {
      width,
      height,
      left: x,
      right: x + width,
      top: y,
      bottom: y + height,
    };
  };
}

/**
 * Stub out getClientRects for the specified target.
 */
export function setClientRects(target, rects) {
  target.getClientRects = function () {
    return rects.map(({x, y, width, height}) => ({
      width,
      height,
      left: x,
      right: x + width,
      top: y,
      bottom: y + height,
      x,
      y,
    }));
  };
}

/**
 * Mock Range.prototype.getClientRects and getBoundingClientRect since jsdom doesn't implement them.
 * Call this in beforeEach to set up the mock.
 */
export function mockRangeClientRects(
  rects = [{x: 0, y: 0, width: 100, height: 20}],
) {
  const originalCreateRange = document.createRange;
  document.createRange = function () {
    const range = originalCreateRange.call(document);
    range.getClientRects = function () {
      return rects.map(({x, y, width, height}) => ({
        width,
        height,
        left: x,
        right: x + width,
        top: y,
        bottom: y + height,
        x,
        y,
      }));
    };
    range.getBoundingClientRect = function () {
      // Return the bounding rect that encompasses all rects
      if (rects.length === 0) {
        return {
          width: 0,
          height: 0,
          left: 0,
          right: 0,
          top: 0,
          bottom: 0,
          x: 0,
          y: 0,
        };
      }
      const first = rects[0];
      return {
        width: first.width,
        height: first.height,
        left: first.x,
        right: first.x + first.width,
        top: first.y,
        bottom: first.y + first.height,
        x: first.x,
        y: first.y,
      };
    };
    return range;
  };
  return function restore() {
    document.createRange = originalCreateRange;
  };
}