import {
  lazy,
  Suspense,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
  type ReactNode,
} from 'react'
import {
  useNavigate,
  useOutletContext,
  useParams,
  useSearchParams,
} from 'react-router-dom'
import { AnimatePresence, m } from 'framer-motion'
import {
  ArrowLeft,
  ArrowRight,
  Building2,
  CalendarDays,
  CarFront,
  Clock3,
  FileText,
  Link as LinkIcon,
  Link2Off,
  Pencil,
  Power,
  Radio,
  Route,
  Tag,
  Timer,
  Trash2,
  Truck,
  Wifi,
} from 'lucide-react'

import type { Beacon } from '../../entities/beacon/model/types'
import type {
  BeaconBindingStatus,
  Machine,
  MachineStateCode,
  MachineStateHistoryItem,
} from '../../entities/machine/model/types'
import { machinesService } from '../../entities/machine/api/machinesService'
import {
  formatMachineDateTime,
  getMachineBindingLabel,
  getMachineBindingStatus,
  getMachineStateClass,
  getMachineStateLabel,
} from '../../entities/machine/lib/machineFormatters'
import type { Employee } from '../../entities/employee/model/types'
import { authService } from '../../features/auth/api/authService'
import type { AppLayoutOutletContext } from '../../app/layouts/AppLayout'
import { pageSwapVariants, uiFadeTransition } from '../../shared/lib/motion'
import { EmptyState } from '../../shared/ui/EmptyState/EmptyState'
import { ConfirmDangerDialog } from '../../widgets/ConfirmDangerDialog/ConfirmDangerDialog'
import { AddMachineModal } from '../MachinesPage/components/AddMachineModal/AddMachineModal'
import { BeaconBindingModal } from '../MachinesPage/components/BeaconBindingModal/BeaconBindingModal'

import '../DevicePage/DevicePage.scss'
import './MachinePage.scss'

type MachinePageData = {
  machine: Machine | null
  beacon: Beacon | null
  history: MachineStateHistoryItem[]
}

type MachineStatistic = {
  key: string
  label: string
  value: string
  icon: ReactNode
}

type MachinePageView = 'overview' | 'charts' | 'calibration' | 'history'

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

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

const stateStatisticLabels: Record<MachineStateCode, string> = {
  MOVING: 'В движении',
  ENGINE_ON: 'Заведена',
  IDLE: 'Стояла',
  NO_DATA: 'Без данных',
}

const emptyMachineHistory: MachineStateHistoryItem[] = []

function getMachinePageView(view?: string | null): MachinePageView {
  if (view === 'charts') return 'charts'
  if (view === 'calibration') return 'calibration'
  if (view === 'history') return 'history'

  return 'overview'
}

function formatDuration(totalSeconds?: number | null) {
  if (!totalSeconds || totalSeconds <= 0) return '0 мин'

  const normalizedSeconds = Math.max(0, Math.floor(totalSeconds))
  const totalMinutes = Math.floor(normalizedSeconds / 60)
  const hours = Math.floor(totalMinutes / 60)
  const minutes = totalMinutes % 60
  const seconds = normalizedSeconds % 60

  if (hours > 0) {
    return seconds > 0
      ? `${hours} ч ${minutes} мин ${seconds} сек`
      : `${hours} ч ${minutes} мин`
  }

  if (totalMinutes > 0) {
    return seconds > 0
      ? `${totalMinutes} мин ${seconds} сек`
      : `${totalMinutes} мин`
  }

  return `${seconds} сек`
}

function getHistoryDurationSeconds(item: MachineStateHistoryItem) {
  if (typeof item.durationSeconds === 'number') return item.durationSeconds

  const startedAt = new Date(item.startedAt).getTime()
  const endedAt = item.endedAt
    ? new Date(item.endedAt).getTime()
    : Date.now()

  return Math.max(0, Math.floor((endedAt - startedAt) / 1000))
}

function formatNullable(value?: string | null) {
  return value?.trim() || 'Не указано'
}

