import { describe, it, expect } from "vitest"
import { mount } from "@vue/test-utils"
import { h, nextTick } from "vue"
import {
  Sheet,
  SheetClose,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetOverlay,
  SheetTitle,
  SheetTrigger,
} from "."

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

    it("renders trigger content", () => {
      const wrapper = mount(Sheet, {
        slots: {
          default: () =>
            h(SheetTrigger, { asChild: true }, {
              default: () => h("button", { class: "trigger-btn" }, "Open"),
            }),
        },
      })
      expect(wrapper.find(".trigger-btn").exists()).toBe(true)
      expect(wrapper.find(".trigger-btn").text()).toBe("Open")
    })
  })

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

    it("has correct base classes", () => {
      const wrapper = mount(SheetHeader)
      const classes = wrapper.classes()
      expect(classes).toContain("flex")
      expect(classes).toContain("flex-col")
      expect(classes).toContain("gap-y-2")
      expect(classes).toContain("text-center")
      expect(classes).toContain("sm:text-left")
    })

    it("renders as a div element", () => {
      const wrapper = mount(SheetHeader)
      expect(wrapper.element.tagName).toBe("DIV")
    })

    it("merges custom class", () => {
      const wrapper = mount(SheetHeader, { props: { class: "custom-header" } })
      expect(wrapper.classes()).toContain("custom-header")
      expect(wrapper.classes()).toContain("flex")
    })
  })

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

    it("has correct base classes", () => {
      const wrapper = mount(SheetFooter)
      const classes = wrapper.classes()
      expect(classes).toContain("flex")
      expect(classes).toContain("flex-col-reverse")
      expect(classes).toContain("sm:flex-row")
      expect(classes).toContain("sm:justify-end")
      expect(classes).toContain("sm:gap-x-2")
    })

    it("renders as a div element", () => {
      const wrapper = mount(SheetFooter)
      expect(wrapper.element.tagName).toBe("DIV")
    })

    it("merges custom class", () => {
      const wrapper = mount(SheetFooter, { props: { class: "custom-footer" } })
      expect(wrapper.classes()).toContain("custom-footer")
      expect(wrapper.classes()).toContain("flex")
    })

    it("renders multiple slot children", () => {
      const wrapper = mount(SheetFooter, {
        slots: { default: "<button>Cancel</button><button>Save</button>" },
      })
      expect(wrapper.text()).toContain("Cancel")
      expect(wrapper.text()).toContain("Save")
    })
  })

  describe("Sheet with open content", () => {
    it("renders SheetTitle with correct classes when sheet is open", async () => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, null, {
              default: () =>
                h(SheetHeader, null, {
                  default: () =>
                    h(SheetTitle, null, { default: () => "Test Title" }),
                }),
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const title = document.body.querySelector("h2")
      expect(title).toBeTruthy()
      expect(title?.textContent).toContain("Test Title")
      expect(title?.className).toContain("text-lg")
      expect(title?.className).toContain("font-semibold")
      expect(title?.className).toContain("text-foreground")
    })

    it("renders SheetDescription with correct classes", async () => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, null, {
              default: () => [
                h(SheetTitle, null, { default: () => "T" }),
                h(SheetDescription, null, {
                  default: () => "Test Description",
                }),
              ],
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const description = document.body.querySelector("p")
      expect(description).toBeTruthy()
      expect(description?.textContent).toContain("Test Description")
      expect(description?.className).toContain("text-sm")
      expect(description?.className).toContain("text-muted-foreground")
    })

    it("renders SheetContent with close X button", async () => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, null, {
              default: () => h(SheetTitle, null, { default: () => "T" }),
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const svg = document.body.querySelector("svg")
      expect(svg).toBeTruthy()
      const srOnly = document.body.querySelector(".sr-only")
      expect(srOnly?.textContent).toBe("Close")
    })

    it("renders overlay when sheet is open", async () => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, null, {
              default: () => h(SheetTitle, null, { default: () => "T" }),
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const overlay = document.body.querySelector("[class*=\"bg-black/80\"]")
      expect(overlay).toBeTruthy()
    })

    it("renders content with right side variant classes by default", async () => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, null, {
              default: () => h(SheetTitle, null, { default: () => "T" }),
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const content = document.body.querySelector("[role=\"dialog\"]")
      expect(content).toBeTruthy()
      expect(content?.className).toContain("fixed")
      expect(content?.className).toContain("z-50")
      expect(content?.className).toContain("bg-background")
      expect(content?.className).toContain("p-6")
      expect(content?.className).toContain("shadow-lg")
      expect(content?.className).toContain("inset-y-0")
      expect(content?.className).toContain("right-0")
      expect(content?.className).toContain("h-full")
      expect(content?.className).toContain("w-3/4")
      expect(content?.className).toContain("border-l")
    })

    it.each([
      ["left", ["inset-y-0", "left-0", "h-full", "w-3/4", "border-r"]],
      ["right", ["inset-y-0", "right-0", "h-full", "w-3/4", "border-l"]],
      ["top", ["inset-x-0", "top-0", "border-b"]],
      ["bottom", ["inset-x-0", "bottom-0", "border-t"]],
    ] as const)("renders side=%s with expected classes", async (side, expected) => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, { side }, {
              default: () => h(SheetTitle, null, { default: () => "T" }),
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const content = document.body.querySelector("[role=\"dialog\"]")
      expect(content).toBeTruthy()
      for (const cls of expected) {
        expect(content?.className).toContain(cls)
      }
    })

    it("merges custom class on SheetContent", async () => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, { class: "my-sheet-class" }, {
              default: () => h(SheetTitle, null, { default: () => "T" }),
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const content = document.body.querySelector("[role=\"dialog\"]")
      expect(content?.className).toContain("my-sheet-class")
    })

    it("renders SheetClose inside open sheet", async () => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, null, {
              default: () => [
                h(SheetTitle, null, { default: () => "T" }),
                h(SheetClose, { asChild: true }, {
                  default: () =>
                    h("button", { class: "close-btn" }, "Close Me"),
                }),
              ],
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const closeBtn = document.body.querySelector(".close-btn")
      expect(closeBtn).toBeTruthy()
      expect(closeBtn?.textContent).toBe("Close Me")
    })

    it("renders full sheet structure with header, body, and footer", async () => {
      mount(Sheet, {
        props: { defaultOpen: true },
        slots: {
          default: () =>
            h(SheetContent, null, {
              default: () => [
                h(SheetHeader, null, {
                  default: () => [
                    h(SheetTitle, null, { default: () => "Edit Settings" }),
                    h(SheetDescription, null, {
                      default: () => "Make changes here.",
                    }),
                  ],
                }),
                h("div", { class: "sheet-body" }, "Body content"),
                h(SheetFooter, null, {
                  default: () => h("button", "Save changes"),
                }),
              ],
            }),
        },
        attachTo: document.body,
      })
      await nextTick()
      const title = document.body.querySelector("h2")
      expect(title?.textContent).toContain("Edit Settings")
      const description = document.body.querySelector("p")
      expect(description?.textContent).toContain("Make changes here.")
      expect(document.body.querySelector(".sheet-body")?.textContent).toBe(
        "Body content",
      )
      const footer = document.body.querySelector("[class*=\"flex-col-reverse\"]")
      expect(footer?.textContent).toContain("Save changes")
    })
  })

  describe("SheetOverlay (export)", () => {
    it("exports the SheetOverlay component", () => {
      expect(SheetOverlay).toBeTruthy()
    })
  })
})
