import { beforeEach, describe, expect, it } from "vitest"
import { mount } from "@vue/test-utils"
import { createPinia, setActivePinia } from "pinia"
import DataTableCard from "./DataTableCard.vue"

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

  it("renders rows from item[listKey]", () => {
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        headers: [
          { key: "name", title: "Name" },
          { key: "status", title: "Status" },
        ],
        item: {
          rows: [
            { name: "Alice", status: "Active" },
            { name: "Bob", status: "Inactive" },
          ],
        },
      },
    })

    expect(wrapper.text()).toContain("Alice")
    expect(wrapper.text()).toContain("Bob")
    expect(wrapper.findAll("tbody tr")).toHaveLength(2)
  })

  it("sorts rows when a sortable column header is clicked", async () => {
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        headers: [{ key: "name", title: "Name", sortable: true }],
        item: {
          rows: [
            { name: "Charlie" },
            { name: "Alice" },
            { name: "Bob" },
          ],
        },
      },
    })

    const initialFirst = wrapper.findAll("tbody tr")[0]?.text()
    expect(initialFirst).toContain("Charlie")

    await wrapper.find("[data-testid='sort-name']").trigger("click")
    const ascRows = wrapper.findAll("tbody tr").map((r) => r.text())
    expect(ascRows[0]).toContain("Alice")
    expect(ascRows[1]).toContain("Bob")
    expect(ascRows[2]).toContain("Charlie")

    await wrapper.find("[data-testid='sort-name']").trigger("click")
    const descRows = wrapper.findAll("tbody tr").map((r) => r.text())
    expect(descRows[0]).toContain("Charlie")
    expect(descRows[2]).toContain("Alice")
  })

  it("filters rows via the search input", async () => {
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        headers: [{ key: "name", title: "Name" }],
        item: {
          rows: [{ name: "Alice" }, { name: "Bob" }, { name: "Charlie" }],
        },
      },
    })

    expect(wrapper.findAll("tbody tr")).toHaveLength(3)

    const search = wrapper.find("[data-testid='datatable-search']")
    await search.setValue("ali")

    const remaining = wrapper.findAll("tbody tr")
    expect(remaining).toHaveLength(1)
    expect(remaining[0]?.text()).toContain("Alice")
  })

  it("paginates rows and advances on next-click", async () => {
    const rows = Array.from({ length: 30 }, (_, i) => ({
      name: `Person ${String(i + 1).padStart(2, "0")}`,
    }))
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        headers: [{ key: "name", title: "Name" }],
        options: {
          paginated: true,
          perPage: 10,
        },
        item: { rows },
      },
    })

    expect(wrapper.findAll("tbody tr")).toHaveLength(10)
    expect(wrapper.text()).toContain("Page 1 of 3")
    expect(wrapper.text()).toContain("Person 01")
    expect(wrapper.text()).not.toContain("Person 11")

    await wrapper.find("[data-testid='datatable-next']").trigger("click")

    expect(wrapper.text()).toContain("Page 2 of 3")
    expect(wrapper.text()).toContain("Person 11")
    expect(wrapper.text()).not.toContain("Person 01")
  })

  it("shows the empty-state message when there are no rows", () => {
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        emptyMessage: "Nothing here yet",
        headers: [{ key: "name", title: "Name" }],
        item: { rows: [] },
      },
    })

    expect(wrapper.find("[data-testid='datatable-empty']").text()).toBe(
      "Nothing here yet",
    )
  })

  it("renders timestamp, boolean, image, and status_circle column types", () => {
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        headers: [
          { key: "createdAt", title: "Created", type: "timestamp" },
          { key: "active", title: "Active", type: "boolean" },
          { key: "avatar", title: "Avatar", type: "image" },
          { key: "status", title: "Status", type: "status_circle" },
        ],
        item: {
          rows: [
            {
              createdAt: "2024-01-15T12:00:00Z",
              active: true,
              avatar: "https://example.com/a.png",
              status: "active",
            },
          ],
        },
      },
    })

    const ts = wrapper.find("[data-testid='cell-timestamp']")
    expect(ts.exists()).toBe(true)
    expect(ts.text().length).toBeGreaterThan(0)

    const bool = wrapper.find("[data-testid='cell-boolean']")
    expect(bool.exists()).toBe(true)
    expect(bool.text()).toBe("✓")

    const img = wrapper.find("[data-testid='cell-image']")
    expect(img.exists()).toBe(true)
    expect(img.attributes("src")).toBe("https://example.com/a.png")

    const dot = wrapper.find("[data-testid='cell-status-circle']")
    expect(dot.exists()).toBe(true)
    expect(dot.classes()).toContain("bg-green-500")
  })

  it("renders the table title from tableTitle", () => {
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        tableTitle: "Recent Invoices",
        headers: [{ key: "name", title: "Name" }],
        item: { rows: [{ name: "A" }] },
      },
    })

    expect(wrapper.text()).toContain("Recent Invoices")
  })

  it("renders per-row action buttons and emits action events", async () => {
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        headers: [{ key: "name", title: "Name" }],
        actions: [{ slug: "edit", label: "Edit" }],
        item: { rows: [{ name: "Alice" }] },
      },
    })

    const btn = wrapper.find("[data-testid='datatable-action-edit']")
    expect(btn.exists()).toBe(true)

    await btn.trigger("click")
    const emitted = wrapper.emitted("action")
    expect(emitted).toBeTruthy()
    expect(emitted?.[0]?.[0]).toMatchObject({
      action: { slug: "edit" },
      row: { name: "Alice" },
    })
  })

  it("renders export buttons from options.exports", async () => {
    const wrapper = mount(DataTableCard, {
      props: {
        listKey: "rows",
        headers: [{ key: "name" }],
        options: {
          exports: [{ route: "exports.csv", label: "CSV" }],
        },
        item: { rows: [{ name: "A" }] },
      },
    })

    const exportsZone = wrapper.find("[data-testid='datatable-exports']")
    expect(exportsZone.exists()).toBe(true)
    expect(exportsZone.text()).toContain("CSV")

    await exportsZone.find("button").trigger("click")
    expect(wrapper.emitted("export")).toBeTruthy()
  })

  it("returns empty rows when searchRoute is set (stubbed fetch)", () => {
    const wrapper = mount(DataTableCard, {
      props: {
        headers: [{ key: "name", title: "Name" }],
        options: {
          searchRoute: { route: "users.index" },
        },
        item: {},
      },
    })

    expect(wrapper.find("[data-testid='datatable-empty']").exists()).toBe(true)
  })
})