function buildStatistics(history: MachineStateHistoryItem[]): MachineStatistic[] {
  const totals: Record<MachineStateCode, number> = {
    IDLE: 0,
    ENGINE_ON: 0,
    MOVING: 0,
    NO_DATA: 0,
  }

  history.forEach((item) => {
    totals[item.state] += getHistoryDurationSeconds(item)
  })

  return [
    {
      key: 'moving',
      label: stateStatisticLabels.MOVING,
      value: formatDuration(totals.MOVING),
      icon: <Route size={18} />,
    },
    {
      key: 'engine-on',
      label: stateStatisticLabels.ENGINE_ON,
      value: formatDuration(totals.ENGINE_ON),
      icon: <Truck size={18} />,
    },
    {
      key: 'idle',
      label: stateStatisticLabels.IDLE,
      value: formatDuration(totals.IDLE),
      icon: <Timer size={18} />,
    },
    {
      key: 'no-data',
      label: stateStatisticLabels.NO_DATA,
      value: formatDuration(totals.NO_DATA),
      icon: <Radio size={18} />,
    },
  ]
}

function getMachineStateBadgeClass(state: MachineStateCode) {
  if (state === 'MOVING') return 'machine-status-badge--blue'
  if (state === 'ENGINE_ON') return 'machine-status-badge--green'
  if (state === 'NO_DATA') return 'machine-status-badge--red'

  return 'machine-status-badge--gray'
}

function getBindingBadgeClass(status: BeaconBindingStatus) {
  return status === 'BOUND'
    ? 'machine-status-badge--green'
    : 'machine-status-badge--gray'
}

function getMachineStateIcon(state: MachineStateCode) {
  if (state === 'MOVING') return <Route size={18} />
  if (state === 'ENGINE_ON') return <Power size={18} />
  if (state === 'NO_DATA') return <Radio size={18} />

  return <Timer size={18} />
}

function getBindingIcon(status: BeaconBindingStatus) {
  return status === 'BOUND'
    ? <Radio size={18} />
    : <Link2Off size={18} />
}

function MachinePassportField({
  icon,
  label,
  value,
}: {
  icon: ReactNode
  label: string
  value: ReactNode
}) {
  return (
    <div className="machine-passport-field">
      <div className="machine-passport-field__icon">{icon}</div>
      <div>
        <span>{label}</span>
        <b>{value}</b>
      </div>
    </div>
  )
}

