<script setup>
import { Icon } from "@iconify/vue";
import { Effect } from "effect";
import { computed, ref } from "vue";
import { useI18n } from "vue-i18n";
import { cel as _rawCel } from "../../../../../utils/cel";
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
import { getLocalizedText } from "../../../../../share/locale";
import { interpolate } from "../../../../../utils/interpolate";
import { InputGroupButton } from "../../../../ui/input-group";
import { Markdown } from "../../../../ui/markdown";
import FormUnitRenderer from "../../../FormUnitRenderer.vue";
import { useValidationProvider } from "../../../utils/validation";
defineOptions({ name: "ShwfedCollapsibleFieldRuntime" });
const props = defineProps({
  fieldId: { type: String, required: true },
  config: { type: null, required: true }
});
const { locale } = useI18n();
const collapsed = ref(props.config.defaultCollapsed ?? false);
function toggle() {
  collapsed.value = !collapsed.value;
}
const inherited = injectCELContext();
const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
const headerSource = computed(() => {
  const template = getLocalizedText(props.config.header, locale.value) ?? "";
  if (!template) return "";
  return interpolate(template, (expression) => {
    try {
      const out = Effect.runSync($cel(expression));
      return out == null ? "" : String(out);
    } catch (err) {
      console.error(
        `[shwfed-form] collapsible: failed to evaluate header expression \`${expression}\` for ${props.fieldId}:`,
        err
      );
      return "";
    }
  });
});
function evaluateMedia(expression) {
  return Effect.runSync($cel(expression));
}
function isHidden(field) {
  const hidden = field.hidden;
  if (!hidden) return false;
  try {
    return Effect.runSync($cel(hidden));
  } catch (err) {
    console.error(`[shwfed-form] collapsible: failed to evaluate hidden for ${field.id}:`, err);
    return false;
  }
}
const validation = useValidationProvider();
function collectFieldIds(fields) {
  const ids = [];
  for (const field of fields) {
    ids.push(field.id);
    const unit = field.unit;
    if (unit?.fields) ids.push(...collectFieldIds(unit.fields));
  }
  return ids;
}
const childResults = computed(
  () => validation?.revealed.value ? validation.resultsFor(collectFieldIds(props.config.unit.fields)) : []
);
const errorCount = computed(() => childResults.value.filter((r) => r.severity === "error").length);
const warningCount = computed(() => childResults.value.filter((r) => r.severity === "warning").length);
</script>

<template>
  <!-- Mirrors the list-row card frame (`rounded border bg-zinc-50/40 p-3`)
       so collapsibles and list rows share a visual language for nested
       containers. The toggle chevron is its own `InputGroupButton`, matching
       the list row's collapse affordance — header text is clickable
       *targets* of focus, but only the chevron toggles. -->
  <div
    data-slot="collapsible-section"
    class="relative rounded border border-zinc-200 bg-zinc-50/40 p-3"
  >
    <div class="flex items-center gap-2">
      <InputGroupButton
        size="icon-xs"
        class="shrink-0"
        data-slot="collapsible-toggle"
        :aria-expanded="!collapsed"
        :aria-label="collapsed ? '\u5C55\u5F00' : '\u6298\u53E0'"
        @click="toggle"
      >
        <Icon
          :icon="collapsed ? 'fluent:chevron-right-20-regular' : 'fluent:chevron-down-20-regular'"
        />
      </InputGroupButton>
      <div
        class="min-w-0 flex-1"
        data-slot="collapsible-header"
      >
        <Markdown
          :source="headerSource"
          class="prose prose-sm prose-zinc max-w-none"
        />
      </div>
      <span
        v-if="errorCount > 0"
        data-slot="collapsible-error-count"
        class="shrink-0 text-xs text-red-600"
      >{{ errorCount }} 个错误</span>
      <span
        v-else-if="warningCount > 0"
        data-slot="collapsible-warning-count"
        class="shrink-0 text-xs text-amber-600"
      >{{ warningCount }} 个警告</span>
    </div>

    <!-- `v-show` (not `v-if`) so children stay mounted while collapsed:
         derived expressions keep running, commit-bus drafts stay live, and
         readonly inheritance keeps flowing. The parent grid's row track
         relies on this field's `metadata.h.grow = true` to shrink the
         collapsed section to its header height. -->
    <div
      v-show="!collapsed"
      data-slot="collapsible-body"
      class="mt-3 min-w-0"
    >
      <FormUnitRenderer
        :unit="config.unit"
        :evaluate-media="evaluateMedia"
        :is-hidden="isHidden"
      />
    </div>
  </div>
</template>
