"use client"

import { useState } from "react"
import { TextField } from "react-aria-components"
import {
  Controller,
  type RegisterOptions,
  useFormContext,
} from "react-hook-form"
import { useIntl, type IntlShape } from "react-intl"

import { MaterialIcon } from "../Icons/MaterialIcon"
import { Input } from "../Input"
import { Typography } from "../Typography"

import { NewPasswordValidation } from "./NewPasswordValidation"

import styles from "./passwordInput.module.css"

const defaultErrorFormatter = (
  _intl: IntlShape,
  errorMessage?: string
): string => errorMessage ?? ""

interface PasswordInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
  label?: string
  registerOptions?: RegisterOptions
  visibilityToggleable?: boolean
  isNewPassword?: boolean
  errorFormatter?: (intl: IntlShape, errorMessage?: string) => string
}

export const PasswordInput = ({
  name = "password",
  label,
  "aria-label": ariaLabel,
  disabled = false,
  placeholder,
  registerOptions = {},
  visibilityToggleable = true,
  isNewPassword = false,
  className = "",
  errorFormatter,
}: PasswordInputProps) => {
  const { control } = useFormContext()
  const intl = useIntl()
  const [isPasswordVisible, setIsPasswordVisible] = useState(false)

  const formatErrorMessage = errorFormatter ?? defaultErrorFormatter

  return (
    <Controller
      disabled={disabled}
      control={control}
      name={name}
      rules={registerOptions}
      render={({ field, fieldState, formState }) => {
        const errors = isNewPassword
          ? Object.values(formState.errors[name]?.types ?? []).flat()
          : []

        // Use field.name as base for all IDs - it's already unique per form field
        const errorId = `${field.name}-error`
        const requirementsId = `${field.name}-requirements`
        const inputId = field.name // Already used on line 85

        // Build aria-describedby dynamically based on what exists
        const describedBy =
          [
            fieldState.error ? errorId : null,
            isNewPassword && field.value ? requirementsId : null,
          ]
            .filter(Boolean)
            .join(" ") || undefined

        const hasError = !!fieldState.error
        const showRequirements = isNewPassword && !!field.value

        return (
          <TextField
            className={className}
            aria-label={ariaLabel}
            aria-invalid={hasError}
            aria-describedby={describedBy}
            isDisabled={field.disabled}
            isInvalid={fieldState.invalid}
            name={field.name}
            onBlur={field.onBlur}
            onChange={field.onChange}
            validationBehavior="aria"
            value={field.value}
            type={
              visibilityToggleable && isPasswordVisible ? "text" : "password"
            }
          >
            <div className={styles.inputWrapper}>
              <Input
                {...field}
                id={inputId}
                label={
                  label ||
                  (isNewPassword
                    ? intl.formatMessage({
                        id: "passwordInput.newPasswordLabel",
                        defaultMessage: "New password",
                      })
                    : intl.formatMessage({
                        id: "common.password",
                        defaultMessage: "Password",
                      }))
                }
                placeholder={placeholder}
                type={
                  visibilityToggleable && isPasswordVisible
                    ? "text"
                    : "password"
                }
              />
              {visibilityToggleable ? (
                <button
                  type="button"
                  onClick={() => setIsPasswordVisible((value) => !value)}
                  aria-label={
                    isPasswordVisible
                      ? intl.formatMessage({
                          id: "passwordInput.hidePassword",
                          defaultMessage: "Hide password",
                        })
                      : intl.formatMessage({
                          id: "passwordInput.showPassword",
                          defaultMessage: "Show password",
                        })
                  }
                  aria-controls={inputId}
                  aria-expanded={isPasswordVisible}
                  className={styles.toggleButton}
                >
                  <MaterialIcon
                    icon={isPasswordVisible ? "visibility_off" : "visibility"}
                    size={24}
                  />
                </button>
              ) : null}
            </div>

            {showRequirements ? (
              <NewPasswordValidation
                value={field.value}
                errors={errors}
                id={requirementsId}
              />
            ) : null}

            {hasError && (!isNewPassword || !field.value) ? (
              <ErrorMessage
                errorMessage={fieldState.error?.message}
                formatErrorMessage={formatErrorMessage}
                id={errorId}
              />
            ) : null}
          </TextField>
        )
      }}
    />
  )
}

function ErrorMessage({
  errorMessage,
  formatErrorMessage,
  id,
}: {
  errorMessage?: string
  formatErrorMessage: (intl: IntlShape, errorMessage?: string) => string
  id: string
}) {
  const intl = useIntl()
  return (
    <Typography
      variant="Body/Supporting text (caption)/smRegular"
      className={styles.error}
    >
      <p role="alert" id={id} aria-atomic="true">
        <MaterialIcon
          icon="info"
          color="Icon/Feedback/Error"
          aria-label={intl.formatMessage({
            id: "common.error",
            defaultMessage: "Error",
          })}
        />
        {formatErrorMessage(intl, errorMessage)}
      </p>
    </Typography>
  )
}