export function MachinePage() {
  const { machineId } = useParams()
  const navigate = useNavigate()
  const requestIdRef = useRef(0)
  const { setNavbarBreadcrumbs } =
    useOutletContext<AppLayoutOutletContext>()
  const [searchParams, setSearchParams] = useSearchParams()
  const [pageData, setPageData] = useState<MachinePageData | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)
  const [currentUser, setCurrentUser] = useState<Employee | null>(null)
  const [editingMachine, setEditingMachine] = useState<Machine | null>(null)
  const [bindingMachine, setBindingMachine] = useState<Machine | null>(null)
  const [unbindingMachine, setUnbindingMachine] = useState<Machine | null>(null)
  const [deletingMachine, setDeletingMachine] = useState<Machine | null>(null)
  const [isDangerActionLoading, setIsDangerActionLoading] = useState(false)

  const numericMachineId = Number(machineId)
  const activeView = getMachinePageView(searchParams.get('view'))
  const isChartsView = activeView === 'charts'
  const isCalibrationView = activeView === 'calibration'
  const isHistoryView = activeView === 'history'
  const machine = pageData?.machine ?? null
  const beacon = pageData?.beacon ?? null
  const history = pageData?.history ?? emptyMachineHistory
  const canManageMachines = authService.isAdmin(currentUser)
  const bindingStatus = getMachineBindingStatus(machine?.beaconId)
  const statistics = useMemo(() => buildStatistics(history), [history])
  const recentHistory = useMemo(() => history.slice(0, 5), [history])

  const fetchMachine = useCallback(async () => {
    if (!numericMachineId) {
      setPageData(null)
      setLoading(false)
      return
    }

    const requestId = requestIdRef.current + 1
    requestIdRef.current = requestId
    setLoading(true)
    setError(null)

    try {
      const [nextMachine, nextBeacon, nextHistory] = await Promise.all([
        machinesService.getMachineById(numericMachineId),
        machinesService.getMachineBeacon(numericMachineId),
        machinesService.getMachineStateHistory(numericMachineId),
      ])

      if (requestIdRef.current === requestId) {
        setPageData({
          machine: nextMachine,
          beacon: nextBeacon,
          history: nextHistory,
        })
      }
    } catch (fetchError) {
      if (requestIdRef.current === requestId) {
        setError(
          fetchError instanceof Error
            ? fetchError
            : new Error('Не удалось загрузить карточку АТТ'),
        )
      }
    } finally {
      if (requestIdRef.current === requestId) {
        setLoading(false)
      }
    }
  }, [numericMachineId])

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

  useEffect(() => {
    function handleDataChange() {
      fetchMachine().catch(() => undefined)
    }

    window.addEventListener('machines:change', handleDataChange)
    window.addEventListener('beacons:change', handleDataChange)

    return () => {
      window.removeEventListener('machines:change', handleDataChange)
      window.removeEventListener('beacons:change', handleDataChange)
    }
  }, [fetchMachine])

  useEffect(() => {
    let isMounted = true

    async function syncCurrentUser() {
      const user = await authService.getCurrentUser()

      if (isMounted) {
        setCurrentUser(user)
      }
    }

    syncCurrentUser()

    window.addEventListener('auth:change', syncCurrentUser)
    window.addEventListener('users:change', syncCurrentUser)

    return () => {
      isMounted = false
      window.removeEventListener('auth:change', syncCurrentUser)
      window.removeEventListener('users:change', syncCurrentUser)
    }
  }, [])

  useEffect(() => {
    if (!machine) {
      setNavbarBreadcrumbs([])
      return
    }

    const activeViewLabel = isChartsView
      ? 'Графики'
      : isHistoryView
        ? 'История состояний'
        : isCalibrationView
          ? 'Калибровка'
          : null

    setNavbarBreadcrumbs([
      {
        label: machine.name,
        to: activeViewLabel ? `/machines/${machine.id}` : undefined,
      },
      ...(activeViewLabel ? [{ label: activeViewLabel }] : []),
    ])

    return () => {
      setNavbarBreadcrumbs([])
    }
  }, [
    isCalibrationView,
    isChartsView,
    isHistoryView,
    machine,
    setNavbarBreadcrumbs,
  ])

  const handleViewChange = useCallback((view: MachinePageView) => {
    setSearchParams(
      (prev) => {
        const next = new URLSearchParams(prev)

        if (view !== 'overview') {
          next.set('view', view)
          return next
        }

        next.delete('view')

        return next
      },
      {
        replace: true,
      },
    )
  }, [setSearchParams])

  const handleConfirmDeleteMachine = useCallback(async () => {
    if (!deletingMachine || !canManageMachines) return

    try {
      setIsDangerActionLoading(true)
      await machinesService.deleteMachine(deletingMachine.id)
      setDeletingMachine(null)
      navigate('/machines')
    } finally {
      setIsDangerActionLoading(false)
    }
  }, [canManageMachines, deletingMachine, navigate])

  const handleConfirmUnbindBeacon = useCallback(async () => {
    if (!unbindingMachine || !canManageMachines) return

    try {
      setIsDangerActionLoading(true)
      await machinesService.unbindBeacon(unbindingMachine.id)
      setUnbindingMachine(null)
      await fetchMachine()
    } finally {
      setIsDangerActionLoading(false)
    }
  }, [canManageMachines, fetchMachine, unbindingMachine])

  if (!numericMachineId) {
    return (
      <section className="device-page machine-page">
        <EmptyState
          className="device-page__empty"
          variant="not-found"
          title="Некорректный ID АТТ"
          description="Проверьте ссылку или вернитесь к парку АТТ."
        >
          <button type="button" onClick={() => navigate('/machines')}>
            Вернуться к парку АТТ
          </button>
        </EmptyState>
      </section>
    )
  }

  if (loading && !pageData) {
    return (
      <section className="device-page machine-page">
        <div className="device-page__grid machine-page__grid">
          <div className="device-card device-card--main machine-page__loading" />
          <div className="device-card machine-page__loading" />
          <div className="device-card-stats machine-page__loading-stack">
            <div className="device-card machine-page__loading" />
            <div className="device-card machine-page__loading" />
          </div>
        </div>
      </section>
    )
  }

  if (error || !machine) {
    return (
      <section className="device-page machine-page">
        <EmptyState
          className="device-page__empty"
          variant="not-found"
          title="АТТ не найдена"
          description="Возможно, АТТ была удалена или ссылка устарела."
        >
          <button type="button" onClick={() => navigate('/machines')}>
            Вернуться к парку АТТ
          </button>
        </EmptyState>
      </section>
    )
  }

  return (
    <section className={`device-page machine-page ${isHistoryView ? 'machine-page--history' : ''} ${isChartsView ? 'machine-page--charts' : ''} ${isCalibrationView ? 'machine-page--calibration' : ''}`}>
      <div className="machine-page-topbar">
        <button
          className="machine-page-back"
          type="button"
          onClick={() => navigate('/machines')}
          aria-label="Назад к парку АТТ"
        >
          <ArrowLeft size={18} />
        Вернуться к парку АТТ
        </button>
      </div>

      <div className="device-card device-card--main machine-page-passport">
        <div className="machine-page-passport__header">
          <div className="machine-page-passport__summary">
            <div className="machine-page-icon">
              <Truck size={48} />
            </div>

            <div className="machine-page-passport__title">
              <h2>{machine.name}</h2>
              <div className="machine-page-passport__chips">
                <span className={`machine-status-badge ${getMachineStateBadgeClass(machine.lastKnownState)}`}>
                  {getMachineStateIcon(machine.lastKnownState)}
                  {getMachineStateLabel(machine.lastKnownState)}
                </span>
                <span className={`machine-status-badge ${getBindingBadgeClass(bindingStatus)}`}>
                  {getBindingIcon(bindingStatus)}
                  {getMachineBindingLabel(bindingStatus)}
                </span>
                <span className="machine-page-last-data-chip">
                  <Clock3 size={17} />
                  Последние данные: {formatMachineDateTime(machine.lastDataReceivedAt)}
                </span>
              </div>
            </div>
          </div>

          {canManageMachines && (
            <div className="device-card__actions machine-page-actions">
              <button
                className="device-history-btn"
                type="button"
                onClick={() => setEditingMachine(machine)}
              >
                <Pencil size={17} />
                Редактировать
              </button>
              <button
                className="machine-page-action machine-page-action--link"
                type="button"
                onClick={() => {
                  if (machine.beaconId) {
                    setUnbindingMachine(machine)
                    return
                  }

                  setBindingMachine(machine)
                }}
              >
                {machine.beaconId ? <Link2Off size={17} /> : <LinkIcon size={17} />}
                {machine.beaconId ? 'Отвязать маяк' : 'Привязать маяк'}
              </button>
              <button
                className="device-delete-btn machine-page-delete-btn"
                type="button"
                onClick={() => setDeletingMachine(machine)}
              >
                <Trash2 size={17} />
                Удалить
              </button>
            </div>
          )}
        </div>

        <div className="machine-page-passport__details">
          <div className="machine-page-passport__column">
            <MachinePassportField
              icon={<CarFront size={22} />}
              label="Госномер"
              value={machine.licensePlate}
            />
            <MachinePassportField
              icon={<Building2 size={22} />}
              label="Подразделение / участок"
              value={machine.department}
            />
            <MachinePassportField
              icon={<CalendarDays size={22} />}
              label="Дата создания"
              value={formatMachineDateTime(machine.createdAt)}
            />
          </div>

          <div className="machine-page-passport__column">
            <MachinePassportField
              icon={<Tag size={22} />}
              label="Идентификатор маяка"
              value={beacon?.identifier ?? 'Маяк не привязан'}
            />
            <MachinePassportField
              icon={<Wifi size={22} />}
              label="MAC-адрес маяка"
              value={beacon?.macAddress ?? 'Нет данных'}
            />
            <MachinePassportField
              icon={<Clock3 size={22} />}
              label="Последний контакт маяка"
              value={formatMachineDateTime(beacon?.lastSeenAt)}
            />
          </div>

          <div className="machine-page-passport__column">
            <div className="machine-page-description-card">
              <span>Описание</span>
              <p>{formatNullable(machine.description)}</p>
            </div>
          </div>
        </div>
      </div>

      <div className="machine-page-tabs" role="tablist" aria-label="Разделы карточки АТТ">
        <button
          className={activeView === 'overview' ? 'is-active' : ''}
          type="button"
          onClick={() => handleViewChange('overview')}
        >
          Обзор
        </button>
        <button
          className={activeView === 'charts' ? 'is-active' : ''}
          type="button"
          onClick={() => handleViewChange('charts')}
        >
          Графики
        </button>
        <button
          className={activeView === 'calibration' ? 'is-active' : ''}
          type="button"
          onClick={() => handleViewChange('calibration')}
        >
          Калибровка
        </button>
        <button
          className={activeView === 'history' ? 'is-active' : ''}
          type="button"
          onClick={() => handleViewChange('history')}
        >
          История состояний
        </button>
      </div>

      <AnimatePresence mode="wait" initial={false}>
        {isHistoryView ? (
          <m.div
            key="history"
            className="device-page__motion-view"
            variants={pageSwapVariants}
            initial="initial"
            animate="animate"
            exit="exit"
            transition={uiFadeTransition}
          >
            <div className="device-card machine-history-card">
              <div className="device-card__header">
                <div className="device-card__title">
                  <Clock3 size={18} />
                  <h3>История состояний</h3>
                </div>
                <p>По моковым данным состояния АТТ</p>
              </div>

              {history.length === 0 ? (
                <div className="machine-page-empty-row">
                  История состояний пока не заполнена
                </div>
              ) : (
                <table className="machine-history-table">
                  <thead>
                    <tr>
                      <th>Начало</th>
                      <th>Конец</th>
                      <th>Состояние</th>
                      <th>Длительность</th>
                    </tr>
                  </thead>
                  <tbody>
                    {history.map((item) => (
                      <tr key={item.id}>
                        <td>{formatMachineDateTime(item.startedAt)}</td>
                        <td>{item.endedAt ? formatMachineDateTime(item.endedAt) : 'По настоящее время'}</td>
                        <td>
                          <span className={`machine-status-badge machine-status-badge--compact ${getMachineStateBadgeClass(item.state)}`}>
                            {getMachineStateIcon(item.state)}
                            {getMachineStateLabel(item.state)}
                          </span>
                        </td>
                        <td>{formatDuration(getHistoryDurationSeconds(item))}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              )}
            </div>
          </m.div>
        ) : isChartsView ? (
          <m.div
            key="charts"
            className="device-page__motion-view"
            variants={pageSwapVariants}
            initial="initial"
            animate="animate"
            exit="exit"
            transition={uiFadeTransition}
          >
            <Suspense
              fallback={(
                <div className="machine-page-empty-row">
                  Загрузка графиков...
                </div>
              )}
            >
              <MachineChartsTab machine={machine} />
            </Suspense>
          </m.div>
        ) : isCalibrationView ? (
          <m.div
            key="calibration"
            className="device-page__motion-view"
            variants={pageSwapVariants}
            initial="initial"
            animate="animate"
            exit="exit"
            transition={uiFadeTransition}
          >
            <Suspense
              fallback={(
                <div className="machine-page-empty-row">
                  Загрузка калибровки...
                </div>
              )}
            >
              <MachineCalibrationTab
                canManage={canManageMachines}
                machine={machine}
              />
            </Suspense>
          </m.div>
        ) : (
          <m.div
            key="overview"
            className="device-page__motion-view"
            variants={pageSwapVariants}
            initial="initial"
            animate="animate"
            exit="exit"
            transition={uiFadeTransition}
          >
            <div className="machine-page-overview">
              <div className="machine-page-overview__main">
                <div className="device-card machine-stats-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <Timer size={18} />
                    <h3>Краткая статистика</h3>
                  </div>
                  <span className="machine-page-period">За последние 24 часа</span>
                </div>

                <div className="machine-stat-grid">
                  {statistics.map((item) => (
                    <div className={`machine-stat-item machine-stat-item--${item.key}`} key={item.key}>
                      {item.icon}
                      <div>
                        <span>{item.label}</span>
                        <b>{item.value}</b>
                      </div>
                    </div>
                  ))}
                </div>
              </div>

              <div className="device-card machine-recent-history-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <Clock3 size={18} />
                    <h3>Последние смены состояний</h3>
                  </div>
                </div>

                {recentHistory.length === 0 ? (
                  <div className="machine-page-empty-row">
                    История состояний пока не заполнена
                  </div>
                ) : (
                  <>
                    <div className="machine-recent-list">
                      {recentHistory.map((item) => (
                        <div className="machine-recent-item" key={item.id}>
                          <div className="machine-recent-item__state">
                            <span className={`machine-recent-dot ${getMachineStateClass(item.state)}`} />
                            {getMachineStateLabel(item.state)}
                          </div>
                          <div className="machine-recent-item__period">
                            {formatMachineDateTime(item.startedAt)}
                            {' — '}
                            {item.endedAt ? formatMachineDateTime(item.endedAt) : 'По настоящее время'}
                          </div>
                          <strong>{formatDuration(getHistoryDurationSeconds(item))}</strong>
                        </div>
                      ))}
                    </div>
                    <button
                      className="machine-history-link"
                      type="button"
                      onClick={() => handleViewChange('history')}
                    >
                      Перейти к истории состояний
                      <ArrowRight size={17} />
                    </button>
                  </>
                )}
              </div>
              </div>

              <div className="device-card machine-notes-card">
                <div className="device-card__header">
                  <div className="device-card__title">
                    <FileText size={18} />
                    <h3>Примечания</h3>
                  </div>
                </div>
                <div className="machine-notes-card__body">—</div>
              </div>
            </div>
          </m.div>
        )}
      </AnimatePresence>

      <AddMachineModal
        open={Boolean(editingMachine)}
        mode="edit"
        machine={editingMachine}
        onOpenChange={(open) => {
          if (!open) {
            setEditingMachine(null)
          }
        }}
        onSuccess={fetchMachine}
      />

      <BeaconBindingModal
        open={Boolean(bindingMachine)}
        machine={bindingMachine}
        onOpenChange={(open) => {
          if (!open) {
            setBindingMachine(null)
          }
        }}
        onSuccess={fetchMachine}
      />

      <ConfirmDangerDialog
        open={Boolean(deletingMachine)}
        title="Удалить АТТ?"
        description={
          deletingMachine
            ? `АТТ «${deletingMachine.name}» будет удалена из системы. Если к ней привязан маяк, он станет свободным.`
            : ''
        }
        confirmText="Удалить"
        isLoading={isDangerActionLoading}
        onOpenChange={(open) => {
          if (!open) {
            setDeletingMachine(null)
          }
        }}
        onConfirm={handleConfirmDeleteMachine}
      />

      <ConfirmDangerDialog
        open={Boolean(unbindingMachine)}
        title="Отвязать маяк?"
        description={
          unbindingMachine
            ? `Маяк будет отвязан от АТТ «${unbindingMachine.name}» и станет доступен для привязки.`
            : ''
        }
        confirmText="Отвязать"
        isLoading={isDangerActionLoading}
        onOpenChange={(open) => {
          if (!open) {
            setUnbindingMachine(null)
          }
        }}
        onConfirm={handleConfirmUnbindBeacon}
      />
    </section>
  )
}
