<script setup>
import { shallowRef, computed, watch, onMounted, onUnmounted, provide } from "vue";
import { SELECTION_CONTEXT_KEY } from "../types";
const emit = defineEmits(["select"]);
const registeredFreeform = shallowRef(null);
let lassoStart = null;
const selectionState = computed(() => registeredFreeform.value?.selectionState.value ?? null);
const isLassoActive = computed(() => selectionState.value?.lassoActive ?? false);
const lassoRect = computed(() => selectionState.value?.lassoRect ?? null);
const selectedItems = computed(() => selectionState.value?.items ?? []);
watch(selectedItems, (items) => {
  emit("select", [...items]);
}, { deep: true });
function startLasso(event) {
  if (!registeredFreeform.value) return;
  if (registeredFreeform.value.disabled.value) return;
  if (event.button !== 0) return;
  lassoStart = { x: event.clientX, y: event.clientY };
  const initialRect = { x: event.clientX, y: event.clientY, width: 0, height: 0 };
  document.body.style.userSelect = "none";
  const state = registeredFreeform.value.selectionState.value;
  state.lassoActive = true;
  state.lassoRect = initialRect;
  state.items = [];
}
function handleLassoMove(event) {
  if (!registeredFreeform.value || !isLassoActive.value || !lassoStart) return;
  const currentX = event.clientX;
  const currentY = event.clientY;
  const rect = {
    x: Math.min(lassoStart.x, currentX),
    y: Math.min(lassoStart.y, currentY),
    width: Math.abs(currentX - lassoStart.x),
    height: Math.abs(currentY - lassoStart.y)
  };
  const { items, itemElements } = registeredFreeform.value;
  const foundItems = [];
  for (const [id, element] of itemElements) {
    if (isElementInRect(element, rect)) {
      const item = items.value.find((i) => i.id === id);
      if (item) {
        foundItems.push(item);
      }
    }
  }
  const state = registeredFreeform.value.selectionState.value;
  state.lassoRect = rect;
  state.items = foundItems;
}
function isElementInRect(element, rect) {
  const elRect = element.getBoundingClientRect();
  return !(elRect.right < rect.x || elRect.left > rect.x + rect.width || elRect.bottom < rect.y || elRect.top > rect.y + rect.height);
}
function endLasso() {
  lassoStart = null;
  document.body.style.userSelect = "";
  if (registeredFreeform.value) {
    const state = registeredFreeform.value.selectionState.value;
    state.lassoActive = false;
    state.lassoRect = null;
  }
}
function onPointerDown(event) {
  const target = event.target;
  if (target.closest("[data-freeform-item]")) return;
  startLasso(event);
}
function onPointerMove(event) {
  if (isLassoActive.value) {
    handleLassoMove(event);
  }
}
function onPointerUp() {
  if (isLassoActive.value) {
    endLasso();
  }
}
provide(SELECTION_CONTEXT_KEY, {
  registerFreeform: (ctx) => {
    registeredFreeform.value = ctx;
  },
  unregisterFreeform: () => {
    registeredFreeform.value = null;
  }
});
const lassoStyle = computed(() => {
  if (!lassoRect.value) return { display: "none" };
  return {
    position: "fixed",
    left: `${lassoRect.value.x}px`,
    top: `${lassoRect.value.y}px`,
    width: `${lassoRect.value.width}px`,
    height: `${lassoRect.value.height}px`,
    pointerEvents: "none",
    zIndex: 9998
  };
});
onMounted(() => {
  document.addEventListener("pointerdown", onPointerDown);
  document.addEventListener("pointermove", onPointerMove);
  document.addEventListener("pointerup", onPointerUp);
  document.addEventListener("pointercancel", onPointerUp);
});
onUnmounted(() => {
  document.removeEventListener("pointerdown", onPointerDown);
  document.removeEventListener("pointermove", onPointerMove);
  document.removeEventListener("pointerup", onPointerUp);
  document.removeEventListener("pointercancel", onPointerUp);
});
</script>

<template>
  <div class="freeform-selection">
    <slot
      :is-lasso-active="isLassoActive"
      :lasso-rect="lassoRect"
      :selected="selectedItems"
    />

    <!-- Lasso Selection Box -->
    <Teleport to="body">
      <div
        v-if="isLassoActive && lassoRect"
        :style="lassoStyle"
      >
        <slot
          name="lasso"
          :rect="lassoRect"
          :selected-count="selectedItems.length"
        >
          <div class="freeform-lasso" />
        </slot>
      </div>
    </Teleport>
  </div>
</template>

<style>
.freeform-selection{display:contents}.freeform-lasso{background:color-mix(in srgb,var(--freeform-color-primary) 10%,transparent);border:1px dashed var(--freeform-color-primary);height:100%;width:100%}
</style>
