<script lang="ts">
  import UpObject from "../components/display/UpObject.svelte";
  import { queryOnce } from "../lib/api";
  import Selector from "../components/utils/Selector.svelte";
  import * as d3 from "d3";
  import { onMount } from "svelte";
  import type { D3ZoomEvent, ZoomTransform } from "d3";

  const urlSearch = window.location.href.substring(
    window.location.href.indexOf("?")
  );
  const urlParams = new URLSearchParams(urlSearch);

  let x: string = urlParams.get("x");
  let y: string = urlParams.get("y");

  interface IPoint {
    address: string;
    x: number;
    y: number;
  }
  let points: IPoint[] = [];

  $: {
    if (x && y) {
      points = [];
      queryOnce(`(matches ? (in "${x}" "${y}") ?)`).then((result) => {
        points = Object.entries(result.objects)
          .map(([address, obj]) => {
            let objX = parseInt(String(obj.get(x)));
            let objY = parseInt(String(obj.get(y)));

            if (objX && objY) {
              return {
                address,
                x: objX,
                y: objY,
              };
            }
          })
          .filter(Boolean);
      });
    }
  }

  onMount(() => {
    const view = d3.select(".view");
    const { width, height } = (
      view.node() as HTMLElement
    ).getBoundingClientRect();

    const svg = view.append("svg");

    const xScale = d3.scaleLinear().domain([0, width]).range([0, width]);

    const xAxis = d3
      .axisBottom(xScale)
      .ticks(15)
      .tickSize(height)
      .tickPadding(5 - height);

    const yScale = d3.scaleLinear().domain([0, height]).range([0, height]);

    const yAxis = d3
      .axisRight(yScale)
      .ticks(height / (width / 15))
      .tickSize(width)
      .tickPadding(5 - width);

    const gX = svg.append("g").attr("class", "axis axis--x").call(xAxis);
    const gY = svg.append("g").attr("class", "axis axis--y").call(yAxis);

    const zoom = d3
      .zoom()
      // .scaleExtent([1, 40])
      // .translateExtent([
      //   [-100, -100],
      //   [width + 90, height + 100],
      // ])
      .on("zoom", zoomed);

    function zoomed({ transform }: { transform: ZoomTransform }) {
      const points = d3.select(".points");
      points.style(
        "transform",
        `translate(${transform.x}px, ${transform.y}px) scale(${transform.k})`
      );
      const allPoints = d3.selectAll(".point");
      allPoints.style("transform", `scale(${1 / transform.k})`);

      gX.call(xAxis.scale(transform.rescaleX(xScale)));
      gY.call(yAxis.scale(transform.rescaleY(yScale)));
    }

    function reset() {
      svg.transition().duration(750).call(zoom.transform, d3.zoomIdentity);
    }

    d3.select(".view").call(zoom);
  });
</script>

<div class="surface">
  <div class="header">
    <div class="axis-selector">
      X: <Selector type="attribute" bind:attribute={x} />
    </div>
    <div class="axis-selector">
      Y: <Selector type="attribute" bind:attribute={y} />
    </div>
  </div>
  <div class="view">
    <div class="points">
      {#each points as point}
        <div class="point" style="left: {point.x}px; top: {point.y}px">
          <div class="inner">
            <UpObject point link address={point.address} />
          </div>
        </div>
      {/each}
    </div>
  </div>
</div>

<style lang="scss">
  .surface {
    display: flex;
    flex-direction: column;
    height: 100%;
  }

  .header {
    display: flex;
    gap: 2em;
    padding: 1em;
    border-bottom: 1px solid var(--foreground);

    .axis-selector {
      display: flex;
      gap: 1em;
      align-items: center;
    }
  }

  .view {
    flex-grow: 1;
    position: relative;

    overflow: hidden;

    :global(svg) {
      width: 100%;
      height: 100%;
    }

    :global(.tick text) {
      color: var(--foreground-lightest);
      font-size: 1rem;
    }

    .points {
      transform-origin: 0 0;
    }

    .point {
      position: absolute;
      transform-origin: 0 0;

      .inner {
        transform: translate(-50%, -50%);
      }
    }
  }
</style>
