import { Point, pointsOnBezierCurves, simplify } from 'points-on-curve';
import { parsePath, absolutize, normalize } from 'path-data-parser';

export { Point } from 'points-on-curve';

export function pointsOnPath(path: string, tolerance?: number, distance?: number): Point[][] {
  const segments = parsePath(path);
  const normalized = normalize(absolutize(segments));

  const sets: Point[][] = [];
  let currentPoints: Point[] = [];
  let start: Point = [0, 0];
  let pendingCurve: Point[] = [];

  const appendPendingCurve = () => {
    if (pendingCurve.length >= 4) {
      currentPoints.push(...pointsOnBezierCurves(pendingCurve, tolerance));
    }
    pendingCurve = [];
  };

  const appendPendingPoints = () => {
    appendPendingCurve();
    if (currentPoints.length) {
      sets.push(currentPoints);
      currentPoints = [];
    }
  };

  for (const { key, data } of normalized) {
    switch (key) {
      case 'M':
        appendPendingPoints();
        start = [data[0], data[1]];
        currentPoints.push(start);
        break;
      case 'L':
        appendPendingCurve();
        currentPoints.push([data[0], data[1]]);
        break;
      case 'C':
        if (!pendingCurve.length) {
          const lastPoint = currentPoints.length ? currentPoints[currentPoints.length - 1] : start;
          pendingCurve.push([lastPoint[0], lastPoint[1]]);
        }
        pendingCurve.push([data[0], data[1]]);
        pendingCurve.push([data[2], data[3]]);
        pendingCurve.push([data[4], data[5]]);
        break;
      case 'Z':
        appendPendingCurve();
        currentPoints.push([start[0], start[1]]);
        break;
    }
  }
  appendPendingPoints();

  if (!distance) {
    return sets;
  }

  const out: Point[][] = [];
  for (const set of sets) {
    const simplifiedSet = simplify(set, distance);
    if (simplifiedSet.length) {
      out.push(simplifiedSet);
    }
  }
  return out;
}