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

beforeAll(() => {
  // jsdom doesn't implement ResizeObserver; reka-ui slider depends on it.
  if (typeof global.ResizeObserver === "undefined") {
    global.ResizeObserver = class {
      observe(): void {}
      unobserve(): void {}
      disconnect(): void {}
    } as unknown as typeof ResizeObserver
  }
})

describe("Slider", () => {
  describe("default rendering", () => {
    it("renders without errors", () => {
      const wrapper = mount(Slider, { props: { modelValue: [50] } })
      expect(wrapper.exists()).toBe(true)
    })

    it("renders a thumb with role=slider", () => {
      const wrapper = mount(Slider, { props: { modelValue: [50] } })
      expect(wrapper.find('[role="slider"]').exists()).toBe(true)
    })

    it("renders one thumb for a single-value model", () => {
      const wrapper = mount(Slider, { props: { modelValue: [50] } })
      expect(wrapper.findAll('[role="slider"]').length).toBe(1)
    })

    it("renders two thumbs for a range value", () => {
      const wrapper = mount(Slider, { props: { modelValue: [25, 75] } })
      expect(wrapper.findAll('[role="slider"]').length).toBe(2)
    })

    it("renders one thumb when modelValue is a single number", () => {
      const wrapper = mount(Slider, { props: { modelValue: 30 } })
      expect(wrapper.findAll('[role="slider"]').length).toBe(1)
    })
  })

  describe("sizes", () => {
    it.each([
      ["sm", ["h-4", "w-4"]],
      ["default", ["h-5", "w-5"]],
      ["lg", ["h-6", "w-6"]],
    ] as const)("renders %s thumb with expected classes", (size, expected) => {
      const wrapper = mount(Slider, {
        props: { modelValue: [50], size },
      })
      const thumb = wrapper.find('[role="slider"]')
      for (const cls of expected) {
        expect(thumb.classes()).toContain(cls)
      }
    })
  })

  describe("orientation", () => {
    it("defaults to horizontal", () => {
      const wrapper = mount(Slider, { props: { modelValue: [50] } })
      expect(wrapper.attributes("data-orientation")).toBe("horizontal")
    })

    it("supports vertical orientation", () => {
      const wrapper = mount(Slider, {
        props: { modelValue: [50], orientation: "vertical" },
      })
      expect(wrapper.attributes("data-orientation")).toBe("vertical")
    })
  })

  describe("range", () => {
    it("respects min and max bounds", () => {
      const wrapper = mount(Slider, {
        props: { modelValue: [50], min: 0, max: 100 },
      })
      const thumb = wrapper.find('[role="slider"]')
      expect(thumb.attributes("aria-valuemin")).toBe("0")
      expect(thumb.attributes("aria-valuemax")).toBe("100")
    })

    it("renders a thumb element when value is provided", () => {
      const wrapper = mount(Slider, { props: { modelValue: [42] } })
      const thumb = wrapper.find('[role="slider"]')
      expect(thumb.exists()).toBe(true)
    })
  })

  describe("disabled", () => {
    it("has data-disabled on root when disabled", () => {
      const wrapper = mount(Slider, {
        props: { modelValue: [50], disabled: true },
      })
      expect(wrapper.attributes("data-disabled")).toBeDefined()
    })

    it("does not have data-disabled when enabled", () => {
      const wrapper = mount(Slider, {
        props: { modelValue: [50], disabled: false },
      })
      expect(wrapper.attributes("data-disabled")).toBeUndefined()
    })
  })

  describe("base styles", () => {
    it("has base layout classes on root", () => {
      const wrapper = mount(Slider, { props: { modelValue: [50] } })
      const classes = wrapper.classes()
      for (const cls of [
        "relative",
        "flex",
        "touch-none",
        "select-none",
        "items-center",
      ]) {
        expect(classes).toContain(cls)
      }
    })

    it("renders a track child element", () => {
      const wrapper = mount(Slider, { props: { modelValue: [50] } })
      const track = wrapper.element.querySelector(":scope > span[data-orientation]")
      expect(track).toBeTruthy()
      expect(track?.className).toContain("rounded-full")
      expect(track?.className).toContain("bg-secondary")
    })

    it("renders a range element inside the track", () => {
      const wrapper = mount(Slider, { props: { modelValue: [50] } })
      const track = wrapper.element.querySelector(":scope > span[data-orientation]")
      const range = track?.querySelector(":scope > span")
      expect(range).toBeTruthy()
      expect(range?.className).toContain("absolute")
      expect(range?.className).toContain("bg-primary")
    })

    it("thumb has focus-visible ring classes", () => {
      const wrapper = mount(Slider, { props: { modelValue: [50] } })
      const thumb = wrapper.find('[role="slider"]')
      expect(thumb.classes()).toContain("focus-visible:outline-none")
      expect(thumb.classes()).toContain("focus-visible:ring-2")
      expect(thumb.classes()).toContain("focus-visible:ring-ring")
    })
  })

  describe("custom class", () => {
    it("merges custom class with base classes", () => {
      const wrapper = mount(Slider, {
        props: { modelValue: [50], class: "my-slider" },
      })
      expect(wrapper.classes()).toContain("my-slider")
      expect(wrapper.classes()).toContain("relative")
      expect(wrapper.classes()).toContain("flex")
    })
  })

  describe("step", () => {
    it("accepts a step value", () => {
      const wrapper = mount(Slider, {
        props: { modelValue: [50], step: 10, min: 0, max: 100 },
      })
      // The thumb should exist; step shapes interaction but not DOM directly.
      expect(wrapper.find('[role="slider"]').exists()).toBe(true)
    })
  })
})
