import {
  lazy,
  Suspense,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react'
import * as Dialog from '@radix-ui/react-dialog'
import { X } from 'lucide-react'
import { useQuery } from '@apollo/client/react'
import SimpleBar from 'simplebar-react'
import 'simplebar-react/dist/simplebar.min.css'

import type { Device } from '../../types'
import { conditionText, connectionText } from '../../types'
import {
  GET_TELEMETRY_QUERY,
} from '../../../../entities/device/api/device.graphql'
import type {
  GetTelemetryData,
  GetTelemetryVariables,
  DeviceHistoryChartItem,
  DevicePackageUseEventsGroup,
  DevicePhoneStateEventType
} from '../../../../entities/device/model/types'

import {
  DeviceHistoryPeriodControl,
  type DeviceHistoryPeriodValue,
} from '../DeviceHistoryPeriodControl/DeviceHistoryPeriodControl'
import { TimelineZoom } from '../TimelineZoom/TimelineZoom'
import { MotionDialogContent } from '../../../../shared/ui/MotionDialog/MotionDialog'

import './DeviceHistoryModal.scss'

type DeviceHistoryModalProps = {
  open: boolean
  onOpenChange: (open: boolean) => void
  device: Device
}

const PHONE_STATE_EVENT_LABELS: Record<DevicePhoneStateEventType, string> = {
  ScreenOn: 'Экран включен',
  ScreenOff: 'Экран выключен',
  EnterNetwork: 'В сети',
  LeaveNetwork: 'Не в сети',
  PowerOn: 'Включение',
  PowerOff: 'Выключение',
  Hit: 'Удар',
  Overheat: 'Перегрев',
  PowerAC: 'Зарядка AC',
  PowerUSB: 'Зарядка USB',
  PowerWireless: 'Беспроводная зарядка',
  PowerDisconnected: 'Зарядка отключена',
}

const CHART_MOUNT_DELAY_MS = 160
const EMPTY_HISTORY_ITEMS: DeviceHistoryChartItem[] = []
const EMPTY_PACKAGE_USE_EVENTS: DevicePackageUseEventsGroup[] = []

const DeviceHistoryChart = lazy(() =>
  import('../DeviceHistoryChart/DeviceHistoryChart').then((module) => ({
    default: module.DeviceHistoryChart,
  })),
)

function DeviceHistoryChartPlaceholder() {
  return (
    <div className="device-history-modal__chart-placeholder">
      Подготавливаем графики...
    </div>
  )
}

function getHistoryConditionClass(device: Device) {
  return device.condition === 'inspection' ? 'is-red' : 'is-green'
}

function getHistoryConnectionClass(device: Device) {
  if (device.connection === 'online') return 'is-green'
  if (device.connection === 'offlineDanger') return 'is-red'

  return 'is-gray'
}

export function DeviceHistoryModal({
  open,
  onOpenChange,
  device,
}: DeviceHistoryModalProps) {
  const [selectedPeriod, setSelectedPeriod] =
    useState<DeviceHistoryPeriodValue | null>(null)

  const [zoomRange, setZoomRange] = useState<{
    start: number
    end: number
  } | null>(null)
  const [isChartReady, setIsChartReady] = useState(false)
  const closeFrameRef = useRef<number | null>(null)

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

    setZoomRange({
      start: selectedPeriod.periodStart.getTime(),
      end: selectedPeriod.periodEnd.getTime(),
    })
  }, [selectedPeriod])

  useEffect(() => {
    if (!open) {
      setIsChartReady(false)
      return
    }

    setIsChartReady(false)

    let firstFrameId = 0
    let secondFrameId = 0
    let timeoutId = 0

    firstFrameId = window.requestAnimationFrame(() => {
      secondFrameId = window.requestAnimationFrame(() => {
        timeoutId = window.setTimeout(() => {
          setIsChartReady(true)
        }, CHART_MOUNT_DELAY_MS)
      })
    })

    return () => {
      window.cancelAnimationFrame(firstFrameId)
      window.cancelAnimationFrame(secondFrameId)
      window.clearTimeout(timeoutId)
    }
  }, [device.id, open])

  useEffect(() => {
    return () => {
      if (closeFrameRef.current !== null) {
        window.cancelAnimationFrame(closeFrameRef.current)
      }
    }
  }, [])

  const handleOpenChange = useCallback(
    (nextOpen: boolean) => {
      if (nextOpen) {
        onOpenChange(true)
        return
      }

      setIsChartReady(false)

      if (closeFrameRef.current !== null) {
        window.cancelAnimationFrame(closeFrameRef.current)
      }

      closeFrameRef.current = window.requestAnimationFrame(() => {
        closeFrameRef.current = null
        onOpenChange(false)
      })
    },
    [onOpenChange],
  )

  const shouldRenderChart = Boolean(open && isChartReady && selectedPeriod && zoomRange)

  const telemetryVariables = useMemo<GetTelemetryVariables>(
    () => ({
      phoneId: Number(device.id),
      packagesPhoneId: String(device.id),
      startDate: selectedPeriod?.periodStart.getTime() ?? 0,
      endDate: selectedPeriod?.periodEnd.getTime(),
    }),
    [device.id, selectedPeriod],
  )

  const {
    data: telemetryData,
    loading: telemetryLoading,
    error: telemetryError,
  } = useQuery<GetTelemetryData, GetTelemetryVariables>(GET_TELEMETRY_QUERY, {
    variables: telemetryVariables,
    skip: !shouldRenderChart,
    fetchPolicy: 'network-only',
    //pollInterval: 15000,
  })

  const telemetryWithEvents = useMemo<DeviceHistoryChartItem[]>(() => {
    if (!telemetryData) return EMPTY_HISTORY_ITEMS

    return [
      ...telemetryData.getTelemetry,

      ...telemetryData.getPhoneStateEvents.map(
        (event): DeviceHistoryChartItem => ({
          date: event.date,
          type: 'event',
          eventType: event.type,
          label: PHONE_STATE_EVENT_LABELS[event.type] ?? event.type,
        }),
      ),
    ].sort((a, b) => a.date - b.date)
  }, [telemetryData])

  const packageUseEvents =
    telemetryData?.getPhonePackagesUseEvents ?? EMPTY_PACKAGE_USE_EVENTS

  return (
    <Dialog.Root open={open} onOpenChange={handleOpenChange}>
      <MotionDialogContent
        open={open}
        overlayClassName="device-history-modal__overlay"
        contentClassName="device-history-modal"
        placement="inset"
      >
          <div className="device-history-chart__zoom">
              <div className="device-history-modal__header">
                <div>
                  <Dialog.Title className="device-history-modal__title">
                    {device.factoryNumber}
                    <span>ID: {device.id}</span>
                  </Dialog.Title>

                  <div className="device-history-modal__meta">
                    <span>{device.imei} · {device.imei2}</span>
                    <span className={getHistoryConditionClass(device)}>
                      {conditionText[device.condition]}
                    </span>
                    <span className={getHistoryConnectionClass(device)}>
                      {device.connectionText || connectionText[device.connection]}
                    </span>
                  </div>
                </div>

                <Dialog.Close className="device-history-modal__close" type="button">
                  <X size={22} />
                </Dialog.Close>
              </div>

              <DeviceHistoryPeriodControl onChange={setSelectedPeriod} />
              {selectedPeriod && zoomRange && (
                <TimelineZoom
                  min={selectedPeriod.periodStart.getTime()}
                  max={selectedPeriod.periodEnd.getTime()}
                  start={zoomRange.start}
                  end={zoomRange.end}
                  onChange={setZoomRange}
                />
              )}

          </div>

          <SimpleBar className="device-history-modal__scroll">
            {shouldRenderChart && selectedPeriod && zoomRange ? (
              <Suspense fallback={<DeviceHistoryChartPlaceholder />}>
                <DeviceHistoryChart
                  period={selectedPeriod}
                  zoomRange={zoomRange}
                  telemetry={telemetryWithEvents}
                  packageUseEvents={packageUseEvents}
                  isLoading={telemetryLoading}
                  isError={Boolean(telemetryError)}
                />
              </Suspense>
            ) : (
              <DeviceHistoryChartPlaceholder />
            )}
          </SimpleBar>
      </MotionDialogContent>
    </Dialog.Root>
  )
}
