import {
  memo,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
  type FormEvent,
} from 'react'
import * as Dialog from '@radix-ui/react-dialog'
import { Check, ChevronDown, KeyRound, X } from 'lucide-react'
import { AnimatePresence, m } from 'framer-motion'
import { AvatarUpload } from '../AvatarUpload/AvatarUpload'

import type {
  Employee,
  EmployeeRole,
} from '../../../../entities/employee/model/types'
import { usersService } from '../../../../entities/employee/api/usersService'
import { MotionDialogContent } from '../../../../shared/ui/MotionDialog/MotionDialog'
import { popoverVariants, uiFadeTransition } from '../../../../shared/lib/motion'

import '../OrganisationSelect/OrganisationSelect.scss'
import './AddEmployeeModal.scss'

type AddEmployeeModalProps = {
  open: boolean
  mode?: 'create' | 'edit'
  employee?: Employee | null
  initialOrganisation?: {
    id: number | string
    name?: string | null
  } | null
  canChangeRole?: boolean
  onOpenChange: (open: boolean) => void
  onSuccess?: () => void | Promise<void>
}

function getUserInitials(lastName: string, firstName: string) {
  const first = lastName.trim()[0] ?? ''
  const second = firstName.trim()[0] ?? ''

  return `${first}${second}`.toUpperCase() || '??'
}

function readFileAsDataUrl(file: File) {
  return new Promise<string>((resolve, reject) => {
    const reader = new FileReader()

    reader.addEventListener('load', () => {
      resolve(String(reader.result ?? ''))
    })
    reader.addEventListener('error', () => {
      reject(reader.error ?? new Error('Не удалось прочитать файл'))
    })
    reader.readAsDataURL(file)
  })
}

