import type { ReactNode } from 'react'
import {
  Activity,
  Gauge,
  Power,
  Radio,
  Route,
  Timer,
  Wrench,
} from 'lucide-react'

import type { BeaconVibrationSample } from '../../../../entities/beacon/model/types'
import type {
  MachineStateDefinition,
  RecognizedMachineStateInterval,
} from '../../../../entities/machine/model/types'

export type CalibrationTimeRange = {
  end: number
  start: number
}

export type CalibrationRangeStats = {
  avg: number
  count: number
  durationSeconds: number
  end: number
  max: number
  min: number
  p90: number
  p95: number
  start: number
}

export const calibrationIconOptions = [
  {
    value: 'Timer',
    label: 'Таймер',
    description: 'Для простоя и ожидания',
  },
  {
    value: 'Power',
    label: 'Питание',
    description: 'Для заведенного двигателя',
  },
  {
    value: 'Route',
    label: 'Маршрут',
    description: 'Для движения',
  },
  {
    value: 'Activity',
    label: 'Активность',
    description: 'Для рабочего режима',
  },
  {
    value: 'Gauge',
    label: 'Шкала',
    description: 'Для нагрузки и метрик',
  },
  {
    value: 'Wrench',
    label: 'Инструмент',
    description: 'Для сервисного состояния',
  },
]

export function getCalibrationIcon(icon: string, size = 18): ReactNode {
  if (icon === 'Timer') return <Timer size={size} />
  if (icon === 'Power') return <Power size={size} />
  if (icon === 'Route') return <Route size={size} />
  if (icon === 'Radio') return <Radio size={size} />
  if (icon === 'Gauge') return <Gauge size={size} />
  if (icon === 'Wrench') return <Wrench size={size} />

  return <Activity size={size} />
}

export function formatCalibrationDateTime(date: string | number) {
  return new Intl.DateTimeFormat('ru-RU', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  }).format(new Date(date))
}

export function formatCalibrationDuration(totalSeconds: number) {
  const normalizedSeconds = Math.max(0, Math.floor(totalSeconds))
  const totalMinutes = Math.floor(normalizedSeconds / 60)
  const hours = Math.floor(totalMinutes / 60)
  const minutes = totalMinutes % 60

  if (hours > 0) {
    return `${hours} ч ${minutes} мин`
  }

  if (totalMinutes > 0) {
    return `${totalMinutes} мин`
  }

  return `${normalizedSeconds} сек`
}

export function formatVibration(value?: number | null) {
  if (value === null || typeof value === 'undefined') return '—'

  return value.toFixed(3)
}

function getPercentile(sortedValues: number[], percentile: number) {
  if (sortedValues.length === 0) return 0

  const index = Math.min(
    sortedValues.length - 1,
    Math.max(0, Math.ceil((percentile / 100) * sortedValues.length) - 1),
  )

  return sortedValues[index]
}

export function getStateDefinitionById(
  definitions: MachineStateDefinition[],
  id: number | null,
) {
  if (id === null) return null

  return definitions.find((definition) => definition.id === id) ?? null
}

export function getIntervalLabel(
  interval: RecognizedMachineStateInterval,
  definitions: MachineStateDefinition[],
) {
  const definition = getStateDefinitionById(definitions, interval.stateDefinitionId)

  if (definition) return definition.name
  if (interval.isNoData) return 'Нет данных'

  return 'Не распознано'
}

export function getIntervalColor(
  interval: RecognizedMachineStateInterval,
  definitions: MachineStateDefinition[],
) {
  const definition = getStateDefinitionById(definitions, interval.stateDefinitionId)

  if (definition) return definition.color
  if (interval.isNoData) return '#e04f5f'

  return '#8c96aa'
}

export function getIntervalAtTime(
  intervals: RecognizedMachineStateInterval[],
  timeMillis: number,
) {
  return intervals.find((interval) => {
    const startedAt = new Date(interval.startedAt).getTime()
    const endedAt = new Date(interval.endedAt).getTime()

    return startedAt <= timeMillis && endedAt >= timeMillis
  }) ?? null
}

export function getNearestVibrationSample(
  samples: BeaconVibrationSample[],
  timeMillis: number,
) {
  if (samples.length === 0) return null

  let nearestSample = samples[0]
  let nearestDelta = Math.abs(samples[0].timeMillis - timeMillis)

  for (let index = 1; index < samples.length; index += 1) {
    const sample = samples[index]
    const delta = Math.abs(sample.timeMillis - timeMillis)

    if (delta < nearestDelta) {
      nearestSample = sample
      nearestDelta = delta
    }
  }

  return nearestSample
}

export function getCalibrationRangeStats(
  samples: BeaconVibrationSample[],
  range: CalibrationTimeRange | null,
): CalibrationRangeStats | null {
  if (!range) return null

  const start = Math.min(range.start, range.end)
  const end = Math.max(range.start, range.end)
  const rangeSamples = samples.filter((sample) => (
    sample.timeMillis >= start &&
    sample.timeMillis <= end
  ))

  if (rangeSamples.length === 0) return null

  const values = rangeSamples
    .map((sample) => sample.vibration)
    .sort((first, second) => first - second)
  const total = values.reduce((sum, value) => sum + value, 0)
  const durationSeconds = rangeSamples.reduce(
    (sum, sample) => sum + sample.duration,
    0,
  )

  return {
    avg: total / values.length,
    count: values.length,
    durationSeconds,
    end,
    max: values.at(-1) ?? 0,
    min: values[0],
    p90: getPercentile(values, 90),
    p95: getPercentile(values, 95),
    start,
  }
}

export function buildCalibrationTooltip({
  definitions,
  interval,
  sample,
  timeMillis,
}: {
  definitions: MachineStateDefinition[]
  interval: RecognizedMachineStateInterval | null
  sample: BeaconVibrationSample | null
  timeMillis: number
}) {
  const color = interval ? getIntervalColor(interval, definitions) : '#8c96aa'
  const label = interval ? getIntervalLabel(interval, definitions) : 'Не распознано'
  const range = interval
    ? `${formatVibration(interval.vibrationMin)} — ${formatVibration(interval.vibrationMax)}`
    : '—'

  return `
    <div style="min-width:300px;">
      <div style="color:#aeb8cc;font-size:12px;margin-bottom:8px;">
        ${formatCalibrationDateTime(timeMillis)}
      </div>
      <div style="display:grid;grid-template-columns:1fr auto;gap:7px 18px;">
        <span>Вибрация</span>
        <strong>${formatVibration(sample?.vibration)}</strong>
        <span>Длительность</span>
        <strong>${sample ? formatCalibrationDuration(sample.duration) : '—'}</strong>
        <span>Состояние</span>
        <strong style="display:flex;align-items:center;gap:8px;">
          <span style="width:10px;height:10px;border-radius:999px;background:${color};display:inline-block;"></span>
          ${label}
        </strong>
        <span>Диапазон</span>
        <strong>${range}</strong>
      </div>
    </div>
  `
}
