<template>
  <Teleport :to="`#${DomOutMountId}`" v-if="stage">
    <transition name="mount-fade">
      <div class="mount-layout" v-if="show">
        <div :size="8" class="mount-controller">
          <div v-for="[key, val] in describeItems" :key="key" class="mount-item">
            <span class="label">{{ val.label }}</span>
            <component
              v-bind="describes[key].props"
              :value="
                'value' in describes[key] ? describes[key].value : data && data[key]
              "
              @update:value="(val: any) => updateValue(key, val)"
              @change="changeHandler"
              :is="propertyComponents[val.type]"
              :key="key"
            />
          </div>
        </div>
      </div>
    </transition>
  </Teleport>
</template>

<script lang="ts" setup>
import { computed, ref, watch } from "vue";
import { useStage } from "../hook/use-global-vars.ts";
import { useMode } from "../hook/use-status.ts";
import { PropertyDescribes, propertyComponents } from "./index.ts";
import { DC, EntityShape } from "@/deconstruction.js";
import { useMouseShapeStatus } from "../hook/use-mouse-status.ts";
import { DomOutMountId } from "@/constant/index.ts";
import { Mode } from "@/constant/mode.ts";
import { debounce } from "@/utils/shared.ts";

const props = defineProps<{
  show?: boolean;
  target: DC<EntityShape> | undefined;
  data?: Record<string, any>;
  describes: PropertyDescribes;
}>();
const emit = defineEmits<{ (e: "change"): void }>();

const describeItems = computed(() => {
  return Object.entries(props.describes).sort(
    ([_a, a], [_b, b]) => (b.sort || -1) - (a.sort || -1)
  );
});

const stage = useStage();
const status = useMouseShapeStatus(computed(() => props.target));
const mode = useMode();
const hidden = computed(
  () =>
    !props.show &&
    (!stage.value?.getStage() ||
      !props.target?.getNode() ||
      !status.value.active ||
      mode.value.has(Mode.draw) ||
      mode.value.has(Mode.draging))
);
const show = ref(false);
watch(
  hidden,
  debounce(() => {
    show.value = !hidden.value;
  }, 32)
);

let isUpdate = false;
const updateValue = (key: string, val: any) => {
  if ("value" in props.describes[key]) {
    props.describes[key].value = val;
  } else {
    props.data![key] = val;
  }
  isUpdate = true;
};

watch(hidden, (nHidden, oHidden) => {
  if (nHidden && nHidden !== oHidden && isUpdate) {
    isUpdate = false;
    emit("change");
  }
});

const changeHandler = () => {
  isUpdate = false;
  emit("change");
};
</script>

<style lang="scss" scoped>
.mount-layout {
  pointer-events: all;
  right: 0;
  top: 0;
  bottom: 0;
  position: absolute;
  border-left: 1px solid #e4e7ed;
  background-color: rgba(255, 255, 255, 0.7);
  overflow-y: auto;
  padding: 6px 12px;
  color: #303133;
  width: 240px;
  font-size: 12px;
  box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
  overflow: hidden;

  .mount-controller {
    // display: grid;
    // grid-template-columns: auto 1fr;
    // gap: 10px 0;
    // align-items: center;

    .mount-item {
      margin-bottom: 15px;
      display: flex;
      flex-wrap: wrap;
      align-items: center;
    }

    .label {
      display: block;
      margin-right: 10px;
      color: #303133;

      &::after {
        content: ":";
      }
    }
  }
}

.mount-fade-enter-active,
.mount-fade-leave-active {
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.mount-fade-enter-from,
.mount-fade-leave-to {
  transform: translateX(100%);
  opacity: 0;
}
</style>
