import { beforeEach, describe, expect, it } from "vitest"
import {
  __resetAutoRootCounter,
  __resetIdCounter,
  convertV1ToV2,
  convertV2ToV1,
  type V2BuilderSchema,
} from "@/adapters"
import type { DisplayCard } from "@/definitions/cards"
import type { CardElement } from "@/definitions/elements"

beforeEach(() => {
  __resetIdCounter()
  __resetAutoRootCounter()
})

/**
 * A v2 schema mirroring the user's `formTemplate` example structure (in this
 * library's dot-notation shape): a card-list/tab-container root whose single
 * child is a tab-list with four section tabs. Two tabs are empty, two hold an
 * element-list card with one field each.
 */
function buildFormTemplateSchema(): {
  root: DisplayCard
  cards: Record<string, DisplayCard>
  elements: Record<string, CardElement>
} {
  const elements = {
    "el-bool": { id: "el-bool", type: "boolean.checkbox", name: "true_or_false_1", label: "True or False 1", defaultValue: false },
    "el-text": { id: "el-text", type: "input.text", name: "input_field_1", label: "Input Field 1", defaultValue: "" },
  } as unknown as Record<string, CardElement>

  const cards = {
    formTemplate: { id: "formTemplate", cardType: "card-list", style: "tab-container", title: "", cardList: ["tab-list-1"] },
    "tab-list-1": { id: "tab-list-1", cardType: "tab-list", title: "New tab-list Card", tabList: ["sec1", "sec2", "sec3", "sec4"] },
    sec1: { id: "sec1", cardType: "card-list", title: "Section 1", cardList: [] },
    sec2: { id: "sec2", cardType: "card-list", title: "Section 2", cardList: [] },
    sec3: { id: "sec3", cardType: "card-list", title: "Section 3", cardList: ["sec3-fields"] },
    "sec3-fields": { id: "sec3-fields", cardType: "element-list", title: "El card", elementList: ["el-bool"] },
    sec4: { id: "sec4", cardType: "card-list", title: "Section 4", cardList: ["sec4-fields"] },
    "sec4-fields": { id: "sec4-fields", cardType: "element-list", title: "El card", elementList: ["el-text"] },
  } as unknown as Record<string, DisplayCard>

  return { root: cards.formTemplate!, cards, elements }
}

describe("convertV2ToV1 — auto-detect", () => {
  it("unwraps a card-list/tab-container root into a single tabs_list", () => {
    const { root, cards, elements } = buildFormTemplateSchema()
    const out = convertV2ToV1(root, cards, elements)

    // Single in (the root container, holding one tab-list) → single out.
    expect(Array.isArray(out)).toBe(false)
    const tabsList = out as { type: string; tabsList: unknown[] }
    expect(tabsList.type).toBe("tabs_list")
    expect(tabsList.tabsList).toHaveLength(4)
  })

  it("emits every tab as a card_list holding the converted content", () => {
    const { root, cards, elements } = buildFormTemplateSchema()
    const out = convertV2ToV1(root, cards, elements) as {
      tabsList: Array<{
        type: string
        title?: string
        tabId?: string
        cards?: Array<{ type: string; fieldsList?: Array<{ type: string; name?: string }> }>
      }>
    }
    const tabs = out.tabsList
    // Empty section tab → card_list with no body cards.
    expect(tabs[0]!.type).toBe("card_list")
    expect(tabs[0]!.title).toBe("Section 1")
    expect(tabs[0]!.cards ?? []).toEqual([])
    // Populated section tab → card_list holding a fields_list card.
    expect(tabs[2]!.cards?.[0]?.type).toBe("fields_list")
    expect(tabs[2]!.cards?.[0]?.fieldsList?.[0]?.type).toBe("checkbox")
    expect(tabs[2]!.cards?.[0]?.fieldsList?.[0]?.name).toBe("true_or_false_1")
    expect(tabs[3]!.cards?.[0]?.fieldsList?.[0]?.type).toBe("text")
  })

  it("accepts a full builder schema and unwraps its root", () => {
    const { cards, elements } = buildFormTemplateSchema()
    const schema: V2BuilderSchema = { rootCardId: "formTemplate", cards, elements }
    const out = convertV2ToV1(schema)
    expect((out as { type: string }).type).toBe("tabs_list")
  })

  it("converts a single tab-list card directly to a tabs_list object", () => {
    const { cards, elements } = buildFormTemplateSchema()
    const out = convertV2ToV1(cards["tab-list-1"]!, cards, elements)
    expect(Array.isArray(out)).toBe(false)
    expect((out as { type: string }).type).toBe("tabs_list")
  })

  it("converts a single element-list card to a single fields_list object", () => {
    const { cards, elements } = buildFormTemplateSchema()
    const out = convertV2ToV1(cards["sec3-fields"]!, cards, elements)
    expect((out as { type: string }).type).toBe("fields_list")
    expect((out as { fieldsList: unknown[] }).fieldsList).toHaveLength(1)
  })

  it("returns an array for array input (no unwrapping of children)", () => {
    const { cards, elements } = buildFormTemplateSchema()
    const out = convertV2ToV1(["sec3", "sec1"], cards, elements)
    expect(Array.isArray(out)).toBe(true)
    const arr = out as Array<{ type: string }>
    expect(arr).toHaveLength(2)
    // Array items stay as their own card type (card-list → card_list).
    expect(arr[0]!.type).toBe("card_list")
  })

  it("resolves card ids passed in an array", () => {
    const { cards, elements } = buildFormTemplateSchema()
    const out = convertV2ToV1(["tab-list-1"], cards, elements) as Array<{ type: string }>
    expect(out[0]!.type).toBe("tabs_list")
  })
})

