<script setup lang="ts">
import { useCircleStore } from "@/stores/circle";
import type { DefaultArcObject } from "d3";
import * as d3 from "d3";
import pick from "lodash/pick";
import * as log from "loglevel";
import { computed, onMounted } from "vue";
import { showIcon } from "./learningSequenceUtils";

// @ts-ignore
import colors from "@/colors.json";
import type { LearningSequence } from "@/types";

const circleStore = useCircleStore();

function someFinished(learningSequence: LearningSequence) {
  if (circleStore.circle) {
    return circleStore.circle.someFinishedInLearningSequence(
      learningSequence.translation_key
    );
  }
  return false;
}

function allFinished(learningSequence: LearningSequence) {
  if (circleStore.circle) {
    return circleStore.circle.allFinishedInLearningSequence(
      learningSequence.translation_key
    );
  }
  return false;
}

onMounted(async () => {
  log.debug("CircleDiagram mounted");
  render();
});

interface CirclePie extends d3.PieArcDatum<number> {
  title: string;
  icon: string;
  slug: string;
  translation_key: string;
  arrowStartAngle: number;
  arrowEndAngle: number;
  someFinished: boolean;
  allFinished: boolean;
}

const pieData = computed(() => {
  const circle = circleStore.circle;

  if (circle) {
    const pieWeights = new Array(Math.max(circle.learningSequences.length, 1)).fill(1);
    const pieGenerator = d3.pie();
    const angles = pieGenerator(pieWeights);
    let result = angles.map((angle) => {
      const thisLearningSequence = circle.learningSequences[angle.index];

      // Rotate the cirlce 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,
          ...pick(thisLearningSequence, ["title", "icon", "translation_key", "slug"]),
          arrowStartAngle: angle.endAngle + (angle.startAngle - angle.endAngle) / 2,
          arrowEndAngle: angle.startAngle + (angle.startAngle - angle.endAngle) / 2,
          someFinished: someFinished(thisLearningSequence),
          allFinished: allFinished(thisLearningSequence),
        },
        angle
      );
    });
    result = result.reverse();
    return result as CirclePie[];
  }

  return undefined;
});

const width = 450;
const height = 450;
const radius = Math.min(width, height) / 2.4;

function getColor(d: CirclePie) {
  let color = colors.gray[300];
  if (d.someFinished) {
    color = colors.sky[500];
  }
  if (d.allFinished) {
    color = colors.green[500];
  }
  return color;
}

function getHoverColor(d: CirclePie) {
  let color = colors.gray[200];
  if (d.someFinished) {
    color = colors.sky[400];
  }
  if (d.allFinished) {
    color = colors.green[400];
  }
  return color;
}

function render() {
  const svg = d3.select(".circle-visualization");
  // 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 wede
    const wedgeGenerator = d3
      .arc()
      .innerRadius(radius / 2.5)
      .padAngle(12 / 360)
      .outerRadius(radius);

    // Generate the arrows
    const arrowRadius = radius * 1.1;

    const learningSequences = g
      .selectAll(".learningSegmentArc")
      .data(pieData.value)
      .enter()
      .append("g")
      .attr("class", "learningSegmentArc")
      .attr("role", "button")
      .attr("fill", colors.gray[300]);

    learningSequences
      .on("mouseover", function (d, i) {
        d3.select(this)
          .transition()
          .duration(200)
          .attr("fill", (d) => {
            // @ts-ignore
            return getHoverColor(d);
          });
      })
      .on("mouseout", function (d, i) {
        d3.select(this)
          .transition()
          .duration(200)
          .attr("fill", (d) => {
            // @ts-ignore
            return getColor(d);
          });
      })
      .on("click", function (d, elm) {
        log.info("clicked on ", d, elm);
        document.getElementById(elm.slug)?.scrollIntoView({ behavior: "smooth" });
      });

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

    // @ts-ignore
    learningSequences.append("path").attr("d", wedgeGenerator);

    const learningSequenceText = learningSequences
      .append("text")
      .attr("fill", colors.blue[900])
      .style("font-size", "15px")
      .text((d) => {
        return d.title;
      })
      .attr("transform", function (d) {
        let translate = wedgeGenerator.centroid(d as unknown as DefaultArcObject);
        translate = [translate[0], translate[1] + 20];
        return "translate(" + translate + ")";
      })
      .attr("class", "circlesText text-large font-bold")
      .style("text-anchor", "middle");

    const iconWidth = 25;

    const learningSequenceIcon = learningSequences
      .append("svg:image")
      .attr("xlink:href", (d) => {
        if (showIcon(d.icon)) {
          return "/static/icons/" + d.icon.replace("it-", "") + ".svg";
        }
        return "";
      })
      .attr("width", iconWidth)
      .attr("height", iconWidth)
      .attr("transform", function (d) {
        let translate = wedgeGenerator.centroid(d as unknown as DefaultArcObject);
        translate = [translate[0] - iconWidth / 2, translate[1] - iconWidth];
        return "translate(" + translate + ")";
      })
      .attr("class", "filter-blue-900");

    // Create Arrows
    const arrow = d3
      .arc()
      .innerRadius(arrowRadius)
      .outerRadius(arrowRadius + arrowStrokeWidth)
      .padAngle(20 / 360)
      .startAngle((d) => {
        return (d as unknown as CirclePie).arrowStartAngle;
      })
      .endAngle((d) => {
        return (d as unknown as CirclePie).arrowEndAngle;
      });

    const arrows = g
      .selectAll(".arrow")
      .data(pieData.value)
      .join("g")
      .attr("class", "arrow")
      .attr("marker-end", "url(#triangle)");

    // remove last arrow
    d3.selection.prototype.last = function () {
      const last = this.size() - 1;
      return d3.select(this.nodes()[last]);
    };

    const all_arows = g.selectAll(".arrow");
    // @ts-ignore
    all_arows.last().remove();

    //Draw arrow paths
    // @ts-ignore
    arrows.append("path").attr("fill", colors.gray[500]).attr("d", arrow);
  }
  return svg;
}
</script>

<template>
  <div class="svg-container h-full content-center">
    <pre hidden>{{ pieData }}</pre>
    <pre hidden>{{ render() }}</pre>
    <svg class="circle-visualization h-full">
      <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>
