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

function mountAvatar(props: Record<string, unknown> = {}) {
  return mount(Avatar, {
    props,
    slots: {
      default: () => h(AvatarFallback, null, { default: () => "JD" }),
    },
  })
}

function mountFallbackInAvatar(fallbackProps: Record<string, unknown> = {}, text = "AB") {
  return mount(Avatar, {
    slots: {
      default: () => h(AvatarFallback, fallbackProps, { default: () => text }),
    },
  })
}

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

    it("renders fallback slot content", () => {
      const wrapper = mountAvatar()
      expect(wrapper.text()).toContain("JD")
    })

    it("has base classes", () => {
      const wrapper = mountAvatar()
      const classes = wrapper.classes()
      for (const cls of [
        "relative",
        "inline-flex",
        "items-center",
        "justify-center",
        "overflow-hidden",
        "rounded-full",
        "bg-secondary",
        "shrink-0",
        "select-none",
      ]) {
        expect(classes).toContain(cls)
      }
    })

    it("applies default size when none provided", () => {
      const wrapper = mountAvatar()
      expect(wrapper.classes()).toContain("h-10")
      expect(wrapper.classes()).toContain("w-10")
    })
  })

  describe("sizes", () => {
    it.each([
      ["sm", ["h-8", "w-8", "text-xs"]],
      ["default", ["h-10", "w-10", "text-sm"]],
      ["lg", ["h-16", "w-16", "text-xl"]],
      ["xl", ["h-24", "w-24", "text-3xl"]],
    ] as const)("renders %s size with expected classes", (size, expected) => {
      const wrapper = mountAvatar({ size })
      for (const cls of expected) {
        expect(wrapper.classes()).toContain(cls)
      }
    })
  })

  describe("custom class", () => {
    it("merges custom class with default classes", () => {
      const wrapper = mountAvatar({ class: "my-avatar" })
      expect(wrapper.classes()).toContain("my-avatar")
      expect(wrapper.classes()).toContain("rounded-full")
    })

    it("allows overriding rounded via custom class", () => {
      const wrapper = mountAvatar({ class: "rounded-none" })
      expect(wrapper.classes()).toContain("rounded-none")
      expect(wrapper.classes()).not.toContain("rounded-full")
    })
  })

  describe("AvatarFallback", () => {
    it("renders fallback content", () => {
      const wrapper = mountFallbackInAvatar()
      expect(wrapper.text()).toBe("AB")
    })

    it("has base fallback classes", () => {
      const wrapper = mountFallbackInAvatar()
      const fallback = wrapper.find("span > span")
      expect(fallback.exists()).toBe(true)
      expect(fallback.classes()).toContain("flex")
      expect(fallback.classes()).toContain("items-center")
      expect(fallback.classes()).toContain("justify-center")
    })

    it("accepts custom class", () => {
      const wrapper = mountFallbackInAvatar({ class: "custom-fallback" })
      const fallback = wrapper.find("span > span")
      expect(fallback.classes()).toContain("custom-fallback")
    })

    it("renders fallback when image src is invalid (image error path)", () => {
      const wrapper = mount(Avatar, {
        slots: {
          default: () => [
            h(AvatarImage, { src: "invalid://not-a-real-image" }),
            h(AvatarFallback, null, { default: () => "FB" }),
          ],
        },
      })
      // The fallback should be rendered in jsdom since the image never loads.
      expect(wrapper.text()).toContain("FB")
    })
  })

  describe("AvatarImage", () => {
    it("accepts custom class merged onto the image element", () => {
      const wrapper = mount(Avatar, {
        slots: {
          default: () => h(AvatarImage, { src: "x.png", class: "my-img" }),
        },
      })
      const img = wrapper.find("img")
      expect(img.exists()).toBe(true)
      expect(img.classes()).toContain("my-img")
      expect(img.classes()).toContain("h-full")
      expect(img.classes()).toContain("w-full")
      expect(img.classes()).toContain("object-cover")
    })
  })

  describe("composition", () => {
    it("composes Avatar with Image and Fallback", () => {
      const wrapper = mount(Avatar, {
        slots: {
          default: () => [
            h(AvatarImage, { src: "https://example.com/x.png", alt: "user" }),
            h(AvatarFallback, null, { default: () => "AB" }),
          ],
        },
      })
      expect(wrapper.exists()).toBe(true)
    })
  })
})
