import { beforeEach, describe, expect, it, vi } from "vitest"
import { defineComponent, h, Suspense } from "vue"
import { flushPromises, mount } from "@vue/test-utils"
import { createPinia, setActivePinia } from "pinia"
import IndexPage from "./IndexPage.vue"
import type { IndexPageConfig } from "./IndexPage.vue"
import {
  __clearCardCache,
  preloadCard,
} from "@/engine/useCardLoader"

function makeConfig(overrides: Partial<IndexPageConfig> = {}): IndexPageConfig {
  return {
    title: "Users",
    ...overrides,
  }
}

function mountWithSuspense(props: Record<string, unknown>) {
  const Host = defineComponent({
    setup() {
      return () =>
        h(Suspense, null, {
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          default: () => h(IndexPage as any, props),
        })
    },
  })
  return mount(Host)
}

describe("IndexPage", () => {
  beforeEach(async () => {
    setActivePinia(createPinia())
    __clearCardCache()
    await preloadCard("datatable")
  })

  it("mounts without error", () => {
    const wrapper = mount(IndexPage, {
      props: { config: makeConfig() },
    })
    expect(wrapper.exists()).toBe(true)
  })

  it("renders the title", () => {
    const wrapper = mount(IndexPage, {
      props: { config: makeConfig({ title: "All Attendees" }) },
    })
    expect(
      wrapper.find("[data-testid='index-page-title']").text(),
    ).toBe("All Attendees")
  })

  it("renders breadcrumbs when provided", () => {
    const wrapper = mount(IndexPage, {
      props: {
        config: makeConfig({
          breadCrumbs: [{ title: "Dashboard" }, { title: "Users" }],
        }),
      },
    })
    const crumbs = wrapper.find("[data-testid='index-page-breadcrumbs']")
    expect(crumbs.exists()).toBe(true)
    expect(crumbs.text()).toContain("Dashboard")
    expect(crumbs.text()).toContain("Users")
  })

  it("omits the breadcrumb nav when no crumbs are provided", () => {
    const wrapper = mount(IndexPage, {
      props: { config: makeConfig() },
    })
    expect(
      wrapper.find("[data-testid='index-page-breadcrumbs']").exists(),
    ).toBe(false)
  })

  it("renders the optional section header", () => {
    const wrapper = mount(IndexPage, {
      props: { config: makeConfig({ section: "People" }) },
    })
    expect(
      wrapper.find("[data-testid='index-page-section']").text(),
    ).toBe("People")
  })

  it("renders the data table card", async () => {
    const wrapper = mountWithSuspense({
      config: makeConfig({
        headers: [
          { key: "name", title: "Name" },
          { key: "email", title: "Email" },
        ],
        listKey: "rows",
      }),
      items: {
        rows: [
          { name: "Alice", email: "alice@example.com" },
          { name: "Bob", email: "bob@example.com" },
        ],
      },
    })
    await flushPromises()
    const table = wrapper.find("[data-card-type='datatable']")
    expect(table.exists()).toBe(true)
    expect(wrapper.text()).toContain("Alice")
    expect(wrapper.text()).toContain("Bob")
  })

  it("hides the create button when no createConfig is provided", () => {
    const wrapper = mount(IndexPage, {
      props: { config: makeConfig() },
    })
    expect(
      wrapper.find("[data-testid='index-page-create-button']").exists(),
    ).toBe(false)
  })

  it("hides the create button when createConfig.hideButton is true", () => {
    const wrapper = mount(IndexPage, {
      props: {
        config: makeConfig({
          createConfig: {
            create: { route: "users.store" },
            hideButton: true,
          },
        }),
      },
    })
    expect(
      wrapper.find("[data-testid='index-page-create-button']").exists(),
    ).toBe(false)
  })

  it("uses the createConfig buttonText when provided", () => {
    const wrapper = mount(IndexPage, {
      props: {
        config: makeConfig({
          createConfig: {
            create: { route: "users.store" },
            buttonText: "Add user",
          },
        }),
      },
    })
    expect(
      wrapper.find("[data-testid='index-page-create-button']").text(),
    ).toBe("Add user")
  })

  it("invokes the eventHandlers.create handler on create-button click", async () => {
    const onCreate = vi.fn()
    const wrapper = mount(IndexPage, {
      props: {
        config: makeConfig({
          createConfig: { create: { route: "users.store" } },
          eventHandlers: { create: onCreate },
        }),
      },
    })
    await wrapper
      .find("[data-testid='index-page-create-button']")
      .trigger("click")
    expect(onCreate).toHaveBeenCalledTimes(1)
  })

  it("emits a 'create' event on create-button click", async () => {
    const wrapper = mount(IndexPage, {
      props: {
        config: makeConfig({
          createConfig: { create: { route: "users.store" } },
        }),
      },
    })
    await wrapper
      .find("[data-testid='index-page-create-button']")
      .trigger("click")
    expect(wrapper.emitted("create")).toBeTruthy()
    expect(wrapper.emitted("create")).toHaveLength(1)
  })
})