describe("convertV1ToV2 — auto-detect", () => {
  it("wraps a v1 tabs_list card into a tab-list root schema", () => {
    const tabsListCard = {
      id: "tl-1",
      type: "tabs_list",
      title: "Tabs",
      tabsList: [
        { title: "A", tabId: "a", cards: [{ type: "fields_list", fieldsList: [{ type: "text", name: "x", label: "X" }] }] },
        { title: "B", tabId: "b", cards: [] },
      ],
    }
    const schema = convertV1ToV2(tabsListCard)
    expect(schema.rootCardId).toBe("tl-1")
    const root = schema.cards[schema.rootCardId] as unknown as Record<string, unknown>
    expect(root.cardType).toBe("tab-list")
    expect((root.tabList as string[])).toHaveLength(2)
  })

  it("makes a single v1 card the root", () => {
    const schema = convertV1ToV2({
      type: "fields_list",
      title: "Profile",
      fieldsList: [{ type: "text", name: "first", label: "First" }],
    })
    const root = schema.cards[schema.rootCardId] as unknown as Record<string, unknown>
    expect(root.cardType).toBe("element-list")
  })

  it("wraps multiple v1 cards in a card-list root", () => {
    const schema = convertV1ToV2([
      { type: "fields_list", title: "One", fieldsList: [] },
      { type: "fields_list", title: "Two", fieldsList: [] },
    ])
    const root = schema.cards[schema.rootCardId] as unknown as Record<string, unknown>
    expect(root.cardType).toBe("card-list")
    expect((root.cardList as string[])).toHaveLength(2)
  })

  it("wraps bare fields in an element-list root", () => {
    const schema = convertV1ToV2([
      { type: "text", name: "a", label: "A" },
      { type: "email", name: "b", label: "B" },
    ])
    const root = schema.cards[schema.rootCardId] as unknown as Record<string, unknown>
    expect(root.cardType).toBe("element-list")
    expect((root.elementList as string[])).toHaveLength(2)
    expect(schema.elements[(root.elementList as string[])[0]!]!.type).toBe("input.text")
  })

  it("tolerates null/undefined input", () => {
    const schema = convertV1ToV2(null)
    expect(schema.cards[schema.rootCardId]).toBeDefined()
  })
})

describe("round-trip stability", () => {
  it("v2 → v1 → v2 keeps the tab structure", () => {
    const { root, cards, elements } = buildFormTemplateSchema()
    const v1 = convertV2ToV1(root, cards, elements) // single tabs_list
    const schema = convertV1ToV2(v1 as never)
    const reRoot = schema.cards[schema.rootCardId] as unknown as Record<string, unknown>
    expect(reRoot.cardType).toBe("tab-list")
    expect((reRoot.tabList as string[])).toHaveLength(4)

    // And back to v1 once more yields the same shape.
    const v1Again = convertV2ToV1(schema) as { type: string; tabsList: unknown[] }
    expect(v1Again.type).toBe("tabs_list")
    expect(v1Again.tabsList).toHaveLength(4)
  })
})
