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

describe("Switch", () => {
  describe("default rendering", () => {
    it("renders as a button with role=switch", () => {
      const wrapper = mount(Switch)
      expect(wrapper.element.tagName).toBe("BUTTON")
      expect(wrapper.attributes("role")).toBe("switch")
    })

    it("has base classes", () => {
      const wrapper = mount(Switch)
      const classes = wrapper.classes()
      for (const cls of [
        "peer",
        "inline-flex",
        "shrink-0",
        "cursor-pointer",
        "items-center",
        "rounded-full",
        "border-2",
        "border-transparent",
        "transition-colors",
      ]) {
        expect(classes).toContain(cls)
      }
    })

    it("has focus-visible classes", () => {
      const wrapper = mount(Switch)
      const classes = wrapper.classes()
      for (const cls of [
        "focus-visible:outline-none",
        "focus-visible:ring-2",
        "focus-visible:ring-ring",
        "focus-visible:ring-offset-2",
      ]) {
        expect(classes).toContain(cls)
      }
    })

    it("has disabled classes", () => {
      const wrapper = mount(Switch)
      expect(wrapper.classes()).toContain("disabled:cursor-not-allowed")
      expect(wrapper.classes()).toContain("disabled:opacity-50")
    })

    it("renders a thumb element", () => {
      const wrapper = mount(Switch)
      const thumb = wrapper.find("span")
      expect(thumb.exists()).toBe(true)
      for (const cls of ["pointer-events-none", "block", "rounded-full", "bg-background", "shadow-lg"]) {
        expect(thumb.classes()).toContain(cls)
      }
    })

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

  describe("size variants", () => {
    it.each([
      ["sm", ["h-5", "w-9"]],
      ["default", ["h-6", "w-11"]],
      ["lg", ["h-7", "w-14"]],
    ] as const)("renders %s size", (size, expected) => {
      const wrapper = mount(Switch, { props: { size } })
      for (const cls of expected) {
        expect(wrapper.classes()).toContain(cls)
      }
    })

    it.each([
      ["sm", ["h-4", "w-4"]],
      ["default", ["h-5", "w-5"]],
      ["lg", ["h-6", "w-6"]],
    ] as const)("renders %s thumb size", (size, expected) => {
      const wrapper = mount(Switch, { props: { size } })
      const thumb = wrapper.find("span")
      for (const cls of expected) {
        expect(thumb.classes()).toContain(cls)
      }
    })
  })

  describe("v-model / state", () => {
    it("reflects defaultValue=true", () => {
      const wrapper = mount(Switch, { props: { defaultValue: true } })
      expect(wrapper.attributes("data-state")).toBe("checked")
    })

    it("reflects controlled modelValue=true", () => {
      const wrapper = mount(Switch, { props: { modelValue: true } })
      expect(wrapper.attributes("data-state")).toBe("checked")
    })

    it("reflects controlled modelValue=false", () => {
      const wrapper = mount(Switch, { props: { modelValue: false } })
      expect(wrapper.attributes("data-state")).toBe("unchecked")
    })

    it("emits update:modelValue when clicked", async () => {
      const wrapper = mount(Switch, { props: { modelValue: false } })
      await wrapper.trigger("click")
      expect(wrapper.emitted("update:modelValue")).toBeTruthy()
      expect(wrapper.emitted("update:modelValue")![0]).toEqual([true])
    })

    it("updates state when modelValue prop changes", async () => {
      const wrapper = mount(Switch, { props: { modelValue: false } })
      expect(wrapper.attributes("data-state")).toBe("unchecked")
      await wrapper.setProps({ modelValue: true })
      expect(wrapper.attributes("data-state")).toBe("checked")
    })
  })

  describe("disabled", () => {
    it("forwards disabled", () => {
      const wrapper = mount(Switch, { props: { disabled: true } })
      expect(wrapper.attributes("disabled")).toBe("")
    })

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

  describe("custom class", () => {
    it("merges custom class with base classes", () => {
      const wrapper = mount(Switch, { props: { class: "my-custom" } })
      expect(wrapper.classes()).toContain("my-custom")
      expect(wrapper.classes()).toContain("peer")
    })

    it("allows overriding sizing via tailwind-merge", () => {
      const wrapper = mount(Switch, { props: { class: "h-10 w-20" } })
      expect(wrapper.classes()).toContain("h-10")
      expect(wrapper.classes()).toContain("w-20")
      expect(wrapper.classes()).not.toContain("h-6")
      expect(wrapper.classes()).not.toContain("w-11")
    })
  })

  describe("a11y", () => {
    it("forwards aria-label", () => {
      const wrapper = mount(Switch, { attrs: { "aria-label": "Dark mode" } })
      expect(wrapper.attributes("aria-label")).toBe("Dark mode")
    })

    it("forwards id", () => {
      const wrapper = mount(Switch, { attrs: { id: "dm-switch" } })
      expect(wrapper.attributes("id")).toBe("dm-switch")
    })
  })
})
