<script setup>
import { computed, inject, onBeforeUnmount, ref, watch } from "vue";
import { Schema } from "effect";
import { Icon } from "@iconify/vue";
import BlockLayoutEditor from "../../../../block-layout-editor/index.vue";
import LayoutsSidebar from "../../../../block-layout-editor/sidebar.vue";
import LayoutMetaStrip from "../../../../block-layout-editor/meta-strip.vue";
import { Button } from "../../../../ui/button";
import { ExpressionEditor } from "../../../../ui/expression-editor";
import { Field, FieldLabel } from "../../../../ui/field";
import { InputGroup, InputGroupInput, InputGroupNumberField } from "../../../../ui/input-group";
import { Locale as LocaleField } from "../../../../ui/locale";
import { Markdown } from "../../../../ui/markdown";
import { ScrollArea } from "../../../../ui/scroll-area";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue
} from "../../../../ui/select";
import { Separator } from "../../../../ui/separator";
import { Switch } from "../../../../ui/switch";
import { BREADCRUMB_EXTENSION_KEY } from "../../../breadcrumb-extension";
import { findBlock } from "../../../utils/resolve";
import { useSlotEditor, useSlotClipboard } from "../../../use-editor";
import {
  BADGE_VARIANTS,
  badgeSchema,
  getStructFieldDescription,
  getStructFieldTitle,
  JSON_VAR,
  schema
} from "./schema";
defineOptions({ name: "ShwfedBlockCardConfig" });
const block = defineModel({ type: null, ...{ required: true } });
const props = defineProps({
  configure: { type: Function, required: false }
});
const configure = computed(() => props.configure ?? (() => {
}));
const blockSchema = schema(() => {
}, Schema.Any);
const badgeSchemaObj = badgeSchema(() => {
});
const fieldTitle = (f) => getStructFieldTitle(blockSchema, f) ?? f;
const fieldDescription = (f) => getStructFieldDescription(blockSchema, f);
const badgeTitle = (f) => getStructFieldTitle(badgeSchemaObj, f) ?? f;
const badgeDescription = (f) => getStructFieldDescription(badgeSchemaObj, f);
const BADGE_VARIANT_LABELS = {
  default: "\u9ED8\u8BA4",
  secondary: "\u6B21\u8981",
  destructive: "\u8B66\u793A",
  outline: "\u63CF\u8FB9"
};
const slotAccessor = computed({
  get: () => block.value.slot,
  set: (next) => {
    block.value = { ...block.value, slot: next };
  }
});
const editor = useSlotEditor(slotAccessor, { configure: configure.value });
const { copy: copyBlocks, paste: pasteBlocks } = useSlotClipboard(editor);
const viewMode = ref("general");
function selectContent() {
  viewMode.value = "content";
  drilledBlockId.value = null;
}
function selectBadge() {
  viewMode.value = "badge";
  drilledBlockId.value = null;
}
function selectGeneral() {
  viewMode.value = "general";
  drilledBlockId.value = null;
}
function setDisplayName(v) {
  const s = String(v ?? "");
  block.value = { ...block.value, displayName: s.length > 0 ? s : void 0 };
}
function setStyle(v) {
  block.value = { ...block.value, style: v.trim().length > 0 ? v : void 0 };
}
function setUrl(v) {
  block.value = { ...block.value, url: v.trim().length > 0 ? v : void 0 };
}
const badge = computed(() => block.value.badge ?? {});
function isLocaleBlank(v) {
  return !v || v.every((item) => item.message.trim().length === 0);
}
function patchBadge(patch) {
  const next = { ...badge.value, ...patch };
  const cleaned = {};
  for (const [k, v] of Object.entries(next)) {
    if (v !== void 0) cleaned[k] = v;
  }
  block.value = {
    ...block.value,
    badge: Object.keys(cleaned).length > 0 ? cleaned : void 0
  };
}
function setBadgeRequest(v) {
  patchBadge({ request: v.trim().length > 0 ? v : void 0 });
}
function setBadgeContent(v) {
  patchBadge({ content: isLocaleBlank(v) ? void 0 : v });
}
function setBadgeShow(v) {
  patchBadge({ show: v.trim().length > 0 ? v : void 0 });
}
function setBadgeInterval(v) {
  patchBadge({ interval: typeof v === "number" && v > 0 ? Math.round(v) : void 0 });
}
function setBadgeDot(v) {
  patchBadge({ dot: v ? true : void 0 });
}
function setBadgeVariant(v) {
  const s = typeof v === "string" ? v : "default";
  patchBadge({ variant: s === "default" ? void 0 : s });
}
function selectLayout(index) {
  editor.activeLayoutIndex.value = index;
  viewMode.value = "content";
  drilledBlockId.value = null;
}
function addLayout() {
  const cur = editor.layouts.value;
  editor.layouts.value = [
    ...cur,
    { name: "\u65B0\u5E03\u5C40", layout: { columns: 1, placements: {} } }
  ];
  editor.activeLayoutIndex.value = cur.length;
  viewMode.value = "content";
}
function addBlock(entry, options) {
  editor.addBlock(entry, options);
}
const drilledBlockId = ref(null);
const drilledBlock = computed(() => {
  const id = drilledBlockId.value;
  if (!id) return null;
  return editor.blocks.value.find((b) => b.id === id) ?? null;
});
const drilledEntry = computed(() => {
  const b = drilledBlock.value;
  return b ? findBlock(b.type, b.compatibilityDate) ?? null : null;
});
function onDrillDown(id) {
  drilledBlockId.value = id;
}
function popDrill() {
  drilledBlockId.value = null;
}
watch(
  () => editor.blocks.value.map((b) => b.id),
  (ids) => {
    const id = drilledBlockId.value;
    if (id && !ids.includes(id)) drilledBlockId.value = null;
  }
);
function updateDrilledBlock(next) {
  const id = drilledBlockId.value;
  if (!id) return;
  editor.updateBlock(id, next);
}
const breadcrumbExt = inject(BREADCRUMB_EXTENSION_KEY, null);
if (breadcrumbExt) {
  const blockCrumb = breadcrumbExt.add();
  watch(
    drilledBlock,
    (drilled) => {
      if (drilled) {
        blockCrumb.label.value = editor.getBlockLabel(drilled);
        blockCrumb.back.value = popDrill;
      } else {
        blockCrumb.label.value = null;
        blockCrumb.back.value = null;
      }
    },
    { immediate: true }
  );
  onBeforeUnmount(() => {
    blockCrumb.dispose();
  });
}
</script>

