import { describe, expect, it, afterEach } from "vitest"
import { render, screen, cleanup } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import { FormProvider, useForm } from "react-hook-form"
import { IntlProvider } from "react-intl"
import { PasswordInput } from "./PasswordInput"

afterEach(() => {
  cleanup()
})

function FormWrapper({
  children,
  defaultValues = { password: "" },
}: {
  children: React.ReactNode
  defaultValues?: Record<string, string>
}) {
  const methods = useForm({ defaultValues })
  return (
    <IntlProvider locale="en" messages={{}}>
      <FormProvider {...methods}>
        <form>{children}</form>
      </FormProvider>
    </IntlProvider>
  )
}

const renderPasswordInput = (
  props: React.ComponentProps<typeof PasswordInput> = {},
  defaultValues?: Record<string, string>
) => {
  return render(
    <FormWrapper defaultValues={defaultValues}>
      <PasswordInput {...props} />
    </FormWrapper>
  )
}

describe("PasswordInput", () => {
  describe("rendering", () => {
    it("renders with default password label", async () => {
      renderPasswordInput()
      expect(await screen.findByLabelText("Password")).toBeTruthy()
    })

    it("renders with custom label", async () => {
      renderPasswordInput({ label: "Enter your password" })
      expect(await screen.findByLabelText("Enter your password")).toBeTruthy()
    })

    it("renders with new password label when isNewPassword is true", async () => {
      renderPasswordInput({ isNewPassword: true })
      expect(await screen.findByLabelText("New password")).toBeTruthy()
    })
  })

  describe("visibility toggle", () => {
    it("shows visibility toggle button by default", async () => {
      renderPasswordInput()
      expect(await screen.findByLabelText("Show password")).toBeTruthy()
    })

    it("hides visibility toggle when visibilityToggleable is false", async () => {
      renderPasswordInput({ visibilityToggleable: false })
      expect(await screen.findByLabelText("Password")).toBeTruthy()
      expect(screen.queryByLabelText("Show password")).toBeNull()
      expect(screen.queryByLabelText("Hide password")).toBeNull()
    })
  })

  describe("disabled state", () => {
    it("disables the input when disabled prop is true", async () => {
      renderPasswordInput({ disabled: true })
      expect(await screen.findByLabelText("Password")).toHaveProperty(
        "disabled",
        true
      )
    })
  })

  describe("form integration", () => {
    it("updates form value when typing", async () => {
      const user = userEvent.setup()
      renderPasswordInput()

      const input = await screen.findByLabelText("Password")
      await user.type(input, "secret123")

      expect(input).toHaveProperty("value", "secret123")
    })

    it("uses custom name prop", async () => {
      const user = userEvent.setup()
      renderPasswordInput({ name: "confirmPassword" }, { confirmPassword: "" })

      const input = await screen.findByLabelText("Password")
      await user.type(input, "test")

      expect(input).toHaveProperty("value", "test")
    })
  })
})
