import React from "react";
import { Point, Range } from "../../editor";
import { getEffectKeys } from "./paragraph";
import type { Controller } from "../../controller";
import { PID } from "../../persist";
import { getSelectionRects } from "./rect";

export function mergeRect(rect1: DOMRect, rect2: DOMRect) {
  if (rect1.top !== rect2.top || rect1.bottom !== rect2.bottom) {
    throw new Error("'mergeRect' find two rect not in a horizontal line");
  }

  return new DOMRect(
    Math.min(rect1.x, rect2.x),
    Math.min(rect1.y, rect2.y),
    rect1.width + rect2.width,
    rect1.height
  );
}

export function comparePoints(controller: Controller, point1: Point, point2: Point) {
  const pids = controller.getPids();
  if (point1.pid !== point2.pid) {
    const startPos = pids.indexOf(point1.pid);
    const endPos = pids.indexOf(point2.pid);
    if (startPos > endPos) {
      return 1;
    } else {
      return -1;
    }
  } else if (point1.offset > point2.offset) {
    return 1;
  } else if (point1.offset < point2.offset) {
    return -1;
  } else {
    return 0;
  }
}

export function minPoint(controller: Controller, ...points: Point[]) {
  const { length } = points;
  if (length === 0) {
    throw new Error("You need pass least one point");
  }

  if (length === 1) {
    return points[0];
  }

  let minOne = points[0];
  for (let i = 1; i < length; i++) {
    const item = points[i];

    const result = comparePoints(controller, minOne, item);
    if (result === 1) {
      minOne = item;
    }
  }
  return minOne;
}

export function maxPoint(controller: Controller, ...points: Point[]) {
  const { length } = points;
  if (length === 0) {
    throw new Error("You need pass least one point");
  }

  if (length === 1) {
    return points[0];
  }

  let maxOne = points[0];
  for (let i = 1; i < length; i++) {
    const item = points[i];

    const result = comparePoints(controller, maxOne, item);
    if (result === -1) {
      maxOne = item;
    }
  }
  return maxOne;
}

export function getOrderedRange(controller: Controller, range: Range) {
  const { start, end } = range;

  const getRevertRange = () => {
    return new Range({
      start: range.end,
      end: range.start,
    });
  };

  if (comparePoints(controller, start, end) === 1) {
    return getRevertRange();
  } else {
    return range;
  }
}

export function calcSelectionStyles(
  controller: Controller,
  extHooks: {
    getParagraphDOM: (pid: PID) => HTMLDivElement | null;
  }
) {
  const selection = controller.getCurrentSelection();

  if (!selection || selection.isCaret()) {
    return null;
  }

  const pids = controller.getPids();
  const effectKeys = getEffectKeys(pids, selection.range);
  const { getParagraphDOM } = extHooks;

  const rects: Record<PID, React.CSSProperties[]> = {};
  effectKeys.forEach(key => {
    const dom = getParagraphDOM(key);
    if (!dom) {
      return;
    }

    rects[key] = getSelectionRects(controller, selection.range, key, dom);
  });
  return rects;
}
