import {
  useCallback,
  useEffect,
  useMemo,
  useState,
} from 'react'
import {
  Activity,
  Gauge,
  MousePointer2,
  Pencil,
  Plus,
  SlidersHorizontal,
  Trash2,
  X,
} from 'lucide-react'

import type { BeaconVibrationSample } from '../../../../entities/beacon/model/types'
import {
  machineCalibrationService,
  type MachineCalibrationRulePayload,
} from '../../../../entities/machine/api/machineCalibrationService'
import type {
  Machine,
  MachineCalibrationPeriod,
  MachineCalibrationRule,
  MachineStateDefinition,
  RecognizedMachineStateInterval,
} from '../../../../entities/machine/model/types'
import { ConfirmDangerDialog } from '../../../../widgets/ConfirmDangerDialog/ConfirmDangerDialog'
import {
  Notification,
  type NotificationVariant,
} from '../../../../widgets/Notification/Notification'
import {
  DeviceHistoryPeriodControl,
  type DeviceHistoryPeriodValue,
} from '../../../DevicePage/components/DeviceHistoryPeriodControl/DeviceHistoryPeriodControl'
import {
  MachineCalibrationRuleModal,
  type MachineCalibrationRuleModalSuccess,
} from './MachineCalibrationRuleModal'
import { MachineCalibrationTimelineChart } from './MachineCalibrationTimelineChart'
import {
  MachineStateDefinitionModal,
  type MachineStateDefinitionModalSuccess,
} from './MachineStateDefinitionModal'
import { MachineVibrationChart } from './MachineVibrationChart'
import {
  MachineVibrationHistogramChart,
  type MachineVibrationHistogramBin,
} from './MachineVibrationHistogramChart'
import {
  type CalibrationTimeRange,
  formatCalibrationDateTime,
  formatCalibrationDuration,
  formatVibration,
  getCalibrationRangeStats,
  getCalibrationIcon,
  getIntervalColor,
  getIntervalLabel,
  getStateDefinitionById,
} from './utils'

import './MachineCalibrationTab.scss'

type MachineCalibrationTabProps = {
  canManage: boolean
  machine: Machine
}

type MachineCalibrationData = {
  definitions: MachineStateDefinition[]
  intervals: RecognizedMachineStateInterval[]
  rules: MachineCalibrationRule[]
  samples: BeaconVibrationSample[]
}

type CalibrationNotification = {
  id: number
  variant: NotificationVariant
  title: string
  description?: string
  actionLabel?: string
  autoCloseMs?: number
  showProgress?: boolean
  onAction?: () => void
} | null

const emptyDefinitions: MachineStateDefinition[] = []
const emptyIntervals: RecognizedMachineStateInterval[] = []
const emptyRules: MachineCalibrationRule[] = []
const emptySamples: BeaconVibrationSample[] = []
const noDataStateDefinitionId = 4
const undoNotificationMs = 7000

function getSampleStats(samples: BeaconVibrationSample[]) {
  if (samples.length === 0) {
    return {
      avg: null,
      count: 0,
      max: null,
      min: null,
      lastTime: null,
    }
  }

  const values = samples.map((sample) => sample.vibration)
  const total = values.reduce((sum, value) => sum + value, 0)

  return {
    avg: total / samples.length,
    count: samples.length,
    max: Math.max(...values),
    min: Math.min(...values),
    lastTime: samples.at(-1)?.timeMillis ?? null,
  }
}

function isNoDataStateDefinition(definition: MachineStateDefinition) {
  return definition.id === noDataStateDefinitionId
}

function startOfDay(date: Date) {
  const result = new Date(date)
  result.setHours(0, 0, 0, 0)

  return result
}

function getMachinePeriodBaseDate(machine: Machine) {
  return machine.lastDataReceivedAt
    ? new Date(machine.lastDataReceivedAt)
    : new Date()
}

function getInitialCalibrationPeriod(machine: Machine): MachineCalibrationPeriod {
  const baseDate = getMachinePeriodBaseDate(machine)

  return {
    preset: 'today',
    periodStart: startOfDay(baseDate),
    periodEnd: baseDate,
  }
}

