<template>
  <div class="tree-layout">
    <div class="seize back" v-if="ctx" :style="seizeStyle">
      <div
        class="tree-group-back"
        v-for="box in ctx.groupBoxs"
        :style="{
          top: box.bound.y + 'px',
          width: ctx.size.w + ctx.offset.x + 'px',
          height: box.bound.h + 'px',
        }"
      />
    </div>
    <svg
      :viewBox="`${ctx.offset.x} ${ctx.offset.y} ${ctx.size.w} ${ctx.size.h}`"
      v-if="ctx"
      :style="{ width: ctx.size.w + 'px', height: ctx.size.h + 'px' }"
      xmlns="http://www.w3.org/2000/svg"
    >
      <template v-for="box in ctx.boxs">
        <polyline
          v-for="line in box.lines"
          :points="line.join(',')"
          fill="none"
          :stroke="lineColor"
          :stroke-width="1"
        />
      </template>
      <template v-for="gbox in ctx.groupBoxs">
        <polyline
          :points="gbox.line.join(',')"
          fill="none"
          stroke-dasharray="3 3"
          :stroke="lineColor"
          :stroke-width="1"
        />
      </template>
    </svg>

    <div class="seize steps" :style="seizeStyle">
      <div
        class="tree-item-layout"
        v-for="(step, i) in fs.steps"
        :ref="(dom: HTMLDivElement) => setDom(dom, i)"
        :style="{
          ...getStepStyle(step),
          padding: margin.map((p) => p + 'px').join(' '),
        }"
      >
        <div class="tree-item-inner">
          <slot name="step" :data="step.raw" :start="ctx && ctx.offset" />
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { DataStepTree, flatSteps, getStepsTreeCtx, NStep } from "./helper-v2";
import { computed, reactive, onUpdated, ref, watch, onMounted } from "vue";
import { DataStep } from "./type";

const props = withDefaults(
  defineProps<{
    margin?: number[];
    data: DataStep[];
    lineColor?: string;
  }>(),
  {
    margin: () => [15, 15],
  }
);

const fs = computed(() => {
  return flatSteps(props.data);
});
const stepNodes = reactive([]) as HTMLDivElement[];

const getStepStyle = (step: NStep<DataStepTree<DataStep>>) => {
  if (!ctx.value) return {};
  const box = ctx.value.boxs.find((box) => box.step === step);
  return {
    left: box.offset.x + "px",
    top: box.offset.y + "px",
  };
};

const setDom = (dom: HTMLDivElement, ndx: number) => {
  if (loaded.value) {
    stepNodes[ndx] = dom;
  }
};

const loaded = ref(false);
watch(
  () => props,
  () => {
    stepNodes.length = 0;
    loaded.value = false;
  },
  { flush: "pre", deep: true }
);

onUpdated(() => (loaded.value = true));
onMounted(() => (loaded.value = true));

const ctx = computed(() => {
  if (stepNodes.length !== fs.value.steps.length || !loaded.value) return;
  const ctx = getStepsTreeCtx(
    fs.value.steps,
    props.margin,
    (step) => {
      const ndx = fs.value.steps.findIndex(({ raw }) => raw === step);
      const node = stepNodes[ndx];
      return { w: node.offsetWidth, h: node.offsetHeight };
    },
    fs.value.group
  );
  console.log(ctx);
  return ctx;
});

// 跟svg坐标系保持一致
const seizeStyle = computed(() => {
  if (!ctx.value) return {};
  return {
    left: -ctx.value.offset.x + "px",
    top: -ctx.value.offset.y + "px",
  };
});
</script>

<style lang="scss" scoped>
.tree-layout {
  display: inline-block;
  position: relative;
  overflow: hidden;

  .seize {
    left: 0;
    top: 0;
    width: 9000px;
    height: 9000px;
    position: absolute;
    pointer-events: none;

    &.steps {
      z-index: 2;
    }

    &.back {
      z-index: 1;
    }
  }

  svg {
    position: relative;
    z-index: 1;
  }
}

.tree-group-back {
  position: absolute;
  background-color: #f2f2f2;
  left: 0;
}

.tree-item-layout {
  position: absolute;
  box-sizing: border-box;

  .tree-item-inner {
    pointer-events: all;
  }
}
</style>
