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

function makeFile(name: string, size = 1024): File {
  return new File([new Blob([new Uint8Array(size)])], name, {
    type: "application/pdf",
  })
}

describe("DropzoneFile (props-based composition)", () => {
  describe("rendering", () => {
    it("renders the label and dropzone target", () => {
      const wrapper = mount(DropzoneFile, { props: { label: "Document" } })
      expect(wrapper.text()).toContain("Document")
      expect(wrapper.find("[data-testid='dropzone-target']").exists()).toBe(true)
    })

    it("uses the custom placeholder", () => {
      const wrapper = mount(DropzoneFile, {
        props: { label: "X", placeholder: "Drop PDFs here" },
      })
      expect(wrapper.text()).toContain("Drop PDFs here")
    })

    it("hides the visible label when hideLabel is true", () => {
      const wrapper = mount(DropzoneFile, {
        props: { label: "Document", hideLabel: true },
      })
      expect(wrapper.find("[data-testid='field-frame-label-sr']").exists()).toBe(
        true,
      )
    })
  })

  describe("drag and drop", () => {
    it("highlights on dragover and resets on dragleave", async () => {
      const wrapper = mount(DropzoneFile, { props: { label: "X" } })
      const target = wrapper.find("[data-testid='dropzone-target']")
      await target.trigger("dragover")
      expect(target.attributes("data-drag-over")).toBe("true")
      await target.trigger("dragleave")
      expect(target.attributes("data-drag-over")).toBeUndefined()
    })

    it("accepts dropped files and emits update:modelValue", async () => {
      const wrapper = mount(DropzoneFile, { props: { label: "X" } })
      const file = makeFile("a.pdf", 2048)
      const target = wrapper.find("[data-testid='dropzone-target']")
      await target.trigger("drop", {
        dataTransfer: { files: [file] },
      })
      expect(wrapper.text()).toContain("a.pdf")
      const emitted = wrapper.emitted("update:modelValue")
      expect(emitted).toBeTruthy()
      expect(emitted![emitted!.length - 1]).toEqual([file])
    })

    it("ignores drops when disabled", async () => {
      const wrapper = mount(DropzoneFile, {
        props: { label: "X", disabled: true },
      })
      const file = makeFile("a.pdf")
      const target = wrapper.find("[data-testid='dropzone-target']")
      await target.trigger("drop", { dataTransfer: { files: [file] } })
      expect(wrapper.text()).not.toContain("a.pdf")
    })
  })

  describe("click to browse", () => {
    it("accepts files from the input fallback", async () => {
      const wrapper = mount(DropzoneFile, { props: { label: "X" } })
      const inputEl = wrapper.find("[data-testid='dropzone-input']")
        .element as HTMLInputElement
      const f = makeFile("hero.pdf")
      Object.defineProperty(inputEl, "files", { configurable: true, value: [f] })
      await wrapper.find("[data-testid='dropzone-input']").trigger("change")
      expect(wrapper.text()).toContain("hero.pdf")
    })

    it("removes a selected file", async () => {
      const wrapper = mount(DropzoneFile, { props: { label: "X" } })
      const inputEl = wrapper.find("[data-testid='dropzone-input']")
        .element as HTMLInputElement
      const f = makeFile("hero.pdf")
      Object.defineProperty(inputEl, "files", { configurable: true, value: [f] })
      await wrapper.find("[data-testid='dropzone-input']").trigger("change")
      await wrapper.find("[data-testid='dropzone-remove']").trigger("click")
      expect(wrapper.text()).not.toContain("hero.pdf")
    })
  })

  describe("state matrix", () => {
    it("renders help text", () => {
      const wrapper = mount(DropzoneFile, {
        props: { label: "X", helpText: "PDFs only." },
      })
      expect(wrapper.find("[data-testid='field-frame-help']").text()).toBe(
        "PDFs only.",
      )
    })

    it("marks required with an asterisk", () => {
      const wrapper = mount(DropzoneFile, {
        props: { label: "X", required: true },
      })
      expect(wrapper.html()).toContain("after:content-['*']")
    })
  })

  describe("errors", () => {
    it("renders error messages from props", () => {
      const wrapper = mount(DropzoneFile, {
        props: { label: "X", errors: ["Required"] },
      })
      expect(wrapper.find("[data-testid='field-frame-errors']").text()).toContain(
        "Required",
      )
    })
  })

  it("works without any props at all", () => {
    const wrapper = mount(DropzoneFile)
    expect(wrapper.exists()).toBe(true)
  })
})
