import { beforeEach, describe, expect, it } from "vitest"
import { mount } from "@vue/test-utils"
import { createPinia, setActivePinia } from "pinia"
import FormBuilder from "./FormBuilder.vue"
import {
  __resetFormBuilderIdCounter,
  tabContainerId,
  useFormBuilderStore,
} from "@/stores/formBuilderStore"

const BUILDER_ID = "fb-test"

interface TabBag {
  id: string
  label: string
  elementList?: string[]
}
function elBag(id: string): Record<string, unknown> {
  const store = useFormBuilderStore()
  return store.getSchema(BUILDER_ID).elements[id] as unknown as Record<
    string,
    unknown
  >
}
function tabsOf(id: string): TabBag[] {
  return (elBag(id).tabs as TabBag[] | undefined) ?? []
}

describe("FormBuilder", () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    __resetFormBuilderIdCounter()
  })

  it("renders the three-pane layout", () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    expect(wrapper.find("[data-testid='form-builder-palette']").exists()).toBe(
      true,
    )
    expect(wrapper.find("[data-testid='form-builder-canvas']").exists()).toBe(
      true,
    )
    expect(
      wrapper.find("[data-testid='form-builder-inspector']").exists(),
    ).toBe(true)
  })

  it("shows an empty-state hint on the canvas when there are no elements", () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    expect(
      wrapper.find("[data-testid='form-builder-canvas-empty']").exists(),
    ).toBe(true)
  })

  it("lists every registered element type in the palette", () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    const palette = wrapper.find("[data-testid='form-builder-palette']")
    for (const type of [
      "action",
      "boolean",
      "builder",
      "code",
      "configuration-block",
      "display",
      "editor",
      "file",
      "input",
      "option-select",
      "picker",
    ]) {
      expect(
        palette.find(`[data-testid='form-builder-palette-${type}']`).exists(),
      ).toBe(true)
    }
  })

  it("expanding a group reveals its style items", async () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    // Style items are hidden until the group is expanded.
    expect(
      wrapper.find("[data-testid='form-builder-palette-input-text']").exists(),
    ).toBe(false)
    await wrapper
      .find("[data-testid='form-builder-palette-input']")
      .trigger("click")
    expect(
      wrapper.find("[data-testid='form-builder-palette-input-text']").exists(),
    ).toBe(true)
  })

  it("searching auto-expands matching groups to reveal their items", async () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    // Collapsed by default — the text style is hidden.
    expect(
      wrapper.find("[data-testid='form-builder-palette-input-text']").exists(),
    ).toBe(false)

    await wrapper.find("input[type='search']").setValue("text")
    // The matching style is now visible without manually expanding the group.
    expect(
      wrapper.find("[data-testid='form-builder-palette-input-text']").exists(),
    ).toBe(true)

    // Clearing the search collapses groups again.
    await wrapper.find("input[type='search']").setValue("")
    expect(
      wrapper.find("[data-testid='form-builder-palette-input-text']").exists(),
    ).toBe(false)
  })

  it("clicking a style item appends an element and selects it", async () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    // Expand the input group, then click the "text" style.
    await wrapper
      .find("[data-testid='form-builder-palette-input']")
      .trigger("click")
    await wrapper
      .find("[data-testid='form-builder-palette-input-text']")
      .trigger("click")

    const store = useFormBuilderStore()
    const schema = store.getSchema(BUILDER_ID)
    const rootList =
      (schema.cards[schema.rootCardId] as unknown as Record<string, unknown>)
        .elementList as string[]
    expect(rootList).toHaveLength(1)
    expect(schema.elements[rootList[0]!]!.type).toBe("input.text")
    expect(
      wrapper.find("[data-testid='form-builder-inspector-fields']").exists(),
    ).toBe(true)
  })

  it("editing the label patches the schema", async () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    await wrapper
      .find("[data-testid='form-builder-palette-input']")
      .trigger("click")
    await wrapper
      .find("[data-testid='form-builder-palette-input-text']")
      .trigger("click")
    await wrapper
      .find("[data-testid='form-builder-inspector-label']")
      .setValue("First name")

    const store = useFormBuilderStore()
    const schema = store.getSchema(BUILDER_ID)
    const rootList =
      (schema.cards[schema.rootCardId] as unknown as Record<string, unknown>)
        .elementList as string[]
    expect(schema.elements[rootList[0]!]!.label).toBe("First name")
  })

  it("removes the selected element when Remove is clicked", async () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    await wrapper
      .find("[data-testid='form-builder-palette-input']")
      .trigger("click")
    await wrapper
      .find("[data-testid='form-builder-palette-input-text']")
      .trigger("click")
    await wrapper.find("[data-testid='form-builder-remove']").trigger("click")

    const store = useFormBuilderStore()
    const schema = store.getSchema(BUILDER_ID)
    const rootList =
      (schema.cards[schema.rootCardId] as unknown as Record<string, unknown>)
        .elementList as string[]
    expect(rootList).toHaveLength(0)
    expect(Object.keys(schema.elements)).toHaveLength(0)
  })

  it("reorders an element when move-up is clicked", async () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    // Add input.text
    await wrapper
      .find("[data-testid='form-builder-palette-input']")
      .trigger("click")
    await wrapper
      .find("[data-testid='form-builder-palette-input-text']")
      .trigger("click")
    // Add display.type
    await wrapper
      .find("[data-testid='form-builder-palette-display']")
      .trigger("click")
    await wrapper
      .find("[data-testid='form-builder-palette-display-type']")
      .trigger("click")

    const store = useFormBuilderStore()
    const schema = store.getSchema(BUILDER_ID)
    const rootList = () =>
      ((schema.cards[schema.rootCardId] as unknown as Record<string, unknown>)
        .elementList as string[])

    expect(rootList()).toHaveLength(2)
    const initial = [...rootList()]
    // The second click selected the display element. Move it up.
    await wrapper
      .find("[data-testid='form-builder-move-up']")
      .trigger("click")
    const reordered = rootList()
    expect(reordered[0]).toBe(initial[1])
    expect(reordered[1]).toBe(initial[0])
  })

  it("loads an existing schema from modelValue on mount", () => {
    const existingSchema = {
      rootCardId: "preloaded-root",
      cards: {
        "preloaded-root": {
          id: "preloaded-root",
          cardType: "element-list",
          elementList: ["preloaded-el"],
        },
      },
      elements: {
        "preloaded-el": {
          id: "preloaded-el",
          type: "input.text",
          name: "preloaded",
          label: "Preloaded element",
        },
      },
    } as never
    mount(FormBuilder, {
      props: {
        builderId: BUILDER_ID,
        modelValue: existingSchema,
      },
    })

    // Verifying the store state is sufficient; the async CardRenderer +
    // ElementRenderer chain that actually paints the element is covered
    // by Suspense-wrapped integration tests elsewhere.
    const store = useFormBuilderStore()
    const schema = store.getSchema(BUILDER_ID)
    expect(schema.rootCardId).toBe("preloaded-root")
    expect(schema.elements["preloaded-el"]?.label).toBe("Preloaded element")
    const rootList =
      (schema.cards["preloaded-root"] as unknown as Record<string, unknown>)
        .elementList as string[]
    expect(rootList).toEqual(["preloaded-el"])
  })

  it("emits update:modelValue on schema mutation", async () => {
    const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
    await wrapper
      .find("[data-testid='form-builder-palette-input']")
      .trigger("click")
    await wrapper
      .find("[data-testid='form-builder-palette-input-text']")
      .trigger("click")
    await wrapper.vm.$nextTick()

    const emitted = wrapper.emitted("update:modelValue")
    expect(emitted).toBeTruthy()
    // The latest emission carries the full schema with one element.
    const last = emitted![emitted!.length - 1] as unknown[]
    const schema = last[0] as { elements: Record<string, unknown> }
    expect(Object.keys(schema.elements).length).toBe(1)
  })

  describe("suggestedFields", () => {
    const suggested = [
      { type: "input.email", name: "email", label: "Email", defaultValue: "" },
      {
        type: "input.text",
        name: "first_name",
        label: "First name",
        defaultValue: "Jane",
      },
      { type: "input.text", name: "age", label: "Age", defaultValue: 0 },
    ]

    function rootList(): string[] {
      const store = useFormBuilderStore()
      const schema = store.getSchema(BUILDER_ID)
      return (
        schema.cards[schema.rootCardId] as unknown as Record<string, unknown>
      ).elementList as string[]
    }

    it("hides the nav button when no suggested fields are provided", () => {
      const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      expect(
        wrapper.find("[data-testid='form-builder-nav-suggested']").exists(),
      ).toBe(false)
    })

    it("shows the nav button when suggested fields are provided", () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, suggestedFields: suggested },
      })
      expect(
        wrapper.find("[data-testid='form-builder-nav-suggested']").exists(),
      ).toBe(true)
    })

    it("lists suggested fields alphabetically by label when none are in the form", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, suggestedFields: suggested },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-suggested']")
        .trigger("click")

      const items = wrapper
        .find("[data-testid='form-builder-suggested']")
        .findAll("[data-testid^='form-builder-suggested-']")
      // Age, Email, First name
      expect(items.map((i) => i.text().replace(/\s+/g, " ").trim())).toEqual([
        "Age",
        "Email",
        "First name",
      ])
    })

    it("adding a suggested field prefills name, label, and defaultValue", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, suggestedFields: suggested },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-suggested']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-suggested-first_name']")
        .trigger("click")

      const store = useFormBuilderStore()
      const schema = store.getSchema(BUILDER_ID)
      const el = schema.elements[rootList()[0]!]! as unknown as Record<
        string,
        unknown
      >
      expect(el.type).toBe("input.text")
      expect(el.name).toBe("first_name")
      expect(el.label).toBe("First name")
      expect(el.defaultValue).toBe("Jane")
    })

    it("mutes and sorts already-added fields to the bottom", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, suggestedFields: suggested },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-suggested']")
        .trigger("click")
      // Add "Email" → its name now exists in the form.
      await wrapper
        .find("[data-testid='form-builder-suggested-email']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      const items = wrapper
        .find("[data-testid='form-builder-suggested']")
        .findAll("[data-testid^='form-builder-suggested-']")
      // Available (Age, First name) first, then the muted Email at the end.
      const last = items[items.length - 1]!
      expect(last.attributes("data-testid")).toBe(
        "form-builder-suggested-email",
      )
      expect(last.attributes("data-in-form")).toBe("true")
      expect(last.classes()).toContain("opacity-50")
    })

    it("'Browse all fields' navigates to the palette panel", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, suggestedFields: suggested },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-suggested']")
        .trigger("click")
      expect(wrapper.find("[data-testid='form-builder-suggested']").exists()).toBe(
        true,
      )
      await wrapper
        .find("[data-testid='form-builder-browse-all']")
        .trigger("click")

      // Now the default element palette is shown, not the suggested list.
      expect(wrapper.find("[data-testid='form-builder-palette']").exists()).toBe(
        true,
      )
      expect(wrapper.find("[data-testid='form-builder-suggested']").exists()).toBe(
        false,
      )
    })

    it("shows the suggested nav button first in the nav rail", () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, suggestedFields: suggested },
      })
      const navButtons = wrapper
        .find("[data-testid='form-builder-nav']")
        .findAll("button")
      expect(navButtons[0]!.attributes("data-testid")).toBe(
        "form-builder-nav-suggested",
      )
    })

    it("badges the nav button with the unused suggested-field count", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, suggestedFields: suggested },
      })
      // All three are unused initially.
      let badge = wrapper.find(
        "[data-testid='form-builder-nav-suggested-badge']",
      )
      expect(badge.exists()).toBe(true)
      expect(badge.text()).toBe("3")

      // Add one suggested field → count drops to 2.
      await wrapper
        .find("[data-testid='form-builder-nav-suggested']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-suggested-email']")
        .trigger("click")
      await wrapper.vm.$nextTick()
      badge = wrapper.find("[data-testid='form-builder-nav-suggested-badge']")
      expect(badge.text()).toBe("2")
    })

    it("hides the badge when every suggested field is already in the form", async () => {
      const wrapper = mount(FormBuilder, {
        props: {
          builderId: BUILDER_ID,
          suggestedFields: [
            {
              type: "input.text",
              name: "first_name",
              label: "First name",
              defaultValue: "",
            },
          ],
          modelValue: {
            rootCardId: "root",
            cards: {
              root: {
                id: "root",
                cardType: "element-list",
                elementList: ["e1"],
              },
            },
            elements: {
              e1: {
                id: "e1",
                type: "input.text",
                name: "first_name",
                label: "First name",
              },
            },
          } as never,
        },
      })
      // loadSchema runs in onMounted, which re-renders on the next tick.
      await wrapper.vm.$nextTick()
      expect(
        wrapper
          .find("[data-testid='form-builder-nav-suggested-badge']")
          .exists(),
      ).toBe(false)
    })

    it("allows re-adding an already-added field (muted but still clickable)", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, suggestedFields: suggested },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-suggested']")
        .trigger("click")
      // Add Email once, then again while it's muted.
      await wrapper
        .find("[data-testid='form-builder-suggested-email']")
        .trigger("click")
      await wrapper.vm.$nextTick()
      const muted = wrapper.find("[data-testid='form-builder-suggested-email']")
      expect(muted.attributes("data-in-form")).toBe("true")
      await muted.trigger("click")

      // Both email elements exist in the form.
      const store = useFormBuilderStore()
      const schema = store.getSchema(BUILDER_ID)
      const emailCount = Object.values(schema.elements).filter(
        (el) => (el as unknown as Record<string, unknown>).name === "email",
      ).length
      expect(emailCount).toBe(2)
    })
  })

  describe("tab container (card.tab)", () => {
    function rootId(): string {
      return useFormBuilderStore().getSchema(BUILDER_ID).rootCardId
    }

    it("seeds a default tab when a card.tab element is added", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      const tabCardId = store.addElement(BUILDER_ID, rootId(), "card.tab")
      const tabs = tabsOf(tabCardId)
      expect(tabs).toHaveLength(1)
      expect(tabs[0]!.label).toBe("Tab 1")
    })

    it("adds elements into a tab via the composite container id", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      const tabCardId = store.addElement(BUILDER_ID, rootId(), "card.tab")
      const tabId = tabsOf(tabCardId)[0]!.id
      const childId = store.addElement(
        BUILDER_ID,
        tabContainerId(tabCardId, tabId),
        "input.text",
      )
      expect(tabsOf(tabCardId)[0]!.elementList).toContain(childId)
    })

    it("addTab / updateTab / reorderTab manage the tabs array", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      const tabCardId = store.addElement(BUILDER_ID, rootId(), "card.tab")
      const t2 = store.addTab(BUILDER_ID, tabCardId, "Second")
      expect(tabsOf(tabCardId).map((t) => t.label)).toEqual(["Tab 1", "Second"])

      store.updateTab(BUILDER_ID, tabCardId, t2, { label: "Renamed" })
      expect(tabsOf(tabCardId)[1]!.label).toBe("Renamed")

      store.reorderTab(BUILDER_ID, tabCardId, 1, 0)
      expect(tabsOf(tabCardId).map((t) => t.label)).toEqual([
        "Renamed",
        "Tab 1",
      ])
    })

    it("removeTab cascade-deletes the tab's child elements", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      const tabCardId = store.addElement(BUILDER_ID, rootId(), "card.tab")
      const tabId = tabsOf(tabCardId)[0]!.id
      const childId = store.addElement(
        BUILDER_ID,
        tabContainerId(tabCardId, tabId),
        "input.text",
      )
      store.removeTab(BUILDER_ID, tabCardId, tabId)
      const schema = store.getSchema(BUILDER_ID)
      expect(tabsOf(tabCardId)).toHaveLength(0)
      expect(schema.elements[childId]).toBeUndefined()
    })

    it("removing the tab card cascades all tab children", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      const tabCardId = store.addElement(BUILDER_ID, rootId(), "card.tab")
      const tabId = tabsOf(tabCardId)[0]!.id
      const childId = store.addElement(
        BUILDER_ID,
        tabContainerId(tabCardId, tabId),
        "input.text",
      )
      store.removeElement(BUILDER_ID, tabCardId)
      const schema = store.getSchema(BUILDER_ID)
      expect(schema.elements[tabCardId]).toBeUndefined()
      expect(schema.elements[childId]).toBeUndefined()
    })

    it("inspector shows a tabs editor for a selected card.tab", async () => {
      const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      // Card / Layout Block group → Tab Container style.
      await wrapper
        .find("[data-testid='form-builder-palette-card']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-palette-card-tab']")
        .trigger("click")

      expect(
        wrapper.find("[data-testid='form-builder-tabs-editor']").exists(),
      ).toBe(true)
      // Add a tab through the inspector.
      await wrapper
        .find("[data-testid='form-builder-tabs-add']")
        .trigger("click")
      const store = useFormBuilderStore()
      const tabCardId = store.getSchema(BUILDER_ID).rootCardId
      const cardId = (
        store.getSchema(BUILDER_ID).cards[tabCardId] as unknown as Record<
          string,
          unknown
        >
      ).elementList as string[]
      expect(tabsOf(cardId[0]!)).toHaveLength(2)
    })

    it("zooming into a tab card edits the active tab's element list", async () => {
      const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      const store = useFormBuilderStore()
      const rootId = store.getSchema(BUILDER_ID).rootCardId
      const tabCardId = store.addElement(BUILDER_ID, rootId, "card.tab")
      const tabId = tabsOf(tabCardId)[0]!.id
      // Pre-seed an element inside the first tab.
      const seeded = store.addElement(
        BUILDER_ID,
        tabContainerId(tabCardId, tabId),
        "input.text",
      )
      store.select(BUILDER_ID, "element", tabCardId)
      await wrapper.vm.$nextTick()

      // Zoom into the tab card.
      await wrapper
        .find("[data-testid='form-builder-zoom-in']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      // The seeded element renders in the zoomed canvas (not empty).
      expect(
        wrapper.find(`[data-testid='form-builder-row-${seeded}']`).exists(),
      ).toBe(true)
      // A tab switcher appears in the breadcrumb.
      expect(
        wrapper.find(`[data-testid='form-builder-zoom-tab-${tabId}']`).exists(),
      ).toBe(true)
    })

    it("zoom breadcrumb cog opens tab settings and renames the active tab", async () => {
      const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      const store = useFormBuilderStore()
      const rootId = store.getSchema(BUILDER_ID).rootCardId
      const tabCardId = store.addElement(BUILDER_ID, rootId, "card.tab")
      const tabId = tabsOf(tabCardId)[0]!.id
      store.select(BUILDER_ID, "element", tabCardId)
      await wrapper.vm.$nextTick()
      await wrapper
        .find("[data-testid='form-builder-zoom-in']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      expect(
        wrapper
          .find("[data-testid='form-builder-zoom-tab-settings-panel']")
          .exists(),
      ).toBe(false)
      await wrapper
        .find("[data-testid='form-builder-zoom-tab-settings']")
        .trigger("click")
      expect(
        wrapper
          .find("[data-testid='form-builder-zoom-tab-settings-panel']")
          .exists(),
      ).toBe(true)

      await wrapper
        .find("[data-testid='form-builder-zoom-tab-settings-label']")
        .setValue("Details")
      const tab = tabsOf(tabCardId).find((t) => t.id === tabId)!
      expect(tab.label).toBe("Details")
    })

    it("reorders card.tab tabs by dragging rows in the inspector editor", async () => {
      const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      await wrapper
        .find("[data-testid='form-builder-palette-card']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-palette-card-tab']")
        .trigger("click")
      // Add a second tab so there are two to reorder.
      await wrapper
        .find("[data-testid='form-builder-tabs-add']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      const store = useFormBuilderStore()
      const cardId = (
        store.getSchema(BUILDER_ID).cards[
          store.getSchema(BUILDER_ID).rootCardId
        ] as unknown as Record<string, unknown>
      ).elementList as string[]
      const tabCardId = cardId[0]!
      const before = tabsOf(tabCardId).map((t) => t.id)
      expect(before).toHaveLength(2)

      await wrapper
        .find(`[data-testid='form-builder-tab-drag-${before[1]}']`)
        .trigger("dragstart")
      await wrapper
        .find(`[data-testid='form-builder-tab-row-${before[0]}']`)
        .trigger("drop")

      expect(tabsOf(tabCardId).map((t) => t.id)).toEqual([
        before[1],
        before[0],
      ])
    })

    it("renders tab headers in the canvas", async () => {
      const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      await wrapper
        .find("[data-testid='form-builder-palette-card']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-palette-card-tab']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      const store = useFormBuilderStore()
      const rootCardId = store.getSchema(BUILDER_ID).rootCardId
      const tabCardId = (
        (
          store.getSchema(BUILDER_ID).cards[rootCardId] as unknown as Record<
            string,
            unknown
          >
        ).elementList as string[]
      )[0]!
      const firstTabId = tabsOf(tabCardId)[0]!.id
      expect(
        wrapper
          .find(`[data-testid='form-builder-canvas-tab-${firstTabId}']`)
          .exists(),
      ).toBe(true)
    })
  })

  describe("rootTabsContainer", () => {
    function rootCardBag(): Record<string, unknown> {
      const store = useFormBuilderStore()
      const schema = store.getSchema(BUILDER_ID)
      return schema.cards[schema.rootCardId] as unknown as Record<
        string,
        unknown
      >
    }
    function rootTabIds(): string[] {
      return (rootCardBag().tabList as string[] | undefined) ?? []
    }

    it("does not render the chrome bar by default", () => {
      const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      expect(
        wrapper.find("[data-testid='form-builder-root-tabs']").exists(),
      ).toBe(false)
    })

    it("converts the root into a tab-list with one tab on mount", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, rootTabsContainer: true },
      })
      await wrapper.vm.$nextTick()
      expect(rootCardBag().cardType).toBe("tab-list")
      expect(rootTabIds()).toHaveLength(1)
      expect(
        wrapper.find("[data-testid='form-builder-root-tabs']").exists(),
      ).toBe(true)
    })

    it("renders a chrome bar button per tab plus an add button", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, rootTabsContainer: true },
      })
      await wrapper.vm.$nextTick()
      const firstTab = rootTabIds()[0]!
      expect(
        wrapper
          .find(`[data-testid='form-builder-root-tab-${firstTab}']`)
          .exists(),
      ).toBe(true)
      expect(
        wrapper.find("[data-testid='form-builder-root-tab-add']").exists(),
      ).toBe(true)
    })

    it("the + button adds a tab and switches the canvas to it", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, rootTabsContainer: true },
      })
      await wrapper.vm.$nextTick()
      await wrapper
        .find("[data-testid='form-builder-root-tab-add']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      const tabs = rootTabIds()
      expect(tabs).toHaveLength(2)
      // Adding an element now lands in the new (second) tab's element list.
      await wrapper
        .find("[data-testid='form-builder-palette-input']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-palette-input-text']")
        .trigger("click")

      const store = useFormBuilderStore()
      const secondTab = store.getSchema(BUILDER_ID).cards[
        tabs[1]!
      ] as unknown as Record<string, unknown>
      expect((secondTab.elementList as string[]).length).toBe(1)
    })

    it("switching tabs changes which element list the canvas edits", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, rootTabsContainer: true },
      })
      await wrapper.vm.$nextTick()
      const store = useFormBuilderStore()
      const firstTab = rootTabIds()[0]!

      // Add an element to tab 1.
      await wrapper
        .find("[data-testid='form-builder-palette-input']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-palette-input-text']")
        .trigger("click")
      const firstTabBag = store.getSchema(BUILDER_ID).cards[
        firstTab
      ] as unknown as Record<string, unknown>
      const elId = (firstTabBag.elementList as string[])[0]!

      // Add a second tab and switch to it — its list is empty.
      await wrapper
        .find("[data-testid='form-builder-root-tab-add']")
        .trigger("click")
      await wrapper.vm.$nextTick()
      const secondTab = rootTabIds()[1]!
      await wrapper
        .find(`[data-testid='form-builder-root-tab-${secondTab}']`)
        .trigger("click")
      await wrapper.vm.$nextTick()

      // The first tab's element is not shown while the second tab is active.
      expect(
        wrapper.find(`[data-testid='form-builder-row-${elId}']`).exists(),
      ).toBe(false)
    })

    it("cog opens tab settings in the inspector and edits the active tab", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, rootTabsContainer: true },
      })
      await wrapper.vm.$nextTick()

      expect(
        wrapper.find("[data-testid='form-builder-tab-settings']").exists(),
      ).toBe(false)
      await wrapper
        .find("[data-testid='form-builder-root-tab-settings']")
        .trigger("click")
      expect(
        wrapper.find("[data-testid='form-builder-tab-settings']").exists(),
      ).toBe(true)

      await wrapper
        .find("[data-testid='form-builder-tab-settings-title']")
        .setValue("Profile")
      await wrapper
        .find("[data-testid='form-builder-tab-settings-icon']")
        .setValue("user")

      const firstTab = rootTabIds()[0]!
      const bag = useFormBuilderStore().getSchema(BUILDER_ID).cards[
        firstTab
      ] as unknown as Record<string, unknown>
      expect(bag.title).toBe("Profile")
      expect(bag.icon).toBe("user")
    })

    it("selecting an element closes the tab settings panel", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, rootTabsContainer: true },
      })
      await wrapper.vm.$nextTick()
      await wrapper
        .find("[data-testid='form-builder-root-tab-settings']")
        .trigger("click")
      expect(
        wrapper.find("[data-testid='form-builder-tab-settings']").exists(),
      ).toBe(true)

      // Add + select an element.
      await wrapper
        .find("[data-testid='form-builder-palette-input']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-palette-input-text']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      expect(
        wrapper.find("[data-testid='form-builder-tab-settings']").exists(),
      ).toBe(false)
      expect(
        wrapper.find("[data-testid='form-builder-inspector-fields']").exists(),
      ).toBe(true)
    })

    it("reorders root tabs by drag-and-drop", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, rootTabsContainer: true },
      })
      await wrapper.vm.$nextTick()
      await wrapper
        .find("[data-testid='form-builder-root-tab-add']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      const before = [...rootTabIds()]
      expect(before).toHaveLength(2)

      // Drag the second tab (index 1) onto the first (index 0).
      const second = before[1]!
      await wrapper
        .find(`[data-testid='form-builder-root-tab-wrap-${second}']`)
        .trigger("dragstart")
      const first = before[0]!
      await wrapper
        .find(`[data-testid='form-builder-root-tab-wrap-${first}']`)
        .trigger("drop")

      expect(rootTabIds()).toEqual([before[1], before[0]])
    })

    it("removes a tab (when more than one) via the chrome bar", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, rootTabsContainer: true },
      })
      await wrapper.vm.$nextTick()
      await wrapper
        .find("[data-testid='form-builder-root-tab-add']")
        .trigger("click")
      await wrapper.vm.$nextTick()
      expect(rootTabIds()).toHaveLength(2)

      const second = rootTabIds()[1]!
      await wrapper
        .find(`[data-testid='form-builder-root-tab-remove-${second}']`)
        .trigger("click")
      expect(rootTabIds()).toHaveLength(1)
    })
  })

  describe("advancedCardLists", () => {
    const advanced = {
      settings: { label: "Advanced Settings", style: "tab-container" },
      meta: { label: "Metadata", cardType: "element-list" as const },
    }

    it("hides the switcher nav button when no advanced lists are provided", () => {
      const wrapper = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      expect(
        wrapper.find("[data-testid='form-builder-nav-card-lists']").exists(),
      ).toBe(false)
    })

    it("shows the switcher nav button when advanced lists are provided", () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, advancedCardLists: advanced },
      })
      expect(
        wrapper.find("[data-testid='form-builder-nav-card-lists']").exists(),
      ).toBe(true)
    })

    it("registers a root card per advanced list keyed by name", async () => {
      mount(FormBuilder, {
        props: { builderId: BUILDER_ID, advancedCardLists: advanced },
      })
      const store = useFormBuilderStore()
      const schema = store.getSchema(BUILDER_ID)
      // tab-container ⇒ tab-list root (seeded with a tab); explicit ⇒ element-list.
      expect(
        (schema.cards["settings"] as unknown as Record<string, unknown>)
          ?.cardType,
      ).toBe("tab-list")
      expect(
        (schema.cards["meta"] as unknown as Record<string, unknown>)?.cardType,
      ).toBe("element-list")
    })

    it("lists the main form plus each advanced list in the switcher panel", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, advancedCardLists: advanced },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-card-lists']")
        .trigger("click")
      expect(
        wrapper.find("[data-testid='form-builder-card-list-root']").exists(),
      ).toBe(true)
      expect(
        wrapper.find("[data-testid='form-builder-card-list-settings']").exists(),
      ).toBe(true)
      expect(
        wrapper.find("[data-testid='form-builder-card-list-meta']").exists(),
      ).toBe(true)
    })

    it("switching to an element-list advanced root re-points where elements are added", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, advancedCardLists: advanced },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-card-lists']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-card-list-meta']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      // Add an element — it should land in the "meta" advanced root.
      await wrapper
        .find("[data-testid='form-builder-nav-palette']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-palette-input']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-palette-input-text']")
        .trigger("click")

      const store = useFormBuilderStore()
      const schema = store.getSchema(BUILDER_ID)
      const metaList = (
        schema.cards["meta"] as unknown as Record<string, unknown>
      ).elementList as string[]
      expect(metaList).toHaveLength(1)
      // The main root stays empty.
      const mainList = (
        schema.cards[schema.rootCardId] as unknown as Record<string, unknown>
      ).elementList as string[]
      expect(mainList ?? []).toHaveLength(0)
    })

    it("shows no editing banner while the primary form root is active", () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, advancedCardLists: advanced },
      })
      expect(
        wrapper.find("[data-testid='form-builder-editing-banner']").exists(),
      ).toBe(false)
    })

    it("shows a 'Currently editing' banner with the advanced list label", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, advancedCardLists: advanced },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-card-lists']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-card-list-settings']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      const banner = wrapper.find("[data-testid='form-builder-editing-banner']")
      expect(banner.exists()).toBe(true)
      expect(banner.text()).toContain("Currently editing")
      expect(banner.text()).toContain("Advanced Settings")
    })

    it("the banner's exit button returns to the primary form root", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, advancedCardLists: advanced },
      })
      await wrapper
        .find("[data-testid='form-builder-nav-card-lists']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-card-list-meta']")
        .trigger("click")
      await wrapper.vm.$nextTick()
      expect(
        wrapper.find("[data-testid='form-builder-editing-banner']").exists(),
      ).toBe(true)

      await wrapper
        .find("[data-testid='form-builder-editing-banner-exit']")
        .trigger("click")
      await wrapper.vm.$nextTick()
      expect(
        wrapper.find("[data-testid='form-builder-editing-banner']").exists(),
      ).toBe(false)
    })

    it("switching to a tab-container advanced root shows the tabs chrome bar", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, advancedCardLists: advanced },
      })
      // Main root (element-list) → no chrome bar.
      expect(
        wrapper.find("[data-testid='form-builder-root-tabs']").exists(),
      ).toBe(false)

      await wrapper
        .find("[data-testid='form-builder-nav-card-lists']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-card-list-settings']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      // The tab-list advanced root renders the chrome bar.
      expect(
        wrapper.find("[data-testid='form-builder-root-tabs']").exists(),
      ).toBe(true)
    })

    describe("externalAdvancedCardControl", () => {
      it("hides the switcher nav button and uses activeAdvancedCard instead", async () => {
        const wrapper = mount(FormBuilder, {
          props: {
            builderId: BUILDER_ID,
            advancedCardLists: advanced,
            externalAdvancedCardControl: true,
            activeAdvancedCard: "meta",
          },
        })
        await wrapper.vm.$nextTick()
        // No built-in switcher nav button under external control.
        expect(
          wrapper.find("[data-testid='form-builder-nav-card-lists']").exists(),
        ).toBe(false)
        // And no "Currently editing" banner.
        expect(
          wrapper.find("[data-testid='form-builder-editing-banner']").exists(),
        ).toBe(false)

        // The canvas is editing the externally-selected "meta" root.
        await wrapper
          .find("[data-testid='form-builder-palette-input']")
          .trigger("click")
        await wrapper
          .find("[data-testid='form-builder-palette-input-text']")
          .trigger("click")
        const store = useFormBuilderStore()
        const schema = store.getSchema(BUILDER_ID)
        const metaList = (
          schema.cards["meta"] as unknown as Record<string, unknown>
        ).elementList as string[]
        expect(metaList).toHaveLength(1)
      })

      it("reacts to activeAdvancedCard changes", async () => {
        const wrapper = mount(FormBuilder, {
          props: {
            builderId: BUILDER_ID,
            advancedCardLists: advanced,
            externalAdvancedCardControl: true,
            activeAdvancedCard: "root",
          },
        })
        await wrapper.vm.$nextTick()
        // tab-container "settings" → chrome bar should appear once selected.
        expect(
          wrapper.find("[data-testid='form-builder-root-tabs']").exists(),
        ).toBe(false)

        await wrapper.setProps({ activeAdvancedCard: "settings" })
        await wrapper.vm.$nextTick()
        expect(
          wrapper.find("[data-testid='form-builder-root-tabs']").exists(),
        ).toBe(true)
        // Still no banner under external control.
        expect(
          wrapper.find("[data-testid='form-builder-editing-banner']").exists(),
        ).toBe(false)
      })

      it("falls back to the main form for an unknown activeAdvancedCard", async () => {
        const wrapper = mount(FormBuilder, {
          props: {
            builderId: BUILDER_ID,
            advancedCardLists: advanced,
            externalAdvancedCardControl: true,
            activeAdvancedCard: "does-not-exist",
          },
        })
        await wrapper.vm.$nextTick()
        // Add an element — it lands in the main root, not an advanced one.
        await wrapper
          .find("[data-testid='form-builder-palette-input']")
          .trigger("click")
        await wrapper
          .find("[data-testid='form-builder-palette-input-text']")
          .trigger("click")
        const store = useFormBuilderStore()
        const schema = store.getSchema(BUILDER_ID)
        const mainList = (
          schema.cards[schema.rootCardId] as unknown as Record<string, unknown>
        ).elementList as string[]
        expect(mainList).toHaveLength(1)
      })
    })

    it("preserves an advanced root already present in the loaded schema", async () => {
      const existing = {
        rootCardId: "root",
        cards: {
          root: { id: "root", cardType: "element-list", elementList: [] },
          settings: {
            id: "settings",
            cardType: "element-list",
            title: "Advanced Settings",
            elementList: ["pre"],
          },
        },
        elements: {
          pre: { id: "pre", type: "input.text", name: "pre", label: "Pre" },
        },
      } as never
      mount(FormBuilder, {
        props: {
          builderId: BUILDER_ID,
          advancedCardLists: advanced,
          modelValue: existing,
        },
      })
      const store = useFormBuilderStore()
      const schema = store.getSchema(BUILDER_ID)
      // The pre-existing "settings" root (with its element) is not overwritten.
      const settings = schema.cards["settings"] as unknown as Record<
        string,
        unknown
      >
      expect(settings.cardType).toBe("element-list")
      expect((settings.elementList as string[]) ?? []).toEqual(["pre"])
    })
  })

  describe("snippets (UI)", () => {
    function rootId(): string {
      return useFormBuilderStore().getSchema(BUILDER_ID).rootCardId
    }

    it("hides the snippets nav button unless enableSnippets is set", () => {
      const a = mount(FormBuilder, { props: { builderId: BUILDER_ID } })
      expect(a.find("[data-testid='form-builder-nav-snippets']").exists()).toBe(false)
      const b = mount(FormBuilder, {
        props: { builderId: `${BUILDER_ID}-2`, enableSnippets: true },
      })
      expect(b.find("[data-testid='form-builder-nav-snippets']").exists()).toBe(true)
    })

    it("adds a snippet from the panel", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      await wrapper.find("[data-testid='form-builder-nav-snippets']").trigger("click")
      await wrapper
        .find("[data-testid='form-builder-snippet-new-input']")
        .setValue("addr")
      await wrapper.find("[data-testid='form-builder-snippet-add']").trigger("click")
      expect(
        wrapper.find("[data-testid='form-builder-snippet-addr']").exists(),
      ).toBe(true)
    })

    it("editing a snippet shows the breadcrumb header and scopes mutations", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      store.addSnippet(BUILDER_ID, "addr", { label: "Address" })
      await wrapper.vm.$nextTick()
      await wrapper.find("[data-testid='form-builder-nav-snippets']").trigger("click")
      await wrapper
        .find("[data-testid='form-builder-snippet-edit-addr']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      const crumb = wrapper.find("[data-testid='form-builder-snippet-breadcrumb']")
      expect(crumb.exists()).toBe(true)
      expect(crumb.text()).toContain("Address")
      expect(crumb.text()).toContain("Full form")

      // Adding an element now lands in the snippet, not the main form.
      await wrapper.find("[data-testid='form-builder-nav-palette']").trigger("click")
      await wrapper.find("[data-testid='form-builder-palette-input']").trigger("click")
      await wrapper.find("[data-testid='form-builder-palette-input-text']").trigger("click")
      const def = store.getSnippet(BUILDER_ID, "addr")!
      expect(Object.keys(def.elements)).toHaveLength(1)
      const main = store.getSchema(BUILDER_ID)
      const mainList =
        (main.cards[main.rootCardId] as unknown as Record<string, unknown>)
          .elementList as string[]
      expect(mainList ?? []).toHaveLength(0)

      // Exit returns to the form.
      await wrapper
        .find("[data-testid='form-builder-snippet-exit']")
        .trigger("click")
      await wrapper.vm.$nextTick()
      expect(
        wrapper.find("[data-testid='form-builder-snippet-breadcrumb']").exists(),
      ).toBe(false)
    })

    it("places a snippet from the palette and renders a non-editable placeholder", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      store.addSnippet(BUILDER_ID, "addr", { label: "Address" })
      await wrapper.vm.$nextTick()
      // The palette is open by default; place the snippet from it.
      await wrapper
        .find("[data-testid='form-builder-palette-snippet-addr']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      // The token is placed in the root and rendered as a placeholder row.
      const list = (
        store.getSchema(BUILDER_ID).cards[rootId()] as unknown as Record<
          string,
          unknown
        >
      ).elementList as string[]
      expect(list).toHaveLength(1)
      const token = list[0]!
      expect(token).toMatch(/^snippet#addr:/)
      const row = wrapper.find(`[data-testid="form-builder-row-${token}"]`)
      expect(row.exists()).toBe(true)
      // The definition is rendered read-only inside the yellow border.
      expect(
        wrapper
          .find(`[data-testid="form-builder-snippet-preview-${token}"]`)
          .exists(),
      ).toBe(true)
    })

    it("renders a snippet placed inside a nested card container", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      store.addSnippet(BUILDER_ID, "addr", { label: "Address" })
      const cardEl = store.addElement(BUILDER_ID, rootId(), "card.list")
      store.placeSnippet(BUILDER_ID, cardEl, "addr")
      await wrapper.vm.$nextTick()

      const token = (
        (store.getSchema(BUILDER_ID).elements[cardEl] as unknown as Record<
          string,
          unknown
        >).elementList as string[]
      )[0]!
      // The nested snippet renders its read-only preview (not just a stub).
      expect(
        wrapper
          .find(`[data-testid="form-builder-snippet-preview-${token}"]`)
          .exists(),
      ).toBe(true)
    })

    it("selecting a placed snippet offers expand + remove", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      store.addSnippet(BUILDER_ID, "addr", { label: "Address" })
      store.placeSnippet(BUILDER_ID, rootId(), "addr")
      const token = (
        (
          store.getSchema(BUILDER_ID).cards[rootId()] as unknown as Record<
            string,
            unknown
          >
        ).elementList as string[]
      )[0]!
      store.select(BUILDER_ID, "element", token)
      await wrapper.vm.$nextTick()

      expect(
        wrapper.find("[data-testid='form-builder-snippet-expand']").exists(),
      ).toBe(true)
      // Remove from form drops the placement but keeps the definition.
      await wrapper
        .find("[data-testid='form-builder-snippet-remove-placement']")
        .trigger("click")
      const list = (
        store.getSchema(BUILDER_ID).cards[rootId()] as unknown as Record<
          string,
          unknown
        >
      ).elementList as string[]
      expect(list ?? []).toEqual([])
      expect(store.getSnippet(BUILDER_ID, "addr")).not.toBeNull()
    })

    it("replaces a placed snippet with an editable copy (inline)", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      // Snippet with two leaf fields in its element-list root.
      const snipRoot = store.addSnippet(BUILDER_ID, "addr", { label: "Address" })
      store.setActiveSnippet(BUILDER_ID, "addr")
      store.addElement(BUILDER_ID, snipRoot, "input.text")
      store.addElement(BUILDER_ID, snipRoot, "input.email")
      store.setActiveSnippet(BUILDER_ID, null)
      // Place + select it on the form.
      store.placeSnippet(BUILDER_ID, rootId(), "addr")
      const token = (
        (store.getSchema(BUILDER_ID).cards[rootId()] as unknown as Record<
          string,
          unknown
        >).elementList as string[]
      )[0]!
      store.select(BUILDER_ID, "element", token)
      await wrapper.vm.$nextTick()

      await wrapper
        .find("[data-testid='form-builder-snippet-replace-copy']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      // The token is replaced by two real, editable element copies.
      const list = (
        store.getSchema(BUILDER_ID).cards[rootId()] as unknown as Record<
          string,
          unknown
        >
      ).elementList as string[]
      expect(list).toHaveLength(2)
      expect(list.some((id) => id.startsWith("snippet#"))).toBe(false)
      expect(store.getSchema(BUILDER_ID).elements[list[0]!]?.type).toBe("input.text")
      // The shared definition is untouched and still present.
      expect(store.getSnippet(BUILDER_ID, "addr")).not.toBeNull()
    })

    it("the snippet block's expand button opens the snippet for editing", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      store.addSnippet(BUILDER_ID, "addr", { label: "Address" })
      store.placeSnippet(BUILDER_ID, rootId(), "addr")
      const token = (
        (store.getSchema(BUILDER_ID).cards[rootId()] as unknown as Record<
          string,
          unknown
        >).elementList as string[]
      )[0]!
      await wrapper.vm.$nextTick()

      await wrapper
        .find(`[data-testid="form-builder-snippet-expand-${token}"]`)
        .trigger("click")
      await wrapper.vm.$nextTick()
      expect(store.getActiveSnippet(BUILDER_ID)).toBe("addr")
      // The shared-snippet disclaimer is shown while editing.
      expect(
        wrapper.find("[data-testid='form-builder-snippet-disclaimer']").exists(),
      ).toBe(true)
    })

    it("keeps the snippet as the parent breadcrumb when zooming into a card inside it", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      const snipRoot = store.addSnippet(BUILDER_ID, "snip1", { label: "snip1" })
      store.setActiveSnippet(BUILDER_ID, "snip1")
      const cardEl = store.addElement(BUILDER_ID, snipRoot, "card.tab")
      store.select(BUILDER_ID, "element", cardEl)
      await wrapper.vm.$nextTick()

      // Zoom into the card that lives inside the snippet.
      await wrapper.find("[data-testid='form-builder-zoom-in']").trigger("click")
      await wrapper.vm.$nextTick()

      // The zoom breadcrumb keeps the snippet as the parent crumb.
      const crumb = wrapper.find("[data-testid='form-builder-zoom-snippet-crumb']")
      expect(crumb.exists()).toBe(true)
      expect(crumb.text()).toContain("snip1")

      // The snippet crumb zooms back to the snippet root (stays in the snippet).
      await crumb.trigger("click")
      await wrapper.vm.$nextTick()
      expect(store.getActiveSnippet(BUILDER_ID)).toBe("snip1")
      expect(
        wrapper.find("[data-testid='form-builder-snippet-breadcrumb']").exists(),
      ).toBe(true)
    })

    it("the 'Full form' crumb exits the snippet entirely from a zoomed card", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      const snipRoot = store.addSnippet(BUILDER_ID, "snip1", { label: "snip1" })
      store.setActiveSnippet(BUILDER_ID, "snip1")
      const cardEl = store.addElement(BUILDER_ID, snipRoot, "card.tab")
      store.select(BUILDER_ID, "element", cardEl)
      await wrapper.vm.$nextTick()
      await wrapper.find("[data-testid='form-builder-zoom-in']").trigger("click")
      await wrapper.vm.$nextTick()

      await wrapper.find("[data-testid='form-builder-zoom-out']").trigger("click")
      await wrapper.vm.$nextTick()
      expect(store.getActiveSnippet(BUILDER_ID)).toBe(null)
    })

    it("converts a selected element into a snippet", async () => {
      const wrapper = mount(FormBuilder, {
        props: { builderId: BUILDER_ID, enableSnippets: true },
      })
      const store = useFormBuilderStore()
      const elId = store.addElement(BUILDER_ID, rootId(), "input.text")
      store.select(BUILDER_ID, "element", elId)
      await wrapper.vm.$nextTick()

      await wrapper
        .find("[data-testid='form-builder-convert-to-snippet']")
        .trigger("click")
      await wrapper
        .find("[data-testid='form-builder-convert-snippet-name']")
        .setValue("myfield")
      await wrapper
        .find("[data-testid='form-builder-convert-snippet-confirm']")
        .trigger("click")
      await wrapper.vm.$nextTick()

      const main = store.getSchema(BUILDER_ID)
      const list = (main.cards[rootId()] as unknown as Record<string, unknown>)
        .elementList as string[]
      expect(list).toHaveLength(1)
      expect(list[0]).toMatch(/^snippet#myfield:/)
      expect(store.getSnippet(BUILDER_ID, "myfield")).not.toBeNull()
    })
  })

  describe("snippets (store)", () => {
    function rootId(): string {
      return useFormBuilderStore().getSchema(BUILDER_ID).rootCardId
    }

    it("addSnippet creates a self-contained element-list definition", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      store.addSnippet(BUILDER_ID, "addr", { label: "Address" })
      expect(store.listSnippets(BUILDER_ID)).toEqual(["addr"])
      const def = store.getSnippet(BUILDER_ID, "addr")!
      expect(def.label).toBe("Address")
      const root = def.cards[def.rootCardId] as unknown as Record<string, unknown>
      expect(root.cardType).toBe("element-list")
      expect(root.elementList).toEqual([])
    })

    it("placeSnippet pushes a snippet#<key>:<instanceId> token into a container", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      store.addSnippet(BUILDER_ID, "addr")
      store.placeSnippet(BUILDER_ID, rootId(), "addr")
      const schema = store.getSchema(BUILDER_ID)
      const list = (schema.cards[rootId()] as unknown as Record<string, unknown>)
        .elementList as string[]
      expect(list).toHaveLength(1)
      expect(list[0]).toMatch(/^snippet#addr:/)
    })

    it("refuses to remove a snippet that is still used", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      store.addSnippet(BUILDER_ID, "addr")
      store.placeSnippet(BUILDER_ID, rootId(), "addr")
      expect(store.isSnippetUsed(BUILDER_ID, "addr")).toBe(true)
      expect(store.removeSnippet(BUILDER_ID, "addr")).toBe(false)
      expect(store.listSnippets(BUILDER_ID)).toEqual(["addr"])
    })

    it("removes an unused snippet", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      store.addSnippet(BUILDER_ID, "addr")
      expect(store.isSnippetUsed(BUILDER_ID, "addr")).toBe(false)
      expect(store.removeSnippet(BUILDER_ID, "addr")).toBe(true)
      expect(store.listSnippets(BUILDER_ID)).toEqual([])
    })

    it("persists a snippet placement's resized colSpan to its overrides", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      store.addSnippet(BUILDER_ID, "addr")
      store.placeSnippet(BUILDER_ID, rootId(), "addr")
      const token = (
        (store.getSchema(BUILDER_ID).cards[rootId()] as unknown as Record<
          string,
          unknown
        >).elementList as string[]
      )[0]!

      store.updateSnippetOverride(BUILDER_ID, token, { colSpan: 2 })
      expect(store.getSnippetOverride(BUILDER_ID, token)).toEqual({ colSpan: 2 })

      // Stored under the token's instance id so it round-trips as an override.
      const instanceId = token.split(":")[1]!
      expect(store.getSchema(BUILDER_ID).snippetOverrides?.[instanceId]).toEqual({
        colSpan: 2,
      })
    })

    it("setActiveSnippet routes element mutations into the snippet sub-schema", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      const snipRoot = store.addSnippet(BUILDER_ID, "addr")
      store.setActiveSnippet(BUILDER_ID, "addr")
      store.addElement(BUILDER_ID, snipRoot, "input.text")

      // The element landed in the snippet definition, not the main schema.
      const def = store.getSnippet(BUILDER_ID, "addr")!
      expect(Object.keys(def.elements)).toHaveLength(1)
      const main = store.getSchema(BUILDER_ID)
      const mainRootList =
        (main.cards[main.rootCardId] as unknown as Record<string, unknown>)
          .elementList as string[]
      expect(mainRootList ?? []).toHaveLength(0)

      // Working schema reflects the active snippet; main schema is the export.
      expect(store.getWorkingSchema(BUILDER_ID).rootCardId).toBe(snipRoot)
      store.setActiveSnippet(BUILDER_ID, null)
      expect(store.getWorkingSchema(BUILDER_ID).rootCardId).toBe(main.rootCardId)
    })

    it("convertElementToSnippet lifts an element and replaces it with a token", () => {
      const store = useFormBuilderStore()
      store.ensureBuilder(BUILDER_ID)
      const elId = store.addElement(BUILDER_ID, rootId(), "input.text")
      const ok = store.convertElementToSnippet(BUILDER_ID, elId, "myfield", "My field")
      expect(ok).toBe(true)

      // The placement is now a token; the original element is gone from main.
      const main = store.getSchema(BUILDER_ID)
      const list = (main.cards[rootId()] as unknown as Record<string, unknown>)
        .elementList as string[]
      expect(list).toHaveLength(1)
      expect(list[0]).toMatch(/^snippet#myfield:/)
      expect(main.elements[elId]).toBeUndefined()
      // The lifted element lives in the snippet definition.
      const def = store.getSnippet(BUILDER_ID, "myfield")!
      expect(def.elements[elId]).toBeDefined()
    })
  })
})