function findRuleForVibrationRange(
  rules: MachineCalibrationRule[],
  range: {
    avg?: number
    max: number
    min: number
  },
) {
  const sortedRules = [...rules]
    .sort((first, second) => first.priority - second.priority)

  if (typeof range.avg === 'number') {
    const avgRule = sortedRules.find((rule) => (
      range.avg !== undefined &&
      range.avg >= rule.vibrationMin &&
      range.avg <= rule.vibrationMax
    ))

    if (avgRule) return avgRule
  }

  return sortedRules.find((rule) => (
    range.min >= rule.vibrationMin &&
    range.max <= rule.vibrationMax
  )) ?? sortedRules.find((rule) => (
    range.min <= rule.vibrationMax &&
    range.max >= rule.vibrationMin
  )) ?? null
}

export function MachineCalibrationTab({
  canManage,
  machine,
}: MachineCalibrationTabProps) {
  const periodBaseDate = useMemo(() => getMachinePeriodBaseDate(machine), [machine])
  const [period, setPeriod] = useState<MachineCalibrationPeriod>(() =>
    getInitialCalibrationPeriod(machine),
  )
  const [data, setData] = useState<MachineCalibrationData | null>(null)
  const [isLoading, setIsLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [isRuleModalOpen, setIsRuleModalOpen] = useState(false)
  const [editingRule, setEditingRule] = useState<MachineCalibrationRule | null>(null)
  const [deletingRule, setDeletingRule] = useState<MachineCalibrationRule | null>(null)
  const [initialRuleValues, setInitialRuleValues] =
    useState<Partial<MachineCalibrationRulePayload> | null>(null)
  const [isRangeSelectionEnabled, setIsRangeSelectionEnabled] = useState(false)
  const [selectedRange, setSelectedRange] =
    useState<CalibrationTimeRange | null>(null)
  const [selectedHistogramBin, setSelectedHistogramBin] =
    useState<MachineVibrationHistogramBin | null>(null)
  const [selectedChartRuleId, setSelectedChartRuleId] = useState<number | null>(null)
  const [isStateModalOpen, setIsStateModalOpen] = useState(false)
  const [editingDefinition, setEditingDefinition] =
    useState<MachineStateDefinition | null>(null)
  const [isDeletingRule, setIsDeletingRule] = useState(false)
  const [notification, setNotification] = useState<CalibrationNotification>(null)
  const definitions = data?.definitions ?? emptyDefinitions
  const intervals = data?.intervals ?? emptyIntervals
  const rules = data?.rules ?? emptyRules
  const samples = data?.samples ?? emptySamples
  const sampleStats = useMemo(() => getSampleStats(samples), [samples])
  const unrecognizedIntervals = useMemo(
    () => intervals.filter((interval) => (
      !interval.isNoData && interval.stateDefinitionId === null
    )),
    [intervals],
  )
  const calibrationMode = useMemo(() => {
    if (samples.length === 0) {
      return {
        className: 'is-empty',
        description: 'За выбранный период сообщений маяка нет.',
        title: 'Нет данных за период',
      }
    }

    if (rules.length === 0) {
      return {
        className: 'is-warning',
        description: 'Выделите участок графика или диапазон гистограммы и создайте первое правило.',
        title: 'Правила не настроены',
      }
    }

    if (unrecognizedIntervals.length > 0) {
      return {
        className: 'is-warning',
        description: `Участков без правила: ${unrecognizedIntervals.length}. Переходные всплески можно не размечать.`,
        title: 'Есть участки вне правил',
      }
    }

    return {
      className: 'is-success',
      description: `Правил: ${rules.length}.`,
      title: 'Есть правила',
    }
  }, [rules.length, samples.length, unrecognizedIntervals.length])
  const selectedRangeStats = useMemo(
    () => getCalibrationRangeStats(samples, selectedRange),
    [samples, selectedRange],
  )
  const selectedRangeRule = useMemo(() => {
    if (!selectedRangeStats) return null

    return findRuleForVibrationRange(rules, {
      avg: selectedRangeStats.avg,
      max: selectedRangeStats.max,
      min: selectedRangeStats.min,
    })
  }, [rules, selectedRangeStats])
  const selectedRangeRuleDefinition = useMemo(() => {
    if (!selectedRangeRule) return null

    return getStateDefinitionById(
      definitions,
      selectedRangeRule.stateDefinitionId,
    )
  }, [definitions, selectedRangeRule])
  const selectedHistogramRule = useMemo(() => {
    if (!selectedHistogramBin) return null

    const ruleById = selectedHistogramBin.ruleId
      ? rules.find((rule) => rule.id === selectedHistogramBin.ruleId)
      : null

    if (ruleById) return ruleById

    return findRuleForVibrationRange(rules, {
      avg: (selectedHistogramBin.start + selectedHistogramBin.end) / 2,
      max: selectedHistogramBin.end,
      min: selectedHistogramBin.start,
    })
  }, [rules, selectedHistogramBin])
  const selectedHistogramRuleDefinition = useMemo(() => {
    if (!selectedHistogramRule) return null

    return getStateDefinitionById(
      definitions,
      selectedHistogramRule.stateDefinitionId,
    )
  }, [definitions, selectedHistogramRule])
  const selectedChartRule = useMemo(() => (
    selectedChartRuleId
      ? rules.find((rule) => rule.id === selectedChartRuleId) ?? null
      : null
  ), [rules, selectedChartRuleId])
  const selectedChartRuleDefinition = useMemo(() => {
    if (!selectedChartRule) return null

    return getStateDefinitionById(
      definitions,
      selectedChartRule.stateDefinitionId,
    )
  }, [definitions, selectedChartRule])
  const tooltipGroupId = useMemo(
    () => `machine-calibration-${machine.id}`,
    [machine.id],
  )

  const handlePeriodChange = useCallback((nextPeriod: DeviceHistoryPeriodValue) => {
    setPeriod(nextPeriod)
    setSelectedRange(null)
    setSelectedHistogramBin(null)
    setSelectedChartRuleId(null)
    setIsRangeSelectionEnabled(false)
  }, [])

  const fetchCalibration = useCallback(async () => {
    setIsLoading(true)
    setError(null)

    try {
      const [nextDefinitions, nextRules, nextSamples, nextIntervals] =
        await Promise.all([
          machineCalibrationService.getMachineStateDefinitions(),
          machineCalibrationService.getMachineCalibrationRules(machine.id),
          machineCalibrationService.getMachineVibrationSamples(machine.id, period),
          machineCalibrationService.getRecognizedStateIntervals(machine.id, period),
        ])

      setData({
        definitions: nextDefinitions,
        intervals: nextIntervals,
        rules: nextRules,
        samples: nextSamples,
      })
    } catch {
      setError('Не удалось загрузить данные калибровки')
      setData(null)
    } finally {
      setIsLoading(false)
    }
  }, [machine.id, period])

  useEffect(() => {
    queueMicrotask(() => {
      fetchCalibration().catch(() => undefined)
    })
  }, [fetchCalibration])

  useEffect(() => {
    function handleCalibrationChange() {
      fetchCalibration().catch(() => undefined)
    }

    window.addEventListener('machine-calibration:change', handleCalibrationChange)

    return () => {
      window.removeEventListener(
        'machine-calibration:change',
        handleCalibrationChange,
      )
    }
  }, [fetchCalibration])

  function showNotification(
    variant: NotificationVariant,
    title: string,
    description?: string,
  ) {
    setNotification({
      description,
      id: Date.now(),
      title,
      variant,
    })
  }

  function showUndoNotification(
    title: string,
    description: string,
    onUndo: () => Promise<void>,
  ) {
    setNotification({
      actionLabel: 'Отменить',
      autoCloseMs: undoNotificationMs,
      description,
      id: Date.now(),
      onAction: () => {
        onUndo().catch(() => {
          showNotification('error', 'Не удалось отменить действие')
        })
      },
      showProgress: true,
      title,
      variant: 'success',
    })
  }

  function handleSelectChartRule(rule: MachineCalibrationRule) {
    setSelectedChartRuleId(rule.id)
    setSelectedRange(null)
    setSelectedHistogramBin(null)
  }

  function handleRangeSelect(range: CalibrationTimeRange | null) {
    setSelectedRange(range)
    setSelectedChartRuleId(null)
  }

  function handleHistogramBinSelect(bin: MachineVibrationHistogramBin | null) {
    setSelectedHistogramBin(bin)
    setSelectedChartRuleId(null)
  }

  function handleOpenCreateRule() {
    setEditingRule(null)
    setInitialRuleValues(null)
    setIsRuleModalOpen(true)
  }

  function handleOpenEditRule(rule: MachineCalibrationRule) {
    setEditingRule(rule)
    setInitialRuleValues(null)
    setIsRuleModalOpen(true)
  }

  function handleOpenReplaceRuleFromRange(rule: MachineCalibrationRule) {
    if (!selectedRangeStats) return

    setEditingRule(rule)
    setInitialRuleValues({
      stateDefinitionId: rule.stateDefinitionId,
      vibrationMax: Number(selectedRangeStats.max.toFixed(3)),
      vibrationMin: Number(selectedRangeStats.min.toFixed(3)),
    })
    setIsRuleModalOpen(true)
  }

  function handleOpenReplaceRuleFromHistogram(rule: MachineCalibrationRule) {
    if (!selectedHistogramBin) return

    setEditingRule(rule)
    setInitialRuleValues({
      stateDefinitionId: rule.stateDefinitionId,
      vibrationMax: Number(selectedHistogramBin.end.toFixed(3)),
      vibrationMin: Number(selectedHistogramBin.start.toFixed(3)),
    })
    setIsRuleModalOpen(true)
  }

  function handleCreateRuleFromRange() {
    if (!selectedRangeStats) return

    setEditingRule(null)
    setInitialRuleValues({
      vibrationMax: Number(selectedRangeStats.max.toFixed(3)),
      vibrationMin: Number(selectedRangeStats.min.toFixed(3)),
    })
    setIsRuleModalOpen(true)
  }

  function handleCreateRuleFromHistogram() {
    if (!selectedHistogramBin) return

    setEditingRule(null)
    setInitialRuleValues({
      vibrationMax: Number(selectedHistogramBin.end.toFixed(3)),
      vibrationMin: Number(selectedHistogramBin.start.toFixed(3)),
    })
    setIsRuleModalOpen(true)
  }

  function handleCreateRuleFromInterval(interval: RecognizedMachineStateInterval) {
    if (
      interval.vibrationMin === null ||
      interval.vibrationMax === null
    ) {
      return
    }

    setEditingRule(null)
    setInitialRuleValues({
      vibrationMax: Number(interval.vibrationMax.toFixed(3)),
      vibrationMin: Number(interval.vibrationMin.toFixed(3)),
    })
    setIsRuleModalOpen(true)
  }

  function handleCancelRangeSelection() {
    setIsRangeSelectionEnabled(false)
    setSelectedRange(null)
  }

  function handleOpenCreateState() {
    setEditingDefinition(null)
    setIsStateModalOpen(true)
  }

  function handleOpenEditState(definition: MachineStateDefinition) {
    if (isNoDataStateDefinition(definition)) return

    setEditingDefinition(definition)
    setIsStateModalOpen(true)
  }

  async function handleRuleModalSuccess(
    context: MachineCalibrationRuleModalSuccess,
  ) {
    await fetchCalibration()

    showUndoNotification(
      context.action === 'create' ? 'Правило добавлено' : 'Правило изменено',
      'Изменение можно отменить, пока идёт индикатор.',
      async () => {
        await machineCalibrationService.restoreCalibrationRules(
          context.previousRules,
        )
        setSelectedChartRuleId(null)
        setSelectedHistogramBin(null)
        setSelectedRange(null)
        await fetchCalibration()
      },
    )
  }

  async function handleStateDefinitionModalSuccess(
    context: MachineStateDefinitionModalSuccess,
  ) {
    await fetchCalibration()

    showUndoNotification(
      context.action === 'create'
        ? 'Состояние добавлено'
        : 'Состояние изменено',
      'Изменение справочника можно отменить, пока идёт индикатор.',
      async () => {
        await machineCalibrationService.restoreMachineStateDefinitions(
          context.previousDefinitions,
        )
        await fetchCalibration()
      },
    )
  }

  async function handleConfirmDeleteRule() {
    if (!deletingRule) return

    try {
      setIsDeletingRule(true)
      const previousRules =
        await machineCalibrationService.getCalibrationRulesSnapshot()

      await machineCalibrationService.deleteMachineCalibrationRule(deletingRule.id)
      setDeletingRule(null)
      setSelectedChartRuleId(null)
      setSelectedHistogramBin(null)
      setSelectedRange(null)
      await fetchCalibration()

      showUndoNotification(
        'Правило удалено',
        'Удаление можно отменить, пока идёт индикатор.',
        async () => {
          await machineCalibrationService.restoreCalibrationRules(previousRules)
          await fetchCalibration()
        },
      )
    } finally {
      setIsDeletingRule(false)
    }
  }

  return (
    <section className="machine-calibration-tab">
      <div className="machine-calibration-toolbar">
        <div>
          <div className="device-card__title">
            <SlidersHorizontal size={18} />
            <h3>Калибровка состояний</h3>
          </div>
        </div>

        <DeviceHistoryPeriodControl
          baseDate={periodBaseDate}
          onChange={handlePeriodChange}
        />
      </div>

      {isLoading && (
        <div className="machine-charts-loading">
          Загрузка калибровки...
        </div>
      )}

      {error ? (
        <div className="machine-page-empty-row">{error}</div>
      ) : (
        <>
          <div className="machine-calibration-stat-grid">
            <div className="machine-calibration-stat">
              <Gauge size={18} />
              <div>
                <span>Средняя вибрация</span>
                <b>{formatVibration(sampleStats.avg)}</b>
              </div>
            </div>
            <div className="machine-calibration-stat">
              <Activity size={18} />
              <div>
                <span>Диапазон</span>
                <b>{formatVibration(sampleStats.min)} — {formatVibration(sampleStats.max)}</b>
              </div>
            </div>
            <div className="machine-calibration-stat">
              <SlidersHorizontal size={18} />
              <div>
                <span>Сообщений маяка</span>
                <b>{sampleStats.count}</b>
              </div>
            </div>
            <div className="machine-calibration-stat">
              <Activity size={18} />
              <div>
                <span>Последнее сообщение</span>
                <b>
                  {sampleStats.lastTime
                    ? formatCalibrationDateTime(sampleStats.lastTime)
                    : 'Нет данных'}
                </b>
              </div>
            </div>
          </div>

          <div className={`machine-calibration-mode ${calibrationMode.className}`}>
            <SlidersHorizontal size={18} />
            <div>
              <span>Режим работы</span>
              <b>{calibrationMode.title}</b>
              <p>{calibrationMode.description}</p>
            </div>
          </div>

          <div className="machine-calibration-layout">
            <div className="machine-calibration-main">
              <div className="device-card machine-calibration-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <Gauge size={18} />
                    <h3>Вибрация маяка</h3>
                  </div>

                  <div className="machine-calibration-card-actions">
                    <button
                      className={
                        isRangeSelectionEnabled
                          ? 'machine-calibration-small-btn is-active'
                          : 'machine-calibration-small-btn'
                      }
                      type="button"
                      onClick={() => setIsRangeSelectionEnabled(true)}
                    >
                      <MousePointer2 size={16} />
                      Выделить период
                    </button>

                    {isRangeSelectionEnabled && (
                      <button
                        className="machine-calibration-small-btn is-muted"
                        type="button"
                        onClick={handleCancelRangeSelection}
                      >
                        <X size={16} />
                        Отмена
                      </button>
                    )}
                  </div>
                </div>

                <MachineVibrationChart
                  definitions={definitions}
                  intervals={intervals}
                  isSelectionMode={isRangeSelectionEnabled}
                  onRangeSelect={handleRangeSelect}
                  onRuleSelect={handleSelectChartRule}
                  rules={rules}
                  selectedRange={selectedRange}
                  samples={samples}
                  tooltipGroupId={tooltipGroupId}
                />

                {selectedChartRule && !selectedRange && (
                  <div className="machine-calibration-selection">
                    <div className="machine-calibration-selection__header">
                      <div>
                        <b>Правило на графике</b>
                        <span>
                          {selectedChartRuleDefinition?.name ?? 'Состояние удалено'}
                        </span>
                      </div>

                      {canManage && (
                        <div className="machine-calibration-selection__actions">
                          <button
                            className="machine-calibration-small-btn"
                            type="button"
                            onClick={() => handleOpenEditRule(selectedChartRule)}
                          >
                            <Pencil size={16} />
                            Редактировать
                          </button>
                          <button
                            className="machine-calibration-small-btn is-danger"
                            type="button"
                            onClick={() => setDeletingRule(selectedChartRule)}
                          >
                            <Trash2 size={16} />
                            Удалить
                          </button>
                        </div>
                      )}
                    </div>

                    <div className="machine-calibration-selection__stats machine-calibration-selection__stats--rule">
                      <div>
                        <span>vibration от</span>
                        <b>{formatVibration(selectedChartRule.vibrationMin)}</b>
                      </div>
                      <div>
                        <span>vibration до</span>
                        <b>{formatVibration(selectedChartRule.vibrationMax)}</b>
                      </div>
                    </div>
                  </div>
                )}

                {isRangeSelectionEnabled && !selectedRange && (
                  <div className="machine-calibration-selection-hint">
                    Зажмите и протяните по графику
                  </div>
                )}

                {selectedRange && (
                  <div className="machine-calibration-selection">
                    {selectedRangeStats ? (
                      <>
                        <div className="machine-calibration-selection__header">
                          <div>
                            <b>Выделенный период</b>
                            <span>
                              {formatCalibrationDateTime(selectedRangeStats.start)}
                              {' — '}
                              {formatCalibrationDateTime(selectedRangeStats.end)}
                            </span>
                            {selectedRangeRule && (
                              <span className="machine-calibration-selection__rule">
                                Правило: {selectedRangeRuleDefinition?.name ?? 'Состояние удалено'}
                              </span>
                            )}
                          </div>

                          {canManage && (
                            <div className="machine-calibration-selection__actions">
                              {selectedRangeRule ? (
                                <>
                                  <button
                                    className="machine-calibration-small-btn"
                                    type="button"
                                    onClick={() => handleOpenReplaceRuleFromRange(
                                      selectedRangeRule,
                                    )}
                                  >
                                    <Pencil size={16} />
                                    Заменить
                                  </button>
                                  <button
                                    className="machine-calibration-small-btn is-danger"
                                    type="button"
                                    onClick={() => setDeletingRule(selectedRangeRule)}
                                  >
                                    <Trash2 size={16} />
                                    Удалить
                                  </button>
                                </>
                              ) : (
                                <button
                                  className="machine-calibration-small-btn"
                                  type="button"
                                  onClick={handleCreateRuleFromRange}
                                >
                                  <Plus size={16} />
                                  Создать правило
                                </button>
                              )}
                            </div>
                          )}
                        </div>

                        <div className="machine-calibration-selection__stats">
                          <div>
                            <span>min</span>
                            <b>{formatVibration(selectedRangeStats.min)}</b>
                          </div>
                          <div>
                            <span>avg</span>
                            <b>{formatVibration(selectedRangeStats.avg)}</b>
                          </div>
                          <div>
                            <span>max</span>
                            <b>{formatVibration(selectedRangeStats.max)}</b>
                          </div>
                          <div>
                            <span>p90</span>
                            <b>{formatVibration(selectedRangeStats.p90)}</b>
                          </div>
                          <div>
                            <span>p95</span>
                            <b>{formatVibration(selectedRangeStats.p95)}</b>
                          </div>
                          <div>
                            <span>Время</span>
                            <b>{formatCalibrationDuration(selectedRangeStats.durationSeconds)}</b>
                          </div>
                          <div>
                            <span>Сообщений</span>
                            <b>{selectedRangeStats.count}</b>
                          </div>
                        </div>
                      </>
                    ) : (
                      <div className="machine-page-empty-row">
                        Нет сообщений в отрезке
                      </div>
                    )}
                  </div>
                )}
              </div>

              <div className="device-card machine-calibration-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <Gauge size={18} />
                    <h3>Гистограмма вибрации</h3>
                  </div>
                </div>

                <MachineVibrationHistogramChart
                  definitions={definitions}
                  onBinSelect={handleHistogramBinSelect}
                  rules={rules}
                  selectedBin={selectedHistogramBin}
                  samples={samples}
                />

                {selectedHistogramBin && (
                  <div className="machine-calibration-selection">
                    <div className="machine-calibration-selection__header">
                      <div>
                        <b>Диапазон гистограммы</b>
                        <span>{selectedHistogramBin.label}</span>
                        {selectedHistogramRule && (
                          <span className="machine-calibration-selection__rule">
                            Правило: {selectedHistogramRuleDefinition?.name ?? 'Состояние удалено'}
                          </span>
                        )}
                      </div>

                      {canManage && (
                        <div className="machine-calibration-selection__actions">
                          {selectedHistogramRule ? (
                            <>
                              <button
                                className="machine-calibration-small-btn"
                                type="button"
                                onClick={() => handleOpenReplaceRuleFromHistogram(
                                  selectedHistogramRule,
                                )}
                              >
                                <Pencil size={16} />
                                Заменить
                              </button>
                              <button
                                className="machine-calibration-small-btn is-danger"
                                type="button"
                                onClick={() => setDeletingRule(selectedHistogramRule)}
                              >
                                <Trash2 size={16} />
                                Удалить
                              </button>
                            </>
                          ) : (
                            <button
                              className="machine-calibration-small-btn"
                              type="button"
                              onClick={handleCreateRuleFromHistogram}
                            >
                              <Plus size={16} />
                              Создать правило
                            </button>
                          )}
                        </div>
                      )}
                    </div>

                    <div className="machine-calibration-selection__stats machine-calibration-selection__stats--histogram">
                      <div>
                        <span>Время</span>
                        <b>{formatCalibrationDuration(selectedHistogramBin.durationSeconds)}</b>
                      </div>
                      <div>
                        <span>Сообщений</span>
                        <b>{selectedHistogramBin.count}</b>
                      </div>
                      <div>
                        <span>Состояние</span>
                        <b>{selectedHistogramRuleDefinition?.name ?? '—'}</b>
                      </div>
                    </div>
                  </div>
                )}
              </div>

              <div className="device-card machine-calibration-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <Activity size={18} />
                    <h3>Распознанные состояния</h3>
                  </div>
                </div>

                <MachineCalibrationTimelineChart
                  definitions={definitions}
                  intervals={intervals}
                  samples={samples}
                  tooltipGroupId={tooltipGroupId}
                />
              </div>
            </div>

            <aside className="machine-calibration-side">
              <div className="device-card machine-calibration-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <SlidersHorizontal size={18} />
                    <h3>Правила АТТ</h3>
                  </div>
                  {canManage && (
                    <button
                      className="machine-calibration-small-btn"
                      type="button"
                      onClick={handleOpenCreateRule}
                    >
                      <Plus size={16} />
                      Добавить
                    </button>
                  )}
                </div>

                {rules.length === 0 ? (
                  <div className="machine-page-empty-row">
                    Правила для этой АТТ ещё не настроены
                  </div>
                ) : (
                  <div className="machine-calibration-rule-list">
                    {rules.map((rule) => {
                      const definition = getStateDefinitionById(
                        definitions,
                        rule.stateDefinitionId,
                      )

                      return (
                        <div className="machine-calibration-rule" key={rule.id}>
                          <div className="machine-calibration-rule__state">
                            <span style={{ color: definition?.color ?? '#8c96aa' }}>
                              {getCalibrationIcon(definition?.icon ?? 'Activity', 18)}
                            </span>
                            <div>
                              <strong>{definition?.name ?? 'Состояние удалено'}</strong>
                              <small>
                                vibration {formatVibration(rule.vibrationMin)}
                                {' — '}
                                {formatVibration(rule.vibrationMax)}
                              </small>
                            </div>
                          </div>

                          {canManage && (
                            <div className="machine-calibration-rule__actions">
                              <button
                                type="button"
                                onClick={() => handleOpenEditRule(rule)}
                                aria-label="Редактировать правило"
                              >
                                <Pencil size={15} />
                              </button>
                              <button
                                className="is-danger"
                                type="button"
                                onClick={() => setDeletingRule(rule)}
                                aria-label="Удалить правило"
                              >
                                <Trash2 size={15} />
                              </button>
                            </div>
                          )}
                        </div>
                      )
                    })}
                  </div>
                )}
              </div>

              <div className="device-card machine-calibration-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <MousePointer2 size={18} />
                    <h3>Нераспознано</h3>
                  </div>
                </div>

                {unrecognizedIntervals.length === 0 ? (
                  <div className="machine-page-empty-row">
                    Все участки периода покрыты правилами
                  </div>
                ) : (
                  <div className="machine-calibration-unrecognized-list">
                    {unrecognizedIntervals.slice(0, 6).map((interval) => (
                      <div
                        className="machine-calibration-unrecognized"
                        key={interval.id}
                      >
                        <div>
                          <b>
                            {formatCalibrationDuration(interval.durationSeconds)}
                          </b>
                          <span>
                            {formatCalibrationDateTime(interval.startedAt)}
                            {' — '}
                            {formatCalibrationDateTime(interval.endedAt)}
                          </span>
                          <small>
                            vibration {formatVibration(interval.vibrationMin)}
                            {' — '}
                            {formatVibration(interval.vibrationMax)}
                          </small>
                        </div>

                        {canManage && (
                          <button
                            type="button"
                            onClick={() => handleCreateRuleFromInterval(interval)}
                            aria-label="Создать правило из нераспознанного участка"
                          >
                            <Plus size={15} />
                          </button>
                        )}
                      </div>
                    ))}
                  </div>
                )}
              </div>

              <div className="device-card machine-calibration-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <Activity size={18} />
                    <h3>Справочник состояний</h3>
                  </div>
                  {canManage && (
                    <button
                      className="machine-calibration-small-btn"
                      type="button"
                      onClick={handleOpenCreateState}
                    >
                      <Plus size={16} />
                      Добавить
                    </button>
                  )}
                </div>

                <div className="machine-calibration-state-list">
                  {definitions.map((definition) => {
                    const isNoDataDefinition = isNoDataStateDefinition(definition)

                    return (
                      <div className="machine-calibration-state" key={definition.id}>
                        <span
                          className="machine-calibration-state__icon"
                          style={{
                            backgroundColor: `${definition.color}22`,
                            color: definition.color,
                          }}
                        >
                          {getCalibrationIcon(definition.icon, 18)}
                        </span>

                        <div>
                          <strong>
                            {definition.name}
                            {isNoDataDefinition && (
                              <em>Системное</em>
                            )}
                          </strong>
                          <small>{definition.description || 'Описание не указано'}</small>
                        </div>

                        {canManage && (
                          isNoDataDefinition ? (
                            <span
                              className="machine-calibration-state__lock"
                              title="Назначается автоматически"
                            >
                              —
                            </span>
                          ) : (
                            <button
                              type="button"
                              onClick={() => handleOpenEditState(definition)}
                              aria-label="Редактировать состояние"
                            >
                              <Pencil size={15} />
                            </button>
                          )
                        )}
                      </div>
                    )
                  })}
                </div>
              </div>

              <div className="device-card machine-calibration-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <Activity size={18} />
                    <h3>Легенда таймлайна</h3>
                  </div>
                </div>

                <div className="machine-calibration-legend">
                  {intervals.slice(0, 8).map((interval) => (
                    <div className="machine-calibration-legend__item" key={interval.id}>
                      <span
                        style={{
                          backgroundColor: getIntervalColor(interval, definitions),
                        }}
                      />
                      <b>{getIntervalLabel(interval, definitions)}</b>
                      <small>{formatCalibrationDuration(interval.durationSeconds)}</small>
                    </div>
                  ))}
                </div>
              </div>
            </aside>
          </div>
        </>
      )}

      <MachineCalibrationRuleModal
        definitions={definitions}
        initialValues={initialRuleValues}
        machineId={machine.id}
        open={isRuleModalOpen}
        rule={editingRule}
        onCreateState={handleOpenCreateState}
        onOpenChange={(open) => {
          setIsRuleModalOpen(open)

          if (!open) {
            setEditingRule(null)
            setInitialRuleValues(null)
          }
        }}
        onSuccess={handleRuleModalSuccess}
      />

      <MachineStateDefinitionModal
        definition={editingDefinition}
        open={isStateModalOpen}
        onOpenChange={(open) => {
          setIsStateModalOpen(open)

          if (!open) {
            setEditingDefinition(null)
          }
        }}
        onSuccess={handleStateDefinitionModalSuccess}
      />

      <ConfirmDangerDialog
        open={Boolean(deletingRule)}
        title="Удалить правило?"
        description={
          deletingRule
            ? 'Правило калибровки будет удалено только для этой АТТ. Справочник состояний не изменится.'
            : ''
        }
        confirmText="Удалить"
        isLoading={isDeletingRule}
        onOpenChange={(open) => {
          if (!open) {
            setDeletingRule(null)
          }
        }}
        onConfirm={handleConfirmDeleteRule}
      />

      {notification && (
        <Notification
          key={notification.id}
          variant={notification.variant}
          title={notification.title}
          description={notification.description}
          actionLabel={notification.actionLabel}
          autoCloseMs={notification.autoCloseMs}
          showProgress={notification.showProgress}
          onAction={notification.onAction}
          onClose={() => setNotification(null)}
        />
      )}
    </section>
  )
}
