<script setup>
import { Effect } from "effect";
import { computed } from "vue";
import { cel as _rawCel } from "../utils/cel";
import { celBindings, injectCELContext } from "../utils/cel-context";
import { DEFAULT_GAP } from "./layout";
defineOptions({ name: "ShwfedSlotRenderer" });
const props = defineProps({
  slotValue: { type: Object, required: true },
  configure: { type: Function, required: true },
  findEntry: { type: Function, required: true }
});
const emit = defineEmits(["update:slotValue"]);
const inherited = injectCELContext();
const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
function pickLayout(sets) {
  if (sets.length === 0) return void 0;
  for (const set of sets) {
    if (!set.media) return set;
    try {
      if (Effect.runSync($cel(set.media))) return set;
    } catch (err) {
      console.error(`[shwfed-slot-renderer] failed to evaluate layout media for ${set.name}:`, err);
    }
  }
  return sets[sets.length - 1];
}
const activeLayout = computed(() => pickLayout(props.slotValue.layouts));
const gridStyle = computed(() => {
  const l = activeLayout.value?.layout;
  if (!l) return "";
  const tracks = (n, min) => `repeat(${n}, minmax(${min}, 1fr))`;
  const gap = `calc(${l.gap ?? DEFAULT_GAP} * 0.25rem)`;
  const colGap = l.columns > 1 ? `min(${gap}, calc(100% / ${l.columns - 1}))` : gap;
  const parts = [
    "display: grid",
    `grid-template-columns: ${tracks(l.columns, "0")}`,
    l.rows ? `grid-template-rows: ${tracks(l.rows, "auto")}` : "",
    `column-gap: ${colGap}`,
    `row-gap: ${gap}`,
    l.style ?? ""
  ].filter(Boolean);
  return parts.join("; ");
});
function cellStyle(placement) {
  const [[x1, y1], [x2, y2]] = placement.area;
  const parts = [`grid-column: ${x1} / ${x2}`, `grid-row: ${y1} / ${y2}`, "min-width: 0"];
  const h = placement.h && placement.h !== "stretch" ? placement.h : null;
  const v = placement.v && placement.v !== "stretch" ? placement.v : null;
  if (h || v) {
    parts.push("display: flex");
    const toFlex = (a) => a === "start" ? "flex-start" : a === "end" ? "flex-end" : "center";
    if (h) parts.push(`justify-content: ${toFlex(h)}`);
    if (v) parts.push(`align-items: ${toFlex(v)}`);
  }
  return parts.join("; ");
}
const warnedMissing = /* @__PURE__ */ new Set();
const rendered = computed(() => {
  const layout = activeLayout.value?.layout;
  if (!layout) return [];
  const out = [];
  for (const b of props.slotValue.blocks) {
    const block = b;
    const placement = layout.placements[block.id];
    if (!placement) continue;
    const entry = props.findEntry(block.type, block.compatibilityDate);
    if (!entry) {
      const key = `${block.type}@${block.compatibilityDate}`;
      if (!warnedMissing.has(key)) {
        warnedMissing.add(key);
        console.warn(`[shwfed-slot-renderer] no registered block type for ${key}`);
      }
      continue;
    }
    out.push({
      key: block.id,
      style: cellStyle(placement),
      component: entry.runtime,
      block
    });
  }
  return out;
});
function updateBlock(id, next) {
  const blocks = props.slotValue.blocks.map((b) => b.id === id ? next : b);
  emit("update:slotValue", { ...props.slotValue, blocks });
}
</script>

<template>
  <div
    :style="gridStyle"
    :class="rendered.length === 0 && $slots.empty ? 'min-h-32 grid place-items-center text-xs text-zinc-400 select-none' : ''"
  >
    <slot
      v-if="rendered.length === 0"
      name="empty"
    />
    <div
      v-for="r in rendered"
      :key="r.key"
      :style="r.style"
    >
      <component
        :is="r.component"
        :block="r.block"
        :configure="configure"
        @update:block="(next) => updateBlock(r.block.id, next)"
      />
    </div>
  </div>
</template>