export function AddEmployeeModal({
  open,
  mode = 'create',
  employee = null,
  canChangeRole = true,
  onOpenChange,
  onSuccess,
}: AddEmployeeModalProps) {
  const isEditMode = mode === 'edit'

  const [lastName, setLastName] = useState('')
  const [firstName, setFirstName] = useState('')
  const [middleName, setMiddleName] = useState('')
  const [email, setEmail] = useState('')
  const [login, setLogin] = useState('')
  const [password, setPassword] = useState('')
  const [passwordDraft, setPasswordDraft] = useState('')
  const [passwordConfirm, setPasswordConfirm] = useState('')
  const [isPasswordChangeOpen, setIsPasswordChangeOpen] = useState(false)
  const [role, setRole] = useState<EmployeeRole>('USER')

  const [avatarFile, setAvatarFile] = useState<File | null>(null)
  const [avatarPreviewUrl, setAvatarPreviewUrl] = useState('')
  const avatarPreviewUrlRef = useRef('')
  const passwordInputRef = useRef<HTMLInputElement | null>(null)
  const passwordConfirmInputRef = useRef<HTMLInputElement | null>(null)

  const [isSubmitting, setIsSubmitting] = useState(false)
  const [submitError, setSubmitError] = useState<string | null>(null)

  const canConfirmPasswordChange =
    Boolean(passwordDraft) && passwordDraft === passwordConfirm
  const isPasswordActionConfirm = Boolean(passwordDraft)
  const hasPasswordConfirmMismatch =
    isPasswordChangeOpen && Boolean(passwordConfirm) && passwordDraft !== passwordConfirm
  const hasUnconfirmedPasswordDraft = isEditMode && isPasswordChangeOpen

  useEffect(() => {
    avatarPreviewUrlRef.current = avatarPreviewUrl
  }, [avatarPreviewUrl])

  useEffect(() => {
    return () => {
      if (avatarPreviewUrlRef.current) {
        URL.revokeObjectURL(avatarPreviewUrlRef.current)
      }
    }
  }, [])

  useEffect(() => {
    if (!open) return

    clearAvatarDraft()
    setSubmitError(null)

    if (isEditMode && employee) {
      setLastName(employee.lastName ?? '')
      setFirstName(employee.firstName ?? '')
      setMiddleName(employee.middleName ?? '')
      setEmail(employee.email ?? '')
      setLogin(employee.login ?? employee.username ?? '')
      setPassword('')
      setPasswordDraft('')
      setPasswordConfirm('')
      setIsPasswordChangeOpen(false)
      setRole(employee.role ?? 'USER')
      return
    }

    setLastName('')
    setFirstName('')
    setMiddleName('')
    setEmail('')
    setLogin('')
    setPassword('')
    setPasswordDraft('')
    setPasswordConfirm('')
    setIsPasswordChangeOpen(false)
    setRole('USER')
  }, [open, isEditMode, employee])

  useEffect(() => {
    if (!isPasswordChangeOpen) return

    const frameId = window.requestAnimationFrame(() => {
      passwordInputRef.current?.focus()
    })

    return () => {
      window.cancelAnimationFrame(frameId)
    }
  }, [isPasswordChangeOpen])

  function clearAvatarDraft() {
    if (avatarPreviewUrlRef.current) {
      URL.revokeObjectURL(avatarPreviewUrlRef.current)
      avatarPreviewUrlRef.current = ''
    }

    setAvatarFile(null)
    setAvatarPreviewUrl('')
  }

  function handleAvatarChange(file: File, previewUrl: string) {
    if (avatarPreviewUrlRef.current) {
      URL.revokeObjectURL(avatarPreviewUrlRef.current)
      avatarPreviewUrlRef.current = ''
    }

    setAvatarFile(file)
    setAvatarPreviewUrl(previewUrl)
  }

  function handleAvatarReset() {
    clearAvatarDraft()
  }

  function openPasswordChange() {
    if (isSubmitting) return

    setPasswordDraft('')
    setPasswordConfirm('')
    setIsPasswordChangeOpen(true)
  }

  function confirmPasswordChange() {
    if (!canConfirmPasswordChange || isSubmitting) return

    setPassword(passwordDraft)
    setIsPasswordChangeOpen(false)
  }

  function cancelPasswordChange() {
    if (isSubmitting) return

    setPassword('')
    setPasswordDraft('')
    setPasswordConfirm('')
    setIsPasswordChangeOpen(false)
  }

  function closePasswordChange() {
    if (isSubmitting) return

    setPasswordDraft('')
    setPasswordConfirm('')
    setIsPasswordChangeOpen(false)
  }

  function handlePasswordAction() {
    if (isPasswordActionConfirm) {
      confirmPasswordChange()
      return
    }

    closePasswordChange()
  }

  async function getAvatarUrlForSubmit() {
    if (avatarFile) {
      return readFileAsDataUrl(avatarFile)
    }

    return employee?.avatarUrl ?? null
  }

  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault()

    if (isSubmitting) return

    const trimmedLastName = lastName.trim()
    const trimmedFirstName = firstName.trim()
    const trimmedMiddleName = middleName.trim()
    const trimmedEmail = email.trim()
    const trimmedLogin = login.trim()
    const hasPasswordValue = Boolean(password.trim())

    if (
      !trimmedLastName ||
      !trimmedFirstName ||
      !trimmedMiddleName ||
      !trimmedEmail ||
      !trimmedLogin ||
      (!isEditMode && !hasPasswordValue)
    ) {
      return
    }

    if (hasUnconfirmedPasswordDraft) return

    try {
      setIsSubmitting(true)
      setSubmitError(null)

      const avatarUrl = await getAvatarUrlForSubmit()
      const selectedRole = canChangeRole ? role : employee?.role ?? role

      if (isEditMode) {
        if (!employee?.id) return

        await usersService.updateUser(employee.id, {
          lastName: trimmedLastName,
          firstName: trimmedFirstName,
          middleName: trimmedMiddleName,
          email: trimmedEmail,
          login: trimmedLogin,
          ...(hasPasswordValue ? { password } : {}),
          role: selectedRole,
          avatarUrl,
        })
      } else {
        await usersService.createUser({
          lastName: trimmedLastName,
          firstName: trimmedFirstName,
          middleName: trimmedMiddleName,
          email: trimmedEmail,
          login: trimmedLogin,
          password,
          role: selectedRole,
          avatarUrl,
        })
      }

      await onSuccess?.()
      onOpenChange(false)
    } catch (error) {
      setSubmitError(
        error instanceof Error
          ? error.message
          : 'Не удалось сохранить пользователя',
      )
    } finally {
      setIsSubmitting(false)
    }
  }

  return (
    <Dialog.Root open={open} onOpenChange={onOpenChange}>
      <MotionDialogContent
        open={open}
        overlayClassName="add-employee-modal__overlay"
        contentClassName="add-employee-modal"
        motionPreset="fade"
      >
          <div className="add-employee-modal__header">
            <div>
              <Dialog.Title className="add-employee-modal__title">
                {isEditMode ? 'Редактировать' : 'Добавить пользователя'}
              </Dialog.Title>

              <Dialog.Description className="add-employee-modal__description">
                {isEditMode
                  ? 'Изменение данных пользователя Fleet BLE Monitor'
                  : 'Создание пользователя для доступа к Fleet BLE Monitor'}
              </Dialog.Description>
            </div>

            <Dialog.Close
              className="add-employee-modal__close"
              type="button"
              disabled={isSubmitting}
            >
              <X size={20} />
            </Dialog.Close>
          </div>

          <form className="add-employee-form" onSubmit={handleSubmit}>
            <div className="add-employee-layout">
              <div className="avatar-fio-container">
                <AvatarUpload
                  avatarUrl={avatarPreviewUrl || employee?.avatarUrl || ''}
                  initials={getUserInitials(lastName, firstName)}
                  disabled={isSubmitting}
                  hasSelectedFile={Boolean(avatarFile)}
                  onChange={handleAvatarChange}
                  onReset={handleAvatarReset}
                />

                <div className="add-employee-fields__section">
                  <div className="add-employee-fields__title">
                    <span>Рабочий доступ</span>
                    <p>Учётные данные и роль пользователя в Fleet BLE Monitor.</p>
                  </div>

                  <div className="add-employee-form__grid">
                    <label className="add-employee-field">
                      <span>Логин</span>
                      <input
                        value={login}
                        onChange={(event) => setLogin(event.target.value)}
                        placeholder="Например: operator"
                        required
                        disabled={isSubmitting}
                      />
                    </label>

                    <label className="add-employee-field">
                      <span>Email</span>
                      <input
                        value={email}
                        onChange={(event) => setEmail(event.target.value)}
                        placeholder="operator@fleet.local"
                        type="email"
                        required
                        disabled={isSubmitting}
                      />
                    </label>
                  </div>

                  <div className="add-employee-form__grid">
                    <div className="add-employee-field">
                      <span>Роль</span>

                      <EmployeeRoleSelect
                        value={role}
                        onChange={setRole}
                        disabled={isSubmitting || !canChangeRole}
                      />
                    </div>

                    {isEditMode ? (
                      <div className="add-employee-field add-employee-field--password-button">
                        <span>Пароль</span>
                        <div
                          className={[
                            'employee-password-picker',
                            password && 'employee-password-picker--confirmed',
                          ]
                            .filter(Boolean)
                            .join(' ')}
                        >
                          {password ? (
                            <div className="employee-password-picker__status">
                              <KeyRound size={17} />
                              <span>Пароль будет изменён</span>
                            </div>
                          ) : (
                            <button
                              className="employee-password-picker__button"
                              type="button"
                              disabled={isSubmitting}
                              onClick={openPasswordChange}
                            >
                              <KeyRound size={17} />
                              <span>Сменить пароль</span>
                            </button>
                          )}

                          {password && (
                            <button
                              className="employee-password-picker__action"
                              type="button"
                              aria-label="Отменить смену пароля"
                              disabled={isSubmitting}
                              onClick={cancelPasswordChange}
                            >
                              <X size={18} strokeWidth={2.6} />
                            </button>
                          )}
                        </div>
                      </div>
                    ) : (
                      <label className="add-employee-field">
                        <span>Пароль</span>
                        <input
                          value={password}
                          onChange={(event) => setPassword(event.target.value)}
                          placeholder="Введите пароль"
                          type="password"
                          required
                          disabled={isSubmitting}
                        />
                      </label>
                    )}
                  </div>

                  {isEditMode && isPasswordChangeOpen && (
                    <div
                      className={[
                        'add-employee-form__grid',
                        'add-employee-form__grid--credentials',
                        'add-employee-form__grid--password-change-open',
                      ]
                        .filter(Boolean)
                        .join(' ')}
                    >
                      <label className="add-employee-field add-employee-field--password-change">
                        <span>Новый пароль</span>
                        <div className="employee-password-picker employee-password-picker--open">
                          <input
                            ref={passwordInputRef}
                            className="employee-password-picker__input"
                            value={passwordDraft}
                            onChange={(event) => {
                              setPasswordDraft(event.target.value)
                            }}
                            onKeyDown={(event) => {
                              if (event.key === 'Enter') {
                                event.preventDefault()
                                passwordConfirmInputRef.current?.focus()
                              }

                              if (event.key === 'Escape') {
                                closePasswordChange()
                              }
                            }}
                            placeholder="Новый пароль"
                            type="password"
                            disabled={isSubmitting}
                          />
                        </div>
                      </label>

                      <label
                        className={[
                          'add-employee-field',
                          'add-employee-field--password-repeat',
                          hasPasswordConfirmMismatch &&
                            'add-employee-field--password-confirm-error',
                        ]
                          .filter(Boolean)
                          .join(' ')}
                      >
                        <span>Повторите пароль</span>
                        <div className="employee-password-confirm">
                          <input
                            ref={passwordConfirmInputRef}
                            className="employee-password-confirm__input"
                            value={passwordConfirm}
                            onChange={(event) => {
                              setPasswordConfirm(event.target.value)
                            }}
                            onKeyDown={(event) => {
                              if (event.key === 'Enter') {
                                event.preventDefault()
                                confirmPasswordChange()
                              }

                              if (event.key === 'Escape') {
                                closePasswordChange()
                              }
                            }}
                            placeholder="Повторите пароль"
                            type="password"
                            disabled={isSubmitting}
                          />

                          <button
                            className={[
                              'employee-password-picker__action',
                              isPasswordActionConfirm &&
                                'employee-password-picker__action--confirm',
                            ]
                              .filter(Boolean)
                              .join(' ')}
                            type="button"
                            aria-label={
                              isPasswordActionConfirm
                                ? 'Подтвердить новый пароль'
                                : 'Отменить смену пароля'
                            }
                            disabled={
                              isSubmitting ||
                              (isPasswordActionConfirm && !canConfirmPasswordChange)
                            }
                            onClick={handlePasswordAction}
                          >
                            {isPasswordActionConfirm ? (
                              <Check size={21} strokeWidth={2.7} />
                            ) : (
                              <X size={18} strokeWidth={2.6} />
                            )}
                          </button>
                        </div>
                      </label>
                    </div>
                  )}
                </div>
              </div>

              <div className="add-employee-fields">
                <div className="add-employee-fields__section">
                  <div className="add-employee-fields__title">
                    <span>ФИО</span>
                    <p>Данные пользователя, которые будут отображаться в системе.</p>
                  </div>

                  <label className="add-employee-field">
                    <span>Фамилия</span>
                    <input
                      value={lastName}
                      onChange={(event) => setLastName(event.target.value)}
                      placeholder="Например: Иванов"
                      required
                      disabled={isSubmitting}
                    />
                  </label>

                  <div className="add-employee-form__grid">
                    <label className="add-employee-field">
                      <span>Имя</span>
                      <input
                        value={firstName}
                        onChange={(event) => setFirstName(event.target.value)}
                        placeholder="Например: Иван"
                        required
                        disabled={isSubmitting}
                      />
                    </label>

                    <label className="add-employee-field">
                      <span>Отчество</span>
                      <input
                        value={middleName}
                        onChange={(event) => setMiddleName(event.target.value)}
                        placeholder="Например: Иванович"
                        required
                        disabled={isSubmitting}
                      />
                    </label>
                  </div>
                </div>
              </div>
            </div>

            {submitError && (
              <div className="add-employee-error">
                {submitError}
              </div>
            )}

            <div className="add-employee-modal__footer">
              <Dialog.Close
                className="add-employee-cancel"
                type="button"
                disabled={isSubmitting}
              >
                Отмена
              </Dialog.Close>

              <button
                className="add-employee-submit"
                type="submit"
                disabled={isSubmitting || hasUnconfirmedPasswordDraft}
              >
                {isSubmitting
                  ? isEditMode
                    ? 'Сохранение...'
                    : 'Добавление...'
                  : isEditMode
                    ? 'Сохранить'
                    : 'Добавить'}
              </button>
            </div>
          </form>
      </MotionDialogContent>
    </Dialog.Root>
  )
}

const roleOptions: Array<{
  value: EmployeeRole
  label: string
  description: string
}> = [
  {
    value: 'USER',
    label: 'Пользователь',
    description: 'Просмотр списка пользователей без управления доступами',
  },
  {
    value: 'ADMIN',
    label: 'Администратор',
    description: 'Создание, редактирование и удаление пользователей',
  },
]

type EmployeeRoleSelectProps = {
  value: EmployeeRole
  disabled?: boolean
  onChange: (value: EmployeeRole) => void
}

const EmployeeRoleSelect = memo(function EmployeeRoleSelect({
  value,
  disabled = false,
  onChange,
}: EmployeeRoleSelectProps) {
  const rootRef = useRef<HTMLDivElement | null>(null)
  const [isOpen, setIsOpen] = useState(false)
  const selectedOption = useMemo(
    () => roleOptions.find((option) => option.value === value) ?? roleOptions[0],
    [value],
  )

  useEffect(() => {
    if (!isOpen) return

    function handleDocumentMouseDown(event: MouseEvent) {
      if (!rootRef.current?.contains(event.target as Node)) {
        setIsOpen(false)
      }
    }

    document.addEventListener('mousedown', handleDocumentMouseDown)

    return () => {
      document.removeEventListener('mousedown', handleDocumentMouseDown)
    }
  }, [isOpen])

  useEffect(() => {
    if (disabled) {
      setIsOpen(false)
    }
  }, [disabled])

  const handleToggleOpen = useCallback(() => {
    setIsOpen((prev) => !prev)
  }, [])

  const handleSelect = useCallback((nextRole: EmployeeRole) => {
    onChange(nextRole)
    setIsOpen(false)
  }, [onChange])

  return (
    <div
      className={`organisation-select employee-role-select ${isOpen ? 'is-open' : ''}`}
      ref={rootRef}
    >
      <button
        className="organisation-select__trigger"
        type="button"
        disabled={disabled}
        onClick={handleToggleOpen}
      >
        <span>{selectedOption.label}</span>
        <ChevronDown size={18} />
      </button>

      <AnimatePresence initial={false}>
        {isOpen && (
          <m.div
            className="organisation-select__dropdown employee-role-select__dropdown"
            variants={popoverVariants}
            initial="initial"
            animate="animate"
            exit="exit"
            transition={uiFadeTransition}
          >
            <div className="organisation-select__list employee-role-select__list">
              {roleOptions.map((option) => {
                const isSelected = option.value === value

                return (
                  <button
                    className={`organisation-select__option employee-role-select__option ${
                      isSelected ? 'is-selected' : ''
                    }`}
                    type="button"
                    key={option.value}
                    onClick={() => handleSelect(option.value)}
                  >
                    <span>{option.label}</span>
                    <small>{option.description}</small>
                  </button>
                )
              })}
            </div>
          </m.div>
        )}
      </AnimatePresence>
    </div>
  )
})
