import { describe, it, expect } from "vitest"
import { mount } from "@vue/test-utils"
import { h, nextTick } from "vue"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "."

function mountTabs(props: Record<string, unknown> = {}, listProps: Record<string, unknown> = {}) {
  return mount(Tabs, {
    props: { defaultValue: "tab1", ...props },
    slots: {
      default: () => [
        h(TabsList, listProps, {
          default: () => [
            h(TabsTrigger, { value: "tab1" }, { default: () => "Tab 1" }),
            h(TabsTrigger, { value: "tab2" }, { default: () => "Tab 2" }),
            h(TabsTrigger, { value: "tab3" }, { default: () => "Tab 3" }),
          ],
        }),
        h(TabsContent, { value: "tab1" }, { default: () => "Content 1" }),
        h(TabsContent, { value: "tab2" }, { default: () => "Content 2" }),
        h(TabsContent, { value: "tab3" }, { default: () => "Content 3" }),
      ],
    },
  })
}

describe("Tabs", () => {
  describe("default rendering", () => {
    it("renders without errors", () => {
      const wrapper = mountTabs()
      expect(wrapper.exists()).toBe(true)
    })

    it("renders all tab triggers", () => {
      const wrapper = mountTabs()
      expect(wrapper.findAll('[role="tab"]')).toHaveLength(3)
    })

    it("shows content for default active tab", () => {
      const wrapper = mountTabs()
      const activePanel = wrapper.find('[role="tabpanel"]')
      expect(activePanel.text()).toContain("Content 1")
    })
  })

  describe("TabsList variants", () => {
    it.each([
      ["default", ["rounded-md", "bg-muted", "p-1"]],
      ["pills", ["gap-1"]],
      ["underline", ["border-b", "w-full", "justify-start"]],
    ] as const)("renders %s variant with expected classes", (variant, expected) => {
      const wrapper = mountTabs({}, { variant })
      const list = wrapper.find('[role="tablist"]')
      for (const cls of expected) {
        expect(list.classes()).toContain(cls)
      }
    })

    it("accepts custom class on TabsList", () => {
      const wrapper = mountTabs({}, { class: "custom-list-class" })
      const list = wrapper.find('[role="tablist"]')
      expect(list.classes()).toContain("custom-list-class")
    })
  })

  describe("TabsTrigger", () => {
    it("active trigger has data-state=active", () => {
      const wrapper = mountTabs()
      const triggers = wrapper.findAll('[role="tab"]')
      const active = triggers.find((t) => t.text().includes("Tab 1"))
      expect(active?.attributes("data-state")).toBe("active")
    })

    it("inactive trigger has data-state=inactive", () => {
      const wrapper = mountTabs()
      const triggers = wrapper.findAll("[role=\"tab\"]")
      const inactive = triggers.find((t) => t.text().includes("Tab 2"))
      expect(inactive?.attributes("data-state")).toBe("inactive")
    })

    it("renders slot content", () => {
      const wrapper = mountTabs()
      const triggers = wrapper.findAll('[role="tab"]')
      expect(triggers[0].text()).toContain("Tab 1")
      expect(triggers[1].text()).toContain("Tab 2")
      expect(triggers[2].text()).toContain("Tab 3")
    })

    it("has trigger base classes", () => {
      const wrapper = mountTabs()
      const trigger = wrapper.find('[role="tab"]')
      const classes = trigger.classes()
      for (const cls of [
        "inline-flex",
        "items-center",
        "justify-center",
        "whitespace-nowrap",
        "text-sm",
        "font-medium",
        "transition-all",
      ]) {
        expect(classes).toContain(cls)
      }
    })

    it("accepts custom class", () => {
      const wrapper = mount(Tabs, {
        props: { defaultValue: "x" },
        slots: {
          default: () => [
            h(TabsList, null, {
              default: () => h(TabsTrigger, { value: "x", class: "custom-trigger" }, { default: () => "X" }),
            }),
            h(TabsContent, { value: "x" }, { default: () => "XC" }),
          ],
        },
      })
      const trigger = wrapper.find('[role="tab"]')
      expect(trigger.classes()).toContain("custom-trigger")
    })
  })

  describe("TabsContent", () => {
    it("active content has data-state=active", () => {
      const wrapper = mountTabs()
      const panel = wrapper.find('[role="tabpanel"]')
      expect(panel.attributes("data-state")).toBe("active")
    })

    it("has base content classes", () => {
      const wrapper = mountTabs()
      const panel = wrapper.find('[role="tabpanel"]')
      expect(panel.classes()).toContain("mt-2")
    })
  })

  describe("orientation", () => {
    it("supports horizontal (default) orientation", () => {
      const wrapper = mountTabs()
      const list = wrapper.find('[role="tablist"]')
      // Reka defaults to horizontal — aria-orientation may or may not be set.
      expect(list.exists()).toBe(true)
    })

    it("supports vertical orientation", () => {
      const wrapper = mountTabs({ orientation: "vertical" })
      const list = wrapper.find('[role="tablist"]')
      expect(list.attributes("aria-orientation")).toBe("vertical")
    })
  })

  describe("tab switching", () => {
    it("switches content when triggering a different tab", async () => {
      const wrapper = mountTabs()
      const triggers = wrapper.findAll('[role="tab"]')
      await triggers[1].trigger("mousedown", { button: 0 })
      await nextTick()
      await nextTick()
      expect(triggers[1].attributes("data-state")).toBe("active")
      const activePanel = wrapper.find('[role="tabpanel"][data-state="active"]')
      expect(activePanel.text()).toContain("Content 2")
    })
  })

  describe("v-model", () => {
    it("emits update:modelValue on tab change", async () => {
      const wrapper = mount(Tabs, {
        props: { modelValue: "tab1" },
        slots: {
          default: () => [
            h(TabsList, null, {
              default: () => [
                h(TabsTrigger, { value: "tab1" }, { default: () => "Tab 1" }),
                h(TabsTrigger, { value: "tab2" }, { default: () => "Tab 2" }),
              ],
            }),
            h(TabsContent, { value: "tab1" }, { default: () => "C1" }),
            h(TabsContent, { value: "tab2" }, { default: () => "C2" }),
          ],
        },
      })
      const triggers = wrapper.findAll('[role="tab"]')
      await triggers[1].trigger("mousedown", { button: 0 })
      await nextTick()
      expect(wrapper.emitted("update:modelValue")).toBeTruthy()
    })
  })

  describe("custom class on Tabs root", () => {
    it("accepts custom class", () => {
      const wrapper = mount(Tabs, {
        props: { defaultValue: "a", class: "my-tabs" },
        slots: {
          default: () => [
            h(TabsList, null, { default: () => h(TabsTrigger, { value: "a" }, { default: () => "A" }) }),
            h(TabsContent, { value: "a" }, { default: () => "AC" }),
          ],
        },
      })
      expect(wrapper.classes()).toContain("my-tabs")
    })
  })
})
