import { beforeEach, describe, expect, it } from "vitest"
import {
  v1ToV2,
  v2ToV1,
  __resetIdCounter,
  v1ConditionParamToV2,
  v2ConditionParamToV1,
  v1ColumnsToV2,
  v2ColumnsToV1,
} from "@/adapters"
import type { V1PageConfig } from "@/adapters"

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

describe("v1ConditionParamToV2", () => {
  it("renames field→name and operator→logic", () => {
    expect(
      v1ConditionParamToV2({ field: "role", operator: "equals", value: "admin" }),
    ).toEqual({ name: "role", logic: "==", value: "admin" })
  })

  it("maps common operator aliases", () => {
    expect(
      v1ConditionParamToV2({ field: "n", operator: "gt", value: 0 }),
    ).toEqual({ name: "n", logic: ">", value: 0 })
    expect(
      v1ConditionParamToV2({ field: "tags", operator: "in", value: ["a"] }),
    ).toEqual({ name: "tags", logic: "in-array", value: ["a"] })
  })

  it("passes unknown operators through unchanged", () => {
    expect(
      v1ConditionParamToV2({ field: "x", operator: "fuzzy", value: 1 }),
    ).toEqual({ name: "x", logic: "fuzzy", value: 1 })
  })

  it("round-trips with v2→v1", () => {
    const v1 = { field: "status", operator: "starts_with", value: "act" }
    expect(v2ConditionParamToV1(v1ConditionParamToV2(v1))).toEqual(v1)
  })
})

describe("v1ColumnsToV2 / v2ColumnsToV1", () => {
  it("renames cols/colsSm/... → columns/columnsSm/...", () => {
    expect(v1ColumnsToV2({ cols: 12, colsMd: 6, colsLg: 4 })).toEqual({
      columns: 12,
      columnsMd: 6,
      columnsLg: 4,
    })
  })

  it("round-trips", () => {
    const v1 = { cols: 12, colsSm: 12, colsMd: 6, colsLg: 4, colsXl: 3 }
    expect(v2ColumnsToV1(v1ColumnsToV2(v1))).toEqual(v1)
  })

  it("ignores unset keys", () => {
    expect(v1ColumnsToV2({})).toEqual({})
    expect(v2ColumnsToV1({})).toEqual({})
  })
})

describe("v1ToV2 — fields_list with mixed elements", () => {
  it("converts a fields_list card into element-list + element entries", () => {
    const v1: V1PageConfig = {
      title: "User Profile",
      tabsList: [
        {
          title: "Profile",
          tabId: "profile",
          cards: [
            {
              type: "fields_list",
              title: "Basic Info",
              fieldsList: [
                {
                  type: "text",
                  name: "name",
                  label: "Full Name",
                  required: true,
                  cols: 12,
                  colsMd: 6,
                },
                {
                  type: "email",
                  name: "email",
                  label: "Email",
                  colsMd: 6,
                },
                {
                  type: "select",
                  name: "role",
                  label: "Role",
                  options: [
                    { value: "user", text: "User" },
                    { value: "admin", text: "Administrator" },
                  ],
                  colsMd: 4,
                },
                {
                  type: "checkbox",
                  name: "is_active",
                  label: "Active",
                  default: true,
                },
                {
                  type: "date",
                  name: "start_date",
                  label: "Start Date",
                  colsMd: 6,
                },
              ],
            },
          ],
        },
      ],
    }

    const v2 = v1ToV2(v1)

    expect(v2.title).toBe("User Profile")
    expect(v2.tabsList).toHaveLength(1)
    expect(v2.tabsList?.[0]?.tabId).toBe("profile")
    expect(v2.tabsList?.[0]?.cards).toHaveLength(1)

    const card = v2.tabsList?.[0]?.cards[0]!
    expect(card.cardType).toBe("element-list")
    expect(card.title).toBe("Basic Info")

    const elementIds = (card as unknown as { elementList: string[] }).elementList
    expect(elementIds).toHaveLength(5)

    const name = v2.elements[elementIds[0]!]!
    expect(name.type).toBe("input.text")
    expect(name.label).toBe("Full Name")
    expect(name.required).toBe(true)
    expect(name.columns).toBe(12)
    expect(name.columnsMd).toBe(6)

    const email = v2.elements[elementIds[1]!]!
    expect(email.type).toBe("input.email")

    const role = v2.elements[elementIds[2]!]!
    expect(role.type).toBe("option-select.select")
    expect((role as unknown as Record<string, unknown>).selectOptions).toEqual([
      { value: "user", text: "User", label: "User" },
      { value: "admin", text: "Administrator", label: "Administrator" },
    ])

    const checkbox = v2.elements[elementIds[3]!]!
    expect(checkbox.type).toBe("boolean.checkbox")
    expect(checkbox.defaultValue).toBe(true)

    const date = v2.elements[elementIds[4]!]!
    expect(date.type).toBe("picker.date-picker")
  })
})