<template>
  <div class="flex min-w-0 gap-2 min-h-128">
    <!-- Left rail: setting rows (top) + the slot's layouts (bottom). Hidden
         while drilled into a child block so the drilled view owns the width. -->
    <div
      v-if="!drilledBlockId"
      class="flex w-56 shrink-0 flex-col"
    >
      <div
        class="row pl-2"
        :class="viewMode === 'general' ? 'bg-[color-mix(in_srgb,var(--primary)_10%,white)] text-(--primary)' : 'text-zinc-700 hover:bg-zinc-50'"
        @click="selectGeneral()"
      >
        <Icon
          icon="fluent:settings-20-regular"
          class="size-4 shrink-0"
        />
        <span class="flex-1 truncate">通用配置</span>
      </div>

      <div
        class="row pl-2"
        :class="viewMode === 'content' ? 'bg-[color-mix(in_srgb,var(--primary)_10%,white)] text-(--primary)' : 'text-zinc-700 hover:bg-zinc-50'"
        @click="selectContent()"
      >
        <Icon
          icon="fluent:apps-list-20-regular"
          class="size-4 shrink-0"
        />
        <span class="flex-1 truncate">内容</span>
      </div>

      <div
        class="row pl-2"
        :class="viewMode === 'badge' ? 'bg-[color-mix(in_srgb,var(--primary)_10%,white)] text-(--primary)' : 'text-zinc-700 hover:bg-zinc-50'"
        @click="selectBadge()"
      >
        <Icon
          icon="fluent:badge-20-regular"
          class="size-4 shrink-0"
        />
        <span class="flex-1 truncate">徽章</span>
      </div>

      <Separator class="my-2" />

      <!-- Layouts of the slot -->
      <div class="flex flex-1 min-h-0 flex-col">
        <ScrollArea class="flex-1">
          <LayoutsSidebar
            :model-value="editor.layouts.value"
            :active-index="editor.activeLayoutIndex.value"
            @update:model-value="(v) => {
  editor.layouts.value = v;
}"
            @update:active-index="selectLayout"
          />
        </ScrollArea>
        <Button
          variant="ghost"
          size="sm"
          class="w-full justify-start"
          @click="addLayout()"
        >
          <Icon
            icon="fluent:add-20-regular"
            class="size-4"
          />
          <span>新增布局</span>
        </Button>
      </div>
    </div>

    <!-- Right pane -->
    <div class="flex min-w-0 flex-1 flex-col gap-3">
      <!-- Drilled into a child block -->
      <template v-if="drilledBlockId">
        <div
          v-if="!drilledBlock"
          class="flex min-h-96 items-center justify-center p-8 text-sm text-zinc-400"
        >
          块已不存在
        </div>
        <div v-else-if="drilledEntry">
          <component
            :is="drilledEntry.config"
            :model-value="drilledBlock"
            :configure="configure"
            @update:model-value="(next) => updateDrilledBlock(next)"
          />
        </div>
        <div
          v-else
          class="p-6 text-sm text-red-500"
        >
          未注册的块类型：{{ drilledBlock.type }}@{{ drilledBlock.compatibilityDate }}
        </div>
      </template>

      <!-- General block-level settings. -->
      <template v-else-if="viewMode === 'general'">
        <Field orientation="vertical">
          <FieldLabel class="text-xs text-zinc-500">
            <template
              v-if="fieldDescription('displayName')"
              #tooltip
            >
              <Markdown
                :source="fieldDescription('displayName')"
                block
                class="prose prose-sm prose-zinc"
              />
            </template>
            {{ fieldTitle("displayName") }}
          </FieldLabel>
          <InputGroup>
            <InputGroupInput
              :model-value="block.displayName ?? ''"
              placeholder="例：概览卡片"
              @update:model-value="setDisplayName"
            />
          </InputGroup>
        </Field>

        <Field orientation="vertical">
          <FieldLabel class="text-xs text-zinc-500">
            <template
              v-if="fieldDescription('style')"
              #tooltip
            >
              <Markdown
                :source="fieldDescription('style')"
                block
                class="prose prose-sm prose-zinc"
              />
            </template>
            {{ fieldTitle("style") }}
          </FieldLabel>
          <ExpressionEditor
            :model-value="block.style ?? ''"
            placeholder="返回 CSS 字符串或样式对象的表达式，如 'padding: 2rem'"
            multiline
            class="min-h-16"
            @update:model-value="(v) => setStyle(v)"
          />
        </Field>

        <Field orientation="vertical">
          <FieldLabel class="text-xs text-zinc-500">
            <template
              v-if="fieldDescription('url')"
              #tooltip
            >
              <Markdown
                :source="fieldDescription('url')"
                block
                class="prose prose-sm prose-zinc"
              />
            </template>
            {{ fieldTitle("url") }}
          </FieldLabel>
          <ExpressionEditor
            :model-value="block.url ?? ''"
            placeholder="可选；返回链接的表达式，如 '/detail/' + string(row.id)"
            result-type="string"
            @update:model-value="(v) => setUrl(v)"
          />
        </Field>
      </template>

      <!-- Badge settings. -->
      <template v-else-if="viewMode === 'badge'">
        <Field orientation="vertical">
          <FieldLabel class="text-xs text-zinc-500">
            <template
              v-if="badgeDescription('request')"
              #tooltip
            >
              <Markdown
                :source="badgeDescription('request')"
                block
                class="prose prose-sm prose-zinc"
              />
            </template>
            {{ badgeTitle("request") }}
          </FieldLabel>
          <ExpressionEditor
            :model-value="badge.request ?? ''"
            placeholder="可选；如 http.get('/api/notifications')"
            result-type="HttpRequest"
            multiline
            class="min-h-20"
            @update:model-value="(v) => setBadgeRequest(v)"
          />
        </Field>

        <Field orientation="vertical">
          <FieldLabel class="text-xs text-zinc-500">
            <template
              v-if="badgeDescription('content')"
              #tooltip
            >
              <Markdown
                :source="badgeDescription('content')"
                block
                class="prose prose-sm prose-zinc"
              />
            </template>
            {{ badgeTitle("content") }}
          </FieldLabel>
          <LocaleField
            markdown
            translate-hint="card badge content"
            :model-value="badge.content"
            @update:model-value="setBadgeContent"
          />
        </Field>

        <Field orientation="vertical">
          <FieldLabel class="text-xs text-zinc-500">
            <template
              v-if="badgeDescription('show')"
              #tooltip
            >
              <Markdown
                :source="badgeDescription('show')"
                block
                class="prose prose-sm prose-zinc"
              />
            </template>
            {{ badgeTitle("show") }}
          </FieldLabel>
          <ExpressionEditor
            :model-value="badge.show ?? ''"
            placeholder="例：json.?data.?total.orValue(0) != 0"
            result-type="bool"
            :extra-vars="{ json: JSON_VAR }"
            multiline
            class="min-h-12"
            @update:model-value="(v) => setBadgeShow(v)"
          />
        </Field>

        <div class="grid grid-cols-2 gap-3">
          <Field orientation="vertical">
            <FieldLabel class="text-xs text-zinc-500">
              <template
                v-if="badgeDescription('interval')"
                #tooltip
              >
                <Markdown
                  :source="badgeDescription('interval')"
                  block
                  class="prose prose-sm prose-zinc"
                />
              </template>
              {{ badgeTitle("interval") }}
            </FieldLabel>
            <InputGroup>
              <InputGroupNumberField
                :model-value="badge.interval"
                :min="1"
                @update:model-value="(v) => setBadgeInterval(v)"
              />
            </InputGroup>
          </Field>

          <Field orientation="vertical">
            <FieldLabel class="text-xs text-zinc-500">
              <template
                v-if="badgeDescription('variant')"
                #tooltip
              >
                <Markdown
                  :source="badgeDescription('variant')"
                  block
                  class="prose prose-sm prose-zinc"
                />
              </template>
              {{ badgeTitle("variant") }}
            </FieldLabel>
            <Select
              :model-value="badge.variant ?? 'default'"
              @update:model-value="setBadgeVariant"
            >
              <SelectTrigger class="w-full">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem
                  v-for="opt in BADGE_VARIANTS"
                  :key="opt"
                  :value="opt"
                >
                  {{ BADGE_VARIANT_LABELS[opt] }}
                </SelectItem>
              </SelectContent>
            </Select>
          </Field>
        </div>

        <Field orientation="horizontal">
          <FieldLabel class="text-xs text-zinc-500">
            <template
              v-if="badgeDescription('dot')"
              #tooltip
            >
              <Markdown
                :source="badgeDescription('dot')"
                block
                class="prose prose-sm prose-zinc"
              />
            </template>
            {{ badgeTitle("dot") }}
          </FieldLabel>
          <Switch
            :model-value="badge.dot ?? false"
            @update:model-value="setBadgeDot"
          />
        </Field>
      </template>

      <!-- Content: slot layout editor. -->
      <template v-else>
        <LayoutMetaStrip
          :model-value="editor.layouts.value"
          :index="editor.activeLayoutIndex.value"
          @update:model-value="(v) => {
  editor.layouts.value = v;
}"
        />
        <div class="flex-1">
          <BlockLayoutEditor
            :model-value="editor.layouts.value"
            :active-index="editor.activeLayoutIndex.value"
            :selected-item-ids="editor.selectedBlockIds.value"
            :items="editor.blocks.value"
            :find-entry="editor.findBlockMeta"
            :get-item-label="editor.getBlockLabel"
            :picker-entries="editor.pickerEntries.value"
            :can-delete="true"
            item-noun="块"
            @update:model-value="(v) => {
  editor.layouts.value = v;
}"
            @update:active-index="(v) => {
  editor.activeLayoutIndex.value = v;
}"
            @update:selected-item-ids="(v) => {
  editor.selectedBlockIds.value = v;
}"
            @add-new="addBlock"
            @drill-down="onDrillDown"
            @delete-item="(id) => editor.removeBlock(id)"
            @delete-items="(ids) => editor.removeBlocks(ids)"
            @copy-items="copyBlocks"
            @paste="pasteBlocks"
          />
        </div>
      </template>
    </div>
  </div>
</template>

<style scoped>
.row{align-items:center;border-radius:.25rem;cursor:pointer;display:flex;font-size:.875rem;gap:.375rem;padding-block:.375rem;padding-left:.5rem;padding-right:.5rem;position:relative;transition:background-color .1s ease;-webkit-user-select:none;-moz-user-select:none;user-select:none}
</style>
