import {
  Button,
  InputGroup,
  Label,
  Section,
  SectionCard,
} from '@blueprintjs/core'
import { css } from '@emotion/css'
import type { PropsOf } from '@emotion/react'
import { useTypedMutation } from '@inject/graphql/graphql'
import { ChangePassword } from '@inject/graphql/mutations'
import CenteredSpinner from '@inject/shared/components/CenteredSpinner'
import type { ChangeEventHandler, FC, FormEventHandler } from 'react'
import { useRef } from 'react'

const passwordInputProps: PropsOf<typeof InputGroup> = {
  required: true,
  type: 'password',
  placeholder: 'New_password123',
  inputClassName: css`
    &:invalid:not(:placeholder-shown),
    &:user-invalid:not(:placeholder-shown) {
      border-color: red !important;
      border: 1px solid;
    }
  `,
  autoComplete: 'new-password',
}

const ChangePasswordSetting: FC<{
  onSubmit: FormEventHandler<HTMLFormElement>
}> = ({ onSubmit }) => {
  const newPasswordRef = useRef<HTMLInputElement>(null)
  const repeatPasswordRef = useRef<HTMLInputElement>(null)
  const oldPasswordRef = useRef<HTMLInputElement>(null)

  const handleNewPasswordChange: ChangeEventHandler<HTMLInputElement> = () => {
    const passwordInput = newPasswordRef.current
    if (!passwordInput) return
    const errors = []
    passwordInput.reportValidity()
    if (passwordInput.validity.tooShort) {
      errors.push('have at least 8 characters')
    }
    if (!/[a-z]/.test(passwordInput.value)) {
      errors.push('contain at least one lowercase letter')
    }
    if (!/[A-Z]/.test(passwordInput.value)) {
      errors.push('contain at least one uppercase letter')
    }
    if (!/[0-9]/.test(passwordInput.value)) {
      errors.push('contain at least one number')
    }
    if (!/[!@#$%^&*_=+-]/.test(passwordInput.value)) {
      errors.push('at least one of these symbols !@#$%^&*_=+-')
    }
    if (errors.length === 0) {
      passwordInput.setCustomValidity('')
    } else {
      passwordInput.setCustomValidity(`Password must ${errors.join(', ')}`)
    }
  }

  const handleRepeatPasswordChange: ChangeEventHandler<
    HTMLInputElement
  > = event => {
    const repeatPasswordInput = repeatPasswordRef.current
    const newPassword = newPasswordRef.current?.value

    if (!repeatPasswordInput) return

    if (event.target.value !== newPassword) {
      repeatPasswordInput.setCustomValidity('Passwords do not match.')
    } else {
      repeatPasswordInput.setCustomValidity('')
    }
  }

  return (
    <SectionCard padded>
      <form onSubmit={onSubmit}>
        <input id='username' autoComplete='username' hidden />
        <Label htmlFor='oldpassword'>
          Current password:
          <InputGroup
            id='oldpassword'
            name='oldpassword'
            inputRef={oldPasswordRef}
            autoComplete='current-password'
            type='password'
            required
          />
        </Label>
        <Label htmlFor='newpassword1'>
          New password:
          <InputGroup
            id='newpassword1'
            name='newpassword1'
            inputRef={newPasswordRef}
            onChange={handleNewPasswordChange}
            {...passwordInputProps}
          />
        </Label>
        <Label htmlFor='newpassword2'>
          New password (again):
          <InputGroup
            id='newpassword2'
            name='newpassword2'
            inputRef={repeatPasswordRef}
            onChange={handleRepeatPasswordChange}
            {...passwordInputProps}
          />
        </Label>
        <Button type='submit' style={{ float: 'right' }}>
          Change password
        </Button>
      </form>
      <p>
        New password must be at least 8 characters long and contain uppercase
        and lowercase letters, number and special symbols (!@#$%^&*_=+-)
      </p>
    </SectionCard>
  )
}

const ChangePasswordForm = () => {
  const [{ data, fetching, error }, mutate] = useTypedMutation(ChangePassword)

  const handler: FormEventHandler<HTMLFormElement> = event => {
    event.preventDefault()
    const oldPassword = event.currentTarget.querySelector(
      '#oldpassword'
    ) as HTMLInputElement
    const newPassword = event.currentTarget.querySelector(
      '#newpassword1'
    ) as HTMLInputElement
    const oldPasswordValue = oldPassword.value
    const newPasswordValue = newPassword.value
    if (oldPasswordValue === newPasswordValue) {
      newPassword.setCustomValidity('The new password must be different')
      return
    }
    mutate({
      newPassword: newPasswordValue,
      newPasswordRepeat: newPasswordValue,
      oldPassword: oldPasswordValue,
    })
  }

  return (
    <Section
      title='Change Password'
      icon='key'
      collapsible
      collapseProps={{ defaultIsOpen: false }}
    >
      {error && (
        <SectionCard padded>
          <p>Error: {error.message}</p>
        </SectionCard>
      )}
      {fetching && <CenteredSpinner />}
      {(!data || !data.passwordChange?.passwordChanged) && (
        <ChangePasswordSetting onSubmit={handler} />
      )}
      {data?.passwordChange?.passwordChanged && <p>Password changed</p>}
    </Section>
  )
}

export default ChangePasswordForm
