import { describe, it, expect } from "vitest"
import { mount } from "@vue/test-utils"
import { h } from "vue"
import { Toggle } from "."

describe("Toggle", () => {
  describe("default rendering", () => {
    it("renders without errors", () => {
      const wrapper = mount(Toggle, { slots: { default: "Toggle" } })
      expect(wrapper.exists()).toBe(true)
      expect(wrapper.text()).toBe("Toggle")
    })

    it("renders as a button element", () => {
      const wrapper = mount(Toggle)
      expect(wrapper.element.tagName).toBe("BUTTON")
    })

    it("has data-state=off by default", () => {
      const wrapper = mount(Toggle)
      expect(wrapper.attributes("data-state")).toBe("off")
    })

    it("has button type=button", () => {
      const wrapper = mount(Toggle)
      expect(wrapper.attributes("type")).toBe("button")
    })
  })

  describe("variants", () => {
    it.each([
      ["default", ["bg-transparent"]],
      ["outline", ["border", "border-input", "bg-transparent"]],
    ] as const)("renders %s variant with expected classes", (variant, expected) => {
      const wrapper = mount(Toggle, { props: { variant } })
      for (const cls of expected) {
        expect(wrapper.classes()).toContain(cls)
      }
    })

    it("does not apply outline border to default variant", () => {
      const wrapper = mount(Toggle, { props: { variant: "default" } })
      expect(wrapper.classes()).not.toContain("border-input")
    })
  })

  describe("sizes", () => {
    it.each([
      ["default", ["h-10", "px-3"]],
      ["sm", ["h-9", "px-2.5"]],
      ["lg", ["h-11", "px-5"]],
    ] as const)("renders %s size with expected classes", (size, expected) => {
      const wrapper = mount(Toggle, { props: { size } })
      for (const cls of expected) {
        expect(wrapper.classes()).toContain(cls)
      }
    })
  })

  describe("pressed state (v-model)", () => {
    it("reflects defaultPressed=true as data-state=on", () => {
      const wrapper = mount(Toggle, { props: { defaultPressed: true } })
      expect(wrapper.attributes("data-state")).toBe("on")
    })

    it("reflects pressed=true as data-state=on", () => {
      const wrapper = mount(Toggle, { props: { pressed: true } })
      expect(wrapper.attributes("data-state")).toBe("on")
    })

    it("toggles on click and emits update:pressed", async () => {
      const wrapper = mount(Toggle, {
        props: { pressed: false },
      })
      await wrapper.trigger("click")
      expect(wrapper.emitted("update:pressed")).toBeTruthy()
      expect(wrapper.emitted("update:pressed")?.[0]).toEqual([true])
    })

    it("does not toggle when disabled", async () => {
      const wrapper = mount(Toggle, {
        props: { disabled: true, pressed: false },
      })
      await wrapper.trigger("click")
      expect(wrapper.emitted("update:pressed")).toBeFalsy()
    })
  })

  describe("disabled", () => {
    it("sets disabled attribute when disabled prop is true", () => {
      const wrapper = mount(Toggle, { props: { disabled: true } })
      expect(wrapper.attributes("disabled")).toBeDefined()
    })

    it("has data-disabled when disabled", () => {
      const wrapper = mount(Toggle, { props: { disabled: true } })
      expect(wrapper.attributes("data-disabled")).toBeDefined()
    })
  })

  describe("custom class", () => {
    it("merges custom class with default classes", () => {
      const wrapper = mount(Toggle, { props: { class: "my-toggle" } })
      expect(wrapper.classes()).toContain("my-toggle")
      expect(wrapper.classes()).toContain("inline-flex")
    })

    it("allows tailwind-merge override", () => {
      const wrapper = mount(Toggle, {
        props: { class: "bg-blue-500", variant: "outline" },
      })
      expect(wrapper.classes()).toContain("bg-blue-500")
    })
  })

  describe("slot content", () => {
    it("renders text", () => {
      const wrapper = mount(Toggle, { slots: { default: "Bold" } })
      expect(wrapper.text()).toBe("Bold")
    })

    it("renders an icon component", () => {
      const Icon = { template: '<svg class="my-icon" />' }
      const wrapper = mount(Toggle, { slots: { default: h(Icon) } })
      expect(wrapper.find(".my-icon").exists()).toBe(true)
    })
  })

  describe("base styles", () => {
    it("has base layout and focus-visible classes", () => {
      const wrapper = mount(Toggle)
      const classes = wrapper.classes()
      for (const cls of [
        "inline-flex",
        "items-center",
        "justify-center",
        "rounded-md",
        "text-sm",
        "font-medium",
        "transition-colors",
        "focus-visible:outline-none",
        "focus-visible:ring-2",
        "focus-visible:ring-ring",
        "disabled:pointer-events-none",
        "disabled:opacity-50",
      ]) {
        expect(classes).toContain(cls)
      }
    })
  })
})
