<script setup>
import { computed, ref, watch } from "vue";
import { Effect } from "effect";
import { useI18n } from "vue-i18n";
import { useHead } from "#app";
import { getLocalizedText } from "../../share/locale";
import { cel } from "../../utils/cel";
import { celBindings, injectCELContext } from "../../utils/cel-context";
import SlotRenderer from "../../share/slot-renderer.vue";
import ShwfedModal from "../modal.vue";
import EditorBody from "./config.vue";
import EditorBreadcrumb from "./breadcrumb.vue";
import EditorFooter from "./footer.vue";
import { provideEventTarget } from "../../share/event-bus";
import { PAGE_TARGET_ID, createPageConfig } from "./schema";
import { useConfigEditor } from "./use-editor";
import { findBlock } from "./utils/resolve";
defineOptions({ name: "ShwfedConfig" });
const configModel = defineModel("config", { type: null });
const config = computed({
  get: () => configModel.value ?? createPageConfig(),
  set: (next) => {
    configModel.value = next;
  }
});
const props = defineProps({
  configure: { type: Function, required: false },
  editable: { type: Boolean, required: false }
});
const inheritedCEL = injectCELContext();
const hostConfigure = props.configure ?? (() => {
});
const mergedConfigure = (env) => {
  hostConfigure(env);
  const existing = new Set(env.getDefinitions().variables.map((v) => v.name));
  for (const [name, v] of Object.entries(inheritedCEL)) {
    if (existing.has(name)) continue;
    env.registerVariable(name, v.type, { description: v.description, label: v.label });
  }
};
class PageClosed {
  _tag = "PageClosed";
}
provideEventTarget(PAGE_TARGET_ID, {
  close: () => Effect.gen(function* () {
    window.close();
    return yield* Effect.die(new PageClosed());
  })
});
const editorOpen = ref(false);
const editorState = useConfigEditor(config, {
  configure: mergedConfigure,
  onClose: () => {
    editorOpen.value = false;
  }
});
watch(editorOpen, (open, prev) => {
  if (open && !prev) editorState.reset();
});
function onGridClick(event) {
  if (!props.editable) return;
  if (!event.metaKey && !event.ctrlKey) return;
  event.preventDefault();
  event.stopPropagation();
  editorOpen.value = true;
}
function updateSlot(next) {
  config.value = { ...config.value, slot: next };
}
const pageStyle = computed(() => {
  const expression = config.value.style;
  if (!expression) return void 0;
  try {
    const r = Effect.runSync(cel(expression, celBindings(inheritedCEL)));
    if (r === null || r === void 0) return void 0;
    if (typeof r === "string") return r;
    if (typeof r === "object") return r;
    return String(r);
  } catch {
    return void 0;
  }
});
const { locale } = useI18n({ useScope: "global", inheritLocale: true });
useHead(() => {
  const title = getLocalizedText(config.value.title, locale.value);
  return title ? { title } : {};
});
</script>

<template>
  <ClientOnly>
    <div
      :class="pageStyle ? '' : 'contents'"
      :style="pageStyle"
      @click.capture="onGridClick"
    >
      <SlotRenderer
        :slot-value="config.slot"
        :configure="mergedConfigure"
        :find-entry="findBlock"
        @update:slot-value="updateSlot"
      >
        <template
          v-if="editable"
          #empty
        >
          meta+click 进入编辑
        </template>
      </SlotRenderer>
    </div>
    <ShwfedModal
      v-if="editable"
      v-model:open="editorOpen"
      content-width="90vw"
      :dismissible="true"
    >
      <template #title>
        <EditorBreadcrumb :state="editorState" />
      </template>
      <template #description>
        <span class="sr-only">编辑页面布局与块配置</span>
      </template>
      <EditorBody :state="editorState" />
      <template #footer>
        <EditorFooter
          :state="editorState"
          @close="editorOpen = false"
        />
      </template>
    </ShwfedModal>
  </ClientOnly>
</template>