describe("v1ToV2 — data_table card", () => {
  it("preserves headers, options, listKey, and createConfig", () => {
    const v1: V1PageConfig = {
      title: "Users",
      cards: [
        {
          type: "data_table",
          tableTitle: "All Users",
          listKey: "items",
          headers: [
            { text: "Name", value: "name", sortable: true },
            { text: "Email", value: "email" },
          ],
          options: { paginated: true, perPage: 25 },
          createConfig: { create: { route: "users.store" } },
        },
      ],
    }
    const v2 = v1ToV2(v1)
    const card = Object.values(v2.cards)[0]!
    expect(card.cardType).toBe("datatable")
    expect((card as unknown as Record<string, unknown>).tableTitle).toBe("All Users")
    expect((card as unknown as Record<string, unknown>).listKey).toBe("items")
    expect((card as unknown as Record<string, unknown>).headers).toHaveLength(2)
    expect((card as unknown as Record<string, unknown>).options).toEqual({
      paginated: true,
      perPage: 25,
    })
  })
})

describe("v1ToV2 — IndexPage shorthand", () => {
  it("synthesises a datatable card when top-level headers + options are present", () => {
    const v1: V1PageConfig = {
      title: "Users",
      breadCrumbs: [{ title: "Admin" }],
      headers: [{ text: "Name", value: "name", sortable: true }],
      options: { paginated: true, perPage: 25 },
      listKey: "items",
      createConfig: { create: { route: "users.store" } },
    }
    const v2 = v1ToV2(v1)
    expect(v2.title).toBe("Users")
    expect(v2.breadCrumbs).toEqual([{ title: "Admin" }])
    expect(v2.createConfig).toBeDefined()
    const cards = Object.values(v2.cards)
    expect(cards).toHaveLength(1)
    expect(cards[0]!.cardType).toBe("datatable")
    expect((cards[0] as unknown as Record<string, unknown>).tableTitle).toBe(
      "Users",
    )
  })
})

describe("v1ToV2 — button_group is wrapped as an element-list", () => {
  it("emits a one-element element-list card with an action/button-group element inside", () => {
    const v1: V1PageConfig = {
      cards: [
        {
          type: "button_group",
          buttons: [
            { type: "button", text: "Save", color: "primary" },
            { type: "button", text: "Cancel" },
          ],
        },
      ],
    }
    const v2 = v1ToV2(v1)
    const cards = Object.values(v2.cards)
    expect(cards).toHaveLength(1)
    expect(cards[0]!.cardType).toBe("element-list")

    const elementId = (cards[0] as unknown as { elementList: string[] })
      .elementList[0]!
    const element = v2.elements[elementId]!
    expect(element.type).toBe("action.button-group")
  })
})

describe("v1ToV2 — card_list with nested fields_list", () => {
  it("flattens nested cards into the v2 cards map and references them by id", () => {
    const v1: V1PageConfig = {
      cards: [
        {
          type: "card_list",
          cards: [
            {
              type: "fields_list",
              title: "Card A",
              fieldsList: [{ type: "text", name: "a", label: "A" }],
            },
            {
              type: "fields_list",
              title: "Card B",
              fieldsList: [{ type: "text", name: "b", label: "B" }],
            },
          ],
        },
      ],
    }
    const v2 = v1ToV2(v1)
    const root = Object.values(v2.cards).find(
      (c) => c.cardType === "card-list",
    )!
    expect(root).toBeDefined()
    const cardList = (root as unknown as { cardList: string[] }).cardList
    expect(cardList).toHaveLength(2)
    for (const id of cardList) {
      const child = v2.cards[id]!
      expect(child.cardType).toBe("element-list")
    }
  })
})

describe("v1ToV2 — conditionParams translation", () => {
  it("translates a field's conditionParams from v1 shape to v2", () => {
    const v1: V1PageConfig = {
      cards: [
        {
          type: "fields_list",
          fieldsList: [
            {
              type: "text",
              name: "secret",
              label: "Secret",
              conditionParams: [
                { field: "role", operator: "equals", value: "admin" },
              ],
            },
          ],
        },
      ],
    }
    const v2 = v1ToV2(v1)
    const element = Object.values(v2.elements)[0]!
    expect(element.conditionParams).toEqual([
      { name: "role", logic: "==", value: "admin" },
    ])
  })
})

describe("v2ToV1 — round-trip", () => {
  it("renders a fields_list / element-list pair losslessly enough for re-conversion", () => {
    const original: V1PageConfig = {
      title: "Round-Trip Test",
      tabsList: [
        {
          title: "Tab A",
          tabId: "a",
          cards: [
            {
              type: "fields_list",
              title: "Form",
              fieldsList: [
                {
                  type: "text",
                  name: "first_name",
                  label: "First name",
                  required: true,
                },
                {
                  type: "select",
                  name: "country",
                  label: "Country",
                  options: [
                    { value: "us", text: "United States" },
                    { value: "uk", text: "United Kingdom" },
                  ],
                },
              ],
            },
          ],
        },
      ],
    }
    const v2 = v1ToV2(original)
    const back = v2ToV1(v2)
    expect(back.title).toBe("Round-Trip Test")
    expect(back.tabsList?.[0]?.title).toBe("Tab A")
    const card = back.tabsList?.[0]?.cards?.[0]!
    expect(card.type).toBe("fields_list")
    expect(card.fieldsList).toHaveLength(2)
    expect(card.fieldsList?.[0]?.type).toBe("text")
    expect(card.fieldsList?.[0]?.required).toBe(true)
    expect(card.fieldsList?.[1]?.type).toBe("select")
    // options.text preserved for v1 consumers.
    const opts = card.fieldsList?.[1]?.options as unknown as Array<
      Record<string, unknown>
    >
    expect(opts[0]?.text).toBe("United States")
  })
})
