import { getBoxToBoxArrow } from 'perfect-arrows';
import { FolkBaseConnection } from './folk-base-connection.ts';
import { getSvgPathFromStroke, pointsOnBezierCurves } from './common/utils.ts';
import { getStroke, StrokeOptions } from 'perfect-freehand';
import { PropertyValues } from '@lit/reactive-element';

export type Arrow = [
  /** The x position of the (padded) starting point. */
  sx: number,
  /** The y position of the (padded) starting point. */
  sy: number,
  /** The x position of the control point. */
  cx: number,
  /** The y position of the control point. */
  cy: number,
  /** The x position of the (padded) ending point. */
  ex: number,
  /** The y position of the (padded) ending point. */
  ey: number,
  /** The angle (in radians) for an ending arrowhead. */
  ae: number,
  /** The angle (in radians) for a starting arrowhead. */
  as: number,
  /** The angle (in radians) for a center arrowhead. */
  ac: number
];

declare global {
  interface HTMLElementTagNameMap {
    'folk-arrow': FolkArrow;
  }
}

export class FolkArrow extends FolkBaseConnection {
  static override tagName = 'folk-arrow';

  #options: StrokeOptions = {
    size: 7,
    thinning: 0.5,
    smoothing: 0.5,
    streamline: 0.5,
    simulatePressure: true,
    // TODO: figure out how to expose these as attributes
    easing: (t) => t,
    start: {
      taper: 50,
      easing: (t) => t,
      cap: true,
    },
    end: {
      taper: 0,
      easing: (t) => t,
      cap: true,
    },
  };

  override update(changedProperties: PropertyValues<this>) {
    super.update(changedProperties);

    const { sourceRect, targetRect } = this;

    if (sourceRect === null || targetRect === null) {
      this.style.clipPath = '';
      this.style.display = 'none';
      return;
    }

    this.style.display = '';

    const [sx, sy, cx, cy, ex, ey] = getBoxToBoxArrow(
      sourceRect.x,
      sourceRect.y,
      sourceRect.width,
      sourceRect.height,
      targetRect.x,
      targetRect.y,
      targetRect.width,
      targetRect.height
    ) as Arrow;

    const points = pointsOnBezierCurves([
      { x: sx, y: sy },
      { x: cx, y: cy },
      { x: ex, y: ey },
      { x: ex, y: ey },
    ]);

    const stroke = getStroke(points, this.#options);
    const path = getSvgPathFromStroke(stroke);
    this.style.clipPath = `path('${path}')`;
    this.style.backgroundColor = 'black';
  }
}
