import { describe, it, expect, beforeAll } from "vitest"
import { mount } from "@vue/test-utils"
import { CalendarDate } from "@internationalized/date"
import { Calendar } from "."

beforeAll(() => {
  if (typeof global.ResizeObserver === "undefined") {
    global.ResizeObserver = class {
      observe(): void {}
      unobserve(): void {}
      disconnect(): void {}
    } as unknown as typeof ResizeObserver
  }
})

const fixed = new CalendarDate(2024, 6, 15) // Saturday, 15 June 2024

describe("Calendar", () => {
  describe("default rendering", () => {
    it("renders without errors", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      expect(wrapper.exists()).toBe(true)
    })

    it("applies p-3 padding on the root", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      expect(wrapper.html()).toContain("p-3")
    })

    it("renders a table for the month grid", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      expect(wrapper.find("table").exists()).toBe(true)
    })

    it("renders 7 weekday head cells", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      expect(wrapper.findAll("th").length).toBe(7)
    })

    it("renders chevron icons in the nav buttons", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      expect(wrapper.findAll("svg").length).toBeGreaterThanOrEqual(2)
    })

    it("renders prev and next navigation buttons", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      // Each day is also a button; we just need at least the 2 nav ones.
      expect(wrapper.findAll("button").length).toBeGreaterThanOrEqual(2)
    })

    it("renders a heading", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      // Heading should include "June" and "2024" for the fixed placeholder.
      expect(wrapper.text()).toContain("June")
      expect(wrapper.text()).toContain("2024")
    })
  })

  describe("navigation", () => {
    it("advances the heading when next is clicked", async () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      const buttons = wrapper.findAll("button")
      // The nav buttons sit at the top; find them by aria-label or position.
      const next = buttons.find((b) =>
        (b.attributes("aria-label") ?? "").toLowerCase().includes("next"),
      )
      expect(next).toBeTruthy()
      await next!.trigger("click")
      expect(wrapper.text()).toContain("July")
    })

    it("retreats the heading when prev is clicked", async () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed },
      })
      const buttons = wrapper.findAll("button")
      const prev = buttons.find((b) =>
        (b.attributes("aria-label") ?? "").toLowerCase().includes("previous"),
      )
      expect(prev).toBeTruthy()
      await prev!.trigger("click")
      expect(wrapper.text()).toContain("May")
    })
  })

  describe("value selection", () => {
    it("renders a selected cell when modelValue is provided", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed, modelValue: fixed },
      })
      const selected = wrapper.find("[data-selected]")
      expect(selected.exists()).toBe(true)
    })

    it("accepts a CalendarDate as modelValue without erroring", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed, modelValue: new CalendarDate(2024, 6, 10) },
      })
      expect(wrapper.exists()).toBe(true)
    })
  })

  describe("min/max", () => {
    it("respects minValue (renders days before as disabled)", () => {
      const wrapper = mount(Calendar, {
        props: {
          placeholder: fixed,
          minValue: new CalendarDate(2024, 6, 10),
        },
      })
      // June 1 should be disabled.
      const disabled = wrapper.findAll("[data-disabled]")
      expect(disabled.length).toBeGreaterThan(0)
    })

    it("respects maxValue", () => {
      const wrapper = mount(Calendar, {
        props: {
          placeholder: fixed,
          maxValue: new CalendarDate(2024, 6, 20),
        },
      })
      const disabled = wrapper.findAll("[data-disabled]")
      expect(disabled.length).toBeGreaterThan(0)
    })
  })

  describe("disabled", () => {
    it("renders disabled when disabled prop is true", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed, disabled: true },
      })
      const disabledCells = wrapper.findAll("[data-disabled]")
      expect(disabledCells.length).toBeGreaterThan(0)
    })
  })

  describe("custom class", () => {
    it("merges custom class with p-3", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed, class: "custom-cal" },
      })
      expect(wrapper.html()).toContain("custom-cal")
      expect(wrapper.html()).toContain("p-3")
    })
  })

  describe("locale", () => {
    it("accepts a locale prop", () => {
      const wrapper = mount(Calendar, {
        props: { placeholder: fixed, locale: "en-US" },
      })
      expect(wrapper.exists()).toBe(true)
    })
  })
})
