"use client"

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

import { passwordValidators } from "@scandic-hotels/common/utils/zod/passwordValidator"
import Caption from "@scandic-hotels/design-system/Caption"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Input } from "@scandic-hotels/design-system/Input"
import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"

import { getErrorMessage } from "../Input/errors"

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

import type { PasswordValidatorKey } from "@/types/components/form/newPassword"
import type { IconProps, PasswordInputProps } from "./passwordInput"

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

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

        return (
          <TextField
            className={className}
            aria-label={ariaLabel}
            isDisabled={field.disabled}
            isInvalid={fieldState.invalid}
            isRequired={!!registerOptions.required}
            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}
                aria-labelledby={field.name}
                id={field.name}
                label={
                  label ||
                  (isNewPassword
                    ? intl.formatMessage({
                        defaultMessage: "New password",
                      })
                    : intl.formatMessage({
                        defaultMessage: "Password",
                      }))
                }
                placeholder={placeholder}
                type={
                  visibilityToggleable && isPasswordVisible
                    ? "text"
                    : "password"
                }
              />
              {visibilityToggleable ? (
                <Button
                  type="button"
                  variant="icon"
                  size="small"
                  intent="tertiary"
                  onClick={() => setIsPasswordVisible((value) => !value)}
                  aria-label={
                    isPasswordVisible
                      ? intl.formatMessage({
                          defaultMessage: "Hide password",
                        })
                      : intl.formatMessage({
                          defaultMessage: "Show password",
                        })
                  }
                  aria-controls={field.name}
                  className={styles.toggleButton}
                >
                  {isPasswordVisible ? (
                    <MaterialIcon icon="visibility_off" />
                  ) : (
                    <MaterialIcon icon="visibility" />
                  )}
                </Button>
              ) : null}
            </div>

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

            {isNewPassword ? (
              !field.value && fieldState.error ? (
                <Caption className={styles.error} fontOnly>
                  <MaterialIcon icon="info" color="Icon/Feedback/Error" />
                  {getErrorMessage(intl, fieldState.error.message)}
                </Caption>
              ) : null
            ) : fieldState.error ? (
              <Caption className={styles.error} fontOnly>
                <MaterialIcon icon="info" color="Icon/Feedback/Error" />
                {getErrorMessage(intl, fieldState.error.message)}
              </Caption>
            ) : null}
          </TextField>
        )
      }}
    />
  )
}

function Icon({ errorMessage, errors }: IconProps) {
  return errors.includes(errorMessage) ? (
    <MaterialIcon icon="close" color="Icon/Interactive/Accent" size={20} />
  ) : (
    <MaterialIcon icon="check" color="Icon/Feedback/Success" size={20} />
  )
}

function NewPasswordValidation({
  value,
  errors,
}: {
  value: string
  errors: string[]
}) {
  const intl = useIntl()

  if (!value) return null

  function getErrorMessage(key: PasswordValidatorKey) {
    switch (key) {
      case "length":
        return intl.formatMessage(
          {
            defaultMessage: "{min} to {max} characters",
          },
          {
            min: 10,
            max: 40,
          }
        )
      case "hasUppercase":
        return intl.formatMessage(
          {
            defaultMessage: "{count} uppercase letter",
          },
          { count: 1 }
        )
      case "hasLowercase":
        return intl.formatMessage(
          {
            defaultMessage: "{count} lowercase letter",
          },
          { count: 1 }
        )
      case "hasNumber":
        return intl.formatMessage(
          {
            defaultMessage: "{count} number",
          },
          { count: 1 }
        )
      case "hasSpecialChar":
        return intl.formatMessage(
          {
            defaultMessage: "{count} special character",
          },
          { count: 1 }
        )
      case "allowedCharacters":
        return intl.formatMessage({
          defaultMessage: "Only allowed characters",
        })
    }
  }

  return (
    <div className={styles.errors}>
      {Object.entries(passwordValidators).map(([key, { message }]) => (
        <Caption asChild color="black" key={key}>
          <Text className={styles.helpText} slot="description">
            <Icon errorMessage={message} errors={errors} />
            {getErrorMessage(key as PasswordValidatorKey)}
          </Text>
        </Caption>
      ))}
    </div>
  )
}
