<script setup lang="ts">
import * as d3 from "d3";
import { computed, onMounted } from "vue";

// @ts-ignore
import colors from "@/colors.json";

export type CircleSectorProgress = "none" | "in_progress" | "finished";

export interface CircleSectorData {
  progress: CircleSectorProgress;
}

const props = defineProps<{
  sectors: CircleSectorData[];
}>();

onMounted(async () => {
  render();
});

interface CircleSector extends d3.PieArcDatum<number> {
  arrowStartAngle: number;
  arrowEndAngle: number;
  progress: CircleSectorProgress;
}

const pieData = computed(() => {
  const pieWeights = new Array(Math.max(props.sectors.length, 1)).fill(1);
  const pieGenerator = d3.pie();
  const angles = pieGenerator(pieWeights);
  return angles
    .map((angle) => {
      // Rotate the circle by PI (180 degrees) normally 0 = 12'o clock, now start at 6 o clock
      angle.startAngle += Math.PI;
      angle.endAngle += Math.PI;

      return Object.assign(
        {
          startAngle: angle.startAngle,
          endAngle: angle.endAngle,
          arrowStartAngle: angle.endAngle + (angle.startAngle - angle.endAngle) / 2,
          arrowEndAngle: angle.startAngle + (angle.startAngle - angle.endAngle) / 2,
          progress: props.sectors[angle.index].progress,
        },
        angle
      );
    })
    .reverse() as CircleSector[];
});

const width = 100;
const height = 100;
const radius = 50;

const svgId = computed(() => {
  // Generate a random id for the svg element like 'circle-visualization-ziurxxmp'
  return `circle-visualization-${Math.random()
    .toString(36)
    .replace(/[^a-z]+/g, "")
    .substring(2, 10)}`;
});

function getColor(sector: CircleSector) {
  let color = colors.gray[300];
  if ("in_progress" === sector.progress) {
    color = colors.sky[500];
  }
  if ("finished" === sector.progress) {
    color = colors.green[500];
  }
  return color;
}

function render() {
  const svg = d3.select("#" + svgId.value);
  // Clean svg before adding new stuff.
  svg.selectAll("*").remove();

  if (pieData.value) {
    const arrowStrokeWidth = 2;
    // Append marker as definition to the svg
    svg
      .attr("viewBox", `0 0 ${width} ${height}`)
      .append("svg:defs")
      .append("svg:marker")
      .attr("id", "triangle")
      .attr("refX", 11)
      .attr("refY", 11)
      .attr("markerWidth", 20)
      .attr("markerHeight", 20)
      .attr("markerUnits", "userSpaceOnUse")
      .attr("orient", "auto")
      .append("path")
      .attr("d", "M -1 0 l 10 0 M 0 -1 l 0 10")
      .attr("transform", "rotate(-90, 10, 0)")
      .attr("stroke-width", arrowStrokeWidth)
      .attr("stroke", colors.gray[500]);

    const g = svg
      .append("g")
      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

    // Generate the pie diagram wedge
    const wedgeGenerator = d3
      .arc()
      .innerRadius(radius / 2.5)
      .padAngle(12 / 360)
      .outerRadius(radius);

    const learningSequences = g
      .selectAll(".learningSegmentArc")
      .data(pieData.value)
      .enter()
      .append("g")
      .attr("class", "learningSegmentArc");

    learningSequences
      .transition()
      .duration(1)
      .attr("fill", (d) => {
        return getColor(d);
      });

    // @ts-ignore
    learningSequences.append("path").attr("d", wedgeGenerator);
  }
  return svg;
}
</script>

<template>
  <div class="svg-container content-center">
    <pre hidden>{{ pieData }}</pre>
    <pre hidden>{{ render() }}</pre>
    <svg :id="svgId" class="h-full min-w-[20px]">
      <circle :cx="width / 2" :cy="height / 2" :r="radius" :color="colors.gray[300]" />
      <circle :cx="width / 2" :cy="height / 2" :r="radius / 2.5" color="white" />
    </svg>
  </div>
</template>
