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

describe("Badge", () => {
  describe("default rendering", () => {
    it("renders with default variant and size", () => {
      const wrapper = mount(Badge, { slots: { default: "New" } })
      expect(wrapper.text()).toBe("New")
      expect(wrapper.classes()).toContain("bg-primary")
      expect(wrapper.classes()).toContain("text-primary-foreground")
      expect(wrapper.classes()).toContain("px-2.5")
      expect(wrapper.classes()).toContain("py-0.5")
      expect(wrapper.classes()).toContain("text-xs")
    })

    it("renders as a div element by default", () => {
      const wrapper = mount(Badge, { slots: { default: "Tag" } })
      expect(wrapper.element.tagName).toBe("DIV")
    })

    it("has base layout classes", () => {
      const wrapper = mount(Badge)
      const classes = wrapper.classes()
      for (const cls of [
        "inline-flex",
        "items-center",
        "gap-1",
        "rounded-full",
        "border",
        "font-semibold",
        "transition-colors",
      ]) {
        expect(classes).toContain(cls)
      }
    })
  })

  describe("variants", () => {
    it.each([
      ["default", ["bg-primary", "text-primary-foreground"]],
      ["secondary", ["bg-secondary", "text-secondary-foreground"]],
      ["destructive", ["bg-destructive", "text-destructive-foreground"]],
      ["outline", ["text-foreground"]],
      ["success", ["bg-success", "text-success-foreground"]],
      ["warning", ["bg-warning", "text-warning-foreground"]],
      ["info", ["bg-info", "text-info-foreground"]],
    ] as const)("renders %s variant with expected classes", (variant, expected) => {
      const wrapper = mount(Badge, {
        props: { variant },
        slots: { default: variant },
      })
      for (const cls of expected) {
        expect(wrapper.classes()).toContain(cls)
      }
    })

    it("does not apply primary bg to outline variant", () => {
      const wrapper = mount(Badge, { props: { variant: "outline" } })
      expect(wrapper.classes()).not.toContain("bg-primary")
    })
  })

  describe("sizes", () => {
    it.each([
      ["default", ["px-2.5", "py-0.5", "text-xs"]],
      ["sm", ["px-2", "text-[10px]"]],
      ["lg", ["px-3", "py-1", "text-sm"]],
    ] as const)("renders %s size with expected classes", (size, expected) => {
      const wrapper = mount(Badge, { props: { size } })
      for (const cls of expected) {
        expect(wrapper.classes()).toContain(cls)
      }
    })
  })

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

    it("renders HTML", () => {
      const wrapper = mount(Badge, {
        slots: { default: '<span class="dot">.</span> Online' },
      })
      expect(wrapper.find(".dot").exists()).toBe(true)
      expect(wrapper.text()).toContain("Online")
    })

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

    it("renders empty when no slot", () => {
      const wrapper = mount(Badge)
      expect(wrapper.text()).toBe("")
    })
  })

  describe("custom class", () => {
    it("merges custom class with default classes", () => {
      const wrapper = mount(Badge, { props: { class: "my-custom" } })
      expect(wrapper.classes()).toContain("my-custom")
      expect(wrapper.classes()).toContain("bg-primary")
    })

    it("allows overriding bg via tailwind-merge", () => {
      const wrapper = mount(Badge, { props: { class: "bg-pink-500" } })
      expect(wrapper.classes()).toContain("bg-pink-500")
      expect(wrapper.classes()).not.toContain("bg-primary")
    })
  })

  describe("asChild prop", () => {
    it("renders the child element when asChild is true", () => {
      const wrapper = mount(Badge, {
        props: { asChild: true },
        slots: {
          default: h("a", { href: "/test", class: "child-link" }, "Link"),
        },
      })
      expect(wrapper.find("a").exists()).toBe(true)
      expect(wrapper.find("a").attributes("href")).toBe("/test")
      expect(wrapper.find("a").classes()).toContain("rounded-full")
    })
  })

  describe("as prop", () => {
    it("renders as a span when as='span'", () => {
      const wrapper = mount(Badge, {
        props: { as: "span" },
        slots: { default: "tag" },
      })
      expect(wrapper.element.tagName).toBe("SPAN")
    })
  })
})
