// Local canvas rendering.
// Emit input events and receive draw calls seperately - these must be piped
// together externally if desired.

import { line, curveLinear } from "d3-shape"

import { canvas } from "./elements.js"

// TODO: switch to curve interpolation that respects mouse points based on velocity
const lineFn = line()
  .x((d) => d[0])
  .y((d) => d[1])
  .curve(curveLinear)

const pathElems = new Map()

export var stroke_colour = "blue"
export const STROKE_RADIUS = 2

export const input = new EventTarget()

export const renderPath = (id, points) => {
  let pathElem = pathElems.get(id)

  if (pathElem == null) {
    pathElem = document.createElementNS("http://www.w3.org/2000/svg", "g")

    pathElem.setAttribute("stroke", stroke_colour)
    pathElem.setAttribute("stroke-width", STROKE_RADIUS * 2)
    pathElem.setAttribute("fill", "none")
    pathElem.setAttribute("stroke-linecap", "round")
    pathElem.setAttribute("pointer-events", "none")

    canvas.appendChild(pathElem)
    pathElems.set(id, pathElem)
  }

  pathElem.innerHTML = ""

  if (points.length == 0) {
    return pathElem
  }

  // Push a fake path split to generate the last path
  points.push([-1, -1, false])

  let subpath = []

  for (const point of points) {
    if (point[0] === undefined) {
      continue
    }

    if (point[2] === false) {
      if (subpath.length == 1) {
        const subpathElem = document.createElementNS(
          "http://www.w3.org/2000/svg",
          "circle",
        )

        subpathElem.setAttribute("stroke", "none")
        subpathElem.setAttribute("fill", stroke_colour)
        subpathElem.setAttribute("cx", subpath[0][0])
        subpathElem.setAttribute("cy", subpath[0][1])
        subpathElem.setAttribute("r", STROKE_RADIUS)

        pathElem.appendChild(subpathElem)
      } else if (subpath.length > 0) {
        const subpathElem = document.createElementNS(
          "http://www.w3.org/2000/svg",
          "path",
        )

        subpathElem.setAttribute("d", lineFn(subpath))

        pathElem.appendChild(subpathElem)
      }

      subpath = []

      continue
    }

    subpath.push(point)
  }

  return pathElem
}

export const clear = () => {
  pathElems.clear()
  canvas.innerHTML = ""
}

// Note that the PointerEvent is passed as the detail in these 'stroke events'.
canvas.addEventListener("pointerdown", (e) => {
  if (e.buttons & 1) {
    input.dispatchEvent(new CustomEvent("strokestart", { detail: e }))
  }
})
canvas.addEventListener("pointerenter", (e) => {
  if (e.buttons & 1) {
    input.dispatchEvent(new CustomEvent("strokestart", { detail: e }))
  }
})
canvas.addEventListener("pointerup", (e) => {
  if (e.buttons & 1) {
    input.dispatchEvent(new CustomEvent("strokeend", { detail: e }))
  }
})
canvas.addEventListener("pointerleave", (e) => {
  if (e.buttons & 1) {
    input.dispatchEvent(new CustomEvent("strokeend", { detail: e }))
  }
})
canvas.addEventListener("pointermove", (e) => {
  if (e.buttons & 1) {
    input.dispatchEvent(new CustomEvent("strokemove", { detail: e }))
  }
})
canvas.addEventListener("touchmove", (e) => e.preventDefault())

export function setStrokeColour(colour) {
  stroke_colour = colour
}