import {
  useEffect,
  useMemo,
  useState,
  type FormEvent,
} from 'react'
import * as Dialog from '@radix-ui/react-dialog'
import { X } from 'lucide-react'

import {
  machineCalibrationService,
  type MachineCalibrationRulePayload,
} from '../../../../entities/machine/api/machineCalibrationService'
import type {
  MachineCalibrationRule,
  MachineStateDefinition,
} from '../../../../entities/machine/model/types'
import { MotionDialogContent } from '../../../../shared/ui/MotionDialog/MotionDialog'
import { MachineSelect } from '../../../MachinesPage/components/MachineSelect/MachineSelect'

import '../../../EmployeesPage/components/AddEmployeeModal/AddEmployeeModal.scss'

type MachineCalibrationRuleModalProps = {
  definitions: MachineStateDefinition[]
  initialValues?: Partial<MachineCalibrationRulePayload> | null
  machineId: number
  open: boolean
  rule?: MachineCalibrationRule | null
  onCreateState?: () => void
  onOpenChange: (open: boolean) => void
  onSuccess: (context: MachineCalibrationRuleModalSuccess) => void | Promise<void>
}

const noDataStateDefinitionId = 4

export type MachineCalibrationRuleModalSuccess = {
  action: 'create' | 'update'
  previousRules: MachineCalibrationRule[]
}

export function MachineCalibrationRuleModal({
  definitions,
  initialValues = null,
  machineId,
  open,
  rule = null,
  onCreateState,
  onOpenChange,
  onSuccess,
}: MachineCalibrationRuleModalProps) {
  const isEditMode = Boolean(rule)
  const [stateDefinitionId, setStateDefinitionId] = useState('')
  const [vibrationMin, setVibrationMin] = useState('')
  const [vibrationMax, setVibrationMax] = useState('')
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [submitError, setSubmitError] = useState<string | null>(null)
  const stateOptions = useMemo(
    () => [...definitions]
      .sort((first, second) => {
        if (first.id === noDataStateDefinitionId) return 1
        if (second.id === noDataStateDefinitionId) return -1

        return first.id - second.id
      })
      .map((definition) => ({
        value: String(definition.id),
        label: definition.name,
        description:
          definition.id === noDataStateDefinitionId
            ? 'Назначается автоматически'
            : definition.description,
        disabled: definition.id === noDataStateDefinitionId,
      })),
    [definitions],
  )

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

    queueMicrotask(() => {
      setSubmitError(null)

      if (rule) {
        setStateDefinitionId(
          initialValues?.stateDefinitionId
            ? String(initialValues.stateDefinitionId)
            : String(rule.stateDefinitionId),
        )
        setVibrationMin(
          typeof initialValues?.vibrationMin === 'number'
            ? String(initialValues.vibrationMin)
            : String(rule.vibrationMin),
        )
        setVibrationMax(
          typeof initialValues?.vibrationMax === 'number'
            ? String(initialValues.vibrationMax)
            : String(rule.vibrationMax),
        )
        return
      }

      setStateDefinitionId(
        initialValues?.stateDefinitionId
          ? String(initialValues.stateDefinitionId)
          : stateOptions[0]?.value ?? '',
      )
      setVibrationMin(
        typeof initialValues?.vibrationMin === 'number'
          ? String(initialValues.vibrationMin)
          : '',
      )
      setVibrationMax(
        typeof initialValues?.vibrationMax === 'number'
          ? String(initialValues.vibrationMax)
          : '',
      )
    })
  }, [initialValues, open, rule, stateOptions])

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

    if (isSubmitting || !stateDefinitionId) return

    const payload: MachineCalibrationRulePayload = {
      stateDefinitionId: Number(stateDefinitionId),
      vibrationMin: Number(vibrationMin),
      vibrationMax: Number(vibrationMax),
    }

    if (
      Number.isNaN(payload.vibrationMin) ||
      Number.isNaN(payload.vibrationMax)
    ) {
      setSubmitError('Укажите диапазон вибрации')
      return
    }

    try {
      setIsSubmitting(true)
      setSubmitError(null)

      const previousRules =
        await machineCalibrationService.getCalibrationRulesSnapshot()

      if (isEditMode && rule) {
        await machineCalibrationService.updateMachineCalibrationRule(rule.id, payload)
      } else {
        await machineCalibrationService.createMachineCalibrationRule(machineId, payload)
      }

      await onSuccess({
        action: isEditMode ? 'update' : 'create',
        previousRules,
      })
      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 machine-calibration-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">
              Диапазон вибрации для распознавания состояния этой АТТ.
            </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-fields__section">
            <div className="add-employee-field">
              <span>Состояние</span>
              <MachineSelect
                actionLabel="Добавить состояние"
                value={stateDefinitionId}
                options={stateOptions}
                placeholder="Выберите состояние"
                emptyText="Состояния не найдены"
                disabled={isSubmitting || (stateOptions.length === 0 && !onCreateState)}
                onAction={onCreateState}
                onChange={setStateDefinitionId}
              />
            </div>

            <div className="add-employee-form__grid">
              <label className="add-employee-field">
                <span>Вибрация от</span>
                <input
                  type="number"
                  step="0.001"
                  min="0"
                  value={vibrationMin}
                  onChange={(event) => setVibrationMin(event.target.value)}
                  placeholder="0.000"
                  disabled={isSubmitting}
                  required
                />
              </label>

              <label className="add-employee-field">
                <span>Вибрация до</span>
                <input
                  type="number"
                  step="0.001"
                  min="0"
                  value={vibrationMax}
                  onChange={(event) => setVibrationMax(event.target.value)}
                  placeholder="0.350"
                  disabled={isSubmitting}
                  required
                />
              </label>
            </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 || !stateDefinitionId}
            >
              {isSubmitting ? 'Сохранение...' : 'Сохранить'}
            </button>
          </div>
        </form>
      </MotionDialogContent>
    </Dialog.Root>
  )
}
