import {eq_vect, resolve_color, set_turtle_color, get_turtle_color, turtle_radius, rotate, turn_to_deg, command_to_state, turtle_init, background_color, turtle_angle, last} from "./turtle_geometry.js"

function hex (n) {
  return n.toString(16).padStart(2, "0")
}

function svg_render_line (prev, curr) {
  if (!prev.pendown) return ""
  if (eq_vect(prev.position, curr.position)) return ""
  const {position: [x1, y1], pencolor, penwidth} = prev
  const {position: [x2, y2]} = curr
  const [r, g, b, a] = resolve_color(pencolor)
  return `
    <line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="#${hex(r)}${hex(g)}${hex(b)}" stroke-linecap="round" stroke-opacity="${a/255}" stroke-width="${penwidth}"/>
    `
}

function escape_svg (svg) {
  return svg
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&apos;")
}

export function extract_ludus (svg) {
  const code = svg.split("<ludus>")[1]?.split("</ludus>")[0] ?? ""
  return code 
    .replace(/&amp;/g, "&")
    .replace(/&lt;/g, "<")
    .replace(/&gt;/g, ">")
    .replace(/&quot;/g, `"`)
    .replace(/&apos;/g, `'`)
}

function svg_render_path (states) {
  const path = []
  for (let i = 1; i < states.length; ++i) {
    const prev = states[i - 1]
    const curr = states[i]
    path.push(svg_render_line(prev, curr))
  }
  return path.join("")
}

function svg_render_turtle (state) {
  if (!state.visible) return ""
  const [fr, fg, fb, fa] = get_turtle_color()
  const fill_alpha = fa/255
  const {heading, pencolor, position: [x, y], pendown, penwidth} = state
  const origin = [0, turtle_radius]
  const [x1, y1] = origin
  const [x2, y2] = rotate(origin, turtle_angle)
  const [x3, y3] = rotate(origin, -turtle_angle)
  const [pr, pg, pb, pa] = resolve_color(pencolor)
  const pen_alpha = pa/255
  const ink = pendown ? `<line x1="${x1}" y1="${y1}" x2="0" y2="0" stroke="#${hex(pr)}${hex(pg)}${hex(pb)}" stroke-linecap="round" stroke-opacity="${pen_alpha}" stroke-width="${penwidth}" />` : ""
  return `
    <g transform="translate(${x}, ${y})rotate(${-turn_to_deg(heading)})">
      <polygon points="${x1} ${y1} ${x2} ${y2} ${x3} ${y3}" stroke="none" fill="#${hex(fr)}${hex(fg)}${hex(fb)})" fill-opacity="${fill_alpha}"/>
      ${ink}
    </g>
    `
}

// TODO: update this to match the new `p5` function
export function svg (commands, code) {
  const all_states = {}
  for (const command of commands) {
    const [turtle_id, _, this_command] = command
    let stack = all_states[turtle_id]
    if (!stack) {
      const new_stack = [turtle_init]
      all_states[turtle_id] = new_stack
      stack = new_stack
    }
    const prev_state = last(all_states[turtle_id])
    const new_state = command_to_state(prev_state, this_command)
    all_states[turtle_id].push(new_state)
  }
  let maxX = -Infinity, maxY = -Infinity, minX = Infinity, minY = Infinity
  for (const states of Object.values(all_states)) {
    for (const {position: [x, y]} of states) {
      maxX = Math.max(maxX, x)
      maxY = Math.max(maxY, y)
      minX = Math.min(minX, x)
      minY = Math.min(minY, y)
    }
  }
  const [r, g, b] = resolve_color(background_color)  
  if ((r+g+b)/3 > 128) set_turtle_color([0, 0, 0, 150])
  const view_width = (maxX - minX) * 1.2
  const view_height = (maxY - minY) * 1.2
  const margin = Math.max(view_width, view_height) * 0.1
  const x_origin = minX - margin
  const y_origin = -maxY - margin
  let path = ""
  let turtle = ""
  for (const states of Object.values(all_states)) {
    path = path + svg_render_path(states)
    turtle = svg_render_turtle(last(states))
  }
  return `<?xml version="1.0" standalone="no"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="${x_origin} ${y_origin} ${view_width} ${view_height}" width="10in" height="8in">

  <rect x="${x_origin - 5}" y="${y_origin - 5}" width="${view_width + 10}" height="${view_height + 10}" fill="#${hex(r)}${hex(g)}${hex(b)}" stroke-width="0" paint-order="fill" />

  <g transform="scale(-1, 1) rotate(180)">
    ${path}
    ${turtle}
  </g>

<ludus>
${escape_svg(code)}
</ludus>
</svg>
  `
}

