import { useEffect, useMemo, useRef, useState } from "react";
import {
  Button,
  Checker,
  GlassSurface,
  Icon,
  Select,
  SegmentedControl,
  StatusBadge,
  TextField,
  type StatusTone,
} from "@nodedc/ui-react";

import { profileSelectionForConnectionMode } from "../compatibility";
import {
  SUPPORTED_GNSS_MODE,
  SUPPORTED_MOUNT_TYPE,
  gnssModeOptions,
  mountTypeOptions,
  type GnssMode,
  type MountType,
} from "../configuration";
import { runAutomaticSpatialSourceStart } from "../automaticSourceStart";
import {
  isConfirmedLiveState,
  isSoftwareCommandedAcquisition,
  isSourceRuntimeBusy,
  isVendorWriteCapable,
  recoverableAcquisition,
  sourceStatusLabel,
} from "../lifecycle";
import { normalizeProjectName, validateProjectName } from "../projectName";
import type { XgridsK1Controller } from "../runtimeContext";
import type { OperatorPresenceConfirmation } from "../api";

type SessionIntent = "live" | "replay";

const sessionItems = [
  { value: "live", label: "Реальное устройство" },
  { value: "replay", label: "Повтор записи" },
] satisfies Array<{ value: SessionIntent; label: string }>;

const PHYSICAL_ACCEPTANCE = {
  operator_present: true,
  owner_controlled_device: true,
  lixelgo_closed: true,
  battery_storage_confirmed: true,
  expected_physical_state_confirmed: true,
} satisfies OperatorPresenceConfirmation;

export function K1AcquisitionPipeline({
  controller,
  openSpatialScene,
  activateAutomaticSpatialSource,
}: {
  controller: XgridsK1Controller;
  openSpatialScene: () => void;
  activateAutomaticSpatialSource: () => void;
}) {
  const {
    state,
    pendingAction,
    closeApplicationControlSession,
    startCanonicalAcquisition,
    startReplay,
    stop,
    abort,
  } = controller;
  const [sessionIntent, setSessionIntent] = useState<SessionIntent>("live");
  const [projectName, setProjectName] = useState("");
  const [projectNameTouched, setProjectNameTouched] = useState(false);
  const [replayPath, setReplayPath] = useState("");
  const [replaySpeed, setReplaySpeed] = useState("1");
  const [replayLoop, setReplayLoop] = useState(false);
  const [mountType, setMountType] = useState<MountType>(SUPPORTED_MOUNT_TYPE);
  const [gnssMode, setGnssMode] = useState<GnssMode>(SUPPORTED_GNSS_MODE);
  const hydratedAcquisitionId = useRef<string | null>(null);

  const activeAcquisition = recoverableAcquisition(state);
  const preparedAcquisition = activeAcquisition?.state === "prepared" ? activeAcquisition : null;
  const projectNameValidation = validateProjectName(projectName);
  const vendorWriteCapable = isVendorWriteCapable(state);
  const control = state?.application_control_session;
  const controlPhase = control?.state ?? "idle";

  useEffect(() => {
    if (state?.source_mode === "live" || state?.source_mode === "replay") {
      setSessionIntent(state.source_mode);
    } else if (state?.acquisition?.state === "prepared") {
      setSessionIntent("live");
    }
  }, [state?.acquisition?.state, state?.source_mode]);

  useEffect(() => {
    const acquisitionId = preparedAcquisition?.acquisition_id ?? null;
    if (!acquisitionId || hydratedAcquisitionId.current === acquisitionId) return;
    hydratedAcquisitionId.current = acquisitionId;
    setProjectName(preparedAcquisition?.project_name ?? "");
    setProjectNameTouched(false);
  }, [preparedAcquisition?.acquisition_id, preparedAcquisition?.project_name]);

  const isBusy = pendingAction !== null;
  const sourceRuntimeBusy = isSourceRuntimeBusy(state);
  const sessionLocked = sourceRuntimeBusy || activeAcquisition !== null;
  const effectiveSessionIntent: SessionIntent =
    state?.source_mode === "live" || state?.source_mode === "replay"
      ? state.source_mode
      : activeAcquisition
        ? "live"
        : sessionIntent;
  const sourceLabel = sourceStatusLabel(state);
  const relevantAcquisitionFailed = state?.source_mode !== "replay" && state?.acquisition?.state === "failed";
  const sourceTone: StatusTone =
    state?.phase === "error" || relevantAcquisitionFailed
      ? "danger"
      : isConfirmedLiveState(state) || state?.source_mode === "replay"
        ? "success"
        : sourceRuntimeBusy || preparedAcquisition
          ? "warning"
          : "neutral";
  const selectableSessionItems = useMemo(
    () => sessionItems.map((item) => ({ ...item, disabled: sessionLocked })),
    [sessionLocked],
  );
  const preparedCanonicalLaunch =
    preparedAcquisition?.control_mode === "plugin-commanded";
  const launchBlockedByAcquisition =
    activeAcquisition !== null && !preparedCanonicalLaunch;
  const controlRetryBlocked =
    controlPhase === "failed" && control?.can_open !== true;

  const startLive = async () => {
    setProjectNameTouched(true);
    if (
      !state?.k1_ip ||
      sourceRuntimeBusy ||
      launchBlockedByAcquisition ||
      controlRetryBlocked ||
      projectNameValidation.error
    ) return;
    const timezoneName = Intl.DateTimeFormat().resolvedOptions().timeZone || "Etc/UTC";
    await runAutomaticSpatialSourceStart(
      () => startCanonicalAcquisition({
        control: {
          ...PHYSICAL_ACCEPTANCE,
          timezone_name: timezoneName,
        },
        acquisition: {
          project_name: projectNameValidation.value,
          mount_type: SUPPORTED_MOUNT_TYPE,
          gnss_mode: SUPPORTED_GNSS_MODE,
          compatibility_attestation: profileSelectionForConnectionMode(
            state.connection_mode ?? "bridge",
          ),
        },
        physicalAcceptance: PHYSICAL_ACCEPTANCE,
      }),
      activateAutomaticSpatialSource,
      openSpatialScene,
    );
  };

  const submitReplay = async () => {
    const speed = Number(replaySpeed);
    await runAutomaticSpatialSourceStart(
      () => startReplay({
        path: replayPath.trim(),
        speed: Number.isFinite(speed) && speed > 0 ? speed : 1,
        loop: replayLoop,
      }),
      activateAutomaticSpatialSource,
      openSpatialScene,
    );
  };

  return (
    <GlassSurface className="session-panel" padding="lg">
      <header className="panel-heading">
        <div>
          <span className="section-eyebrow">{effectiveSessionIntent === "live" ? "ШАГИ 04–05 · ПРОЕКТ И ПРИЁМ" : "СЛУЖЕБНЫЙ РЕЖИМ"}</span>
          <h2>{effectiveSessionIntent === "live" ? "Назовите проект и запустите приём" : "Повторите запись"}</h2>
        </div>
        <StatusBadge tone={sourceTone}>{sourceLabel}</StatusBadge>
      </header>
      <SegmentedControl
        label="Источник данных"
        value={effectiveSessionIntent}
        items={selectableSessionItems}
        onChange={(intent) => { if (!sessionLocked) setSessionIntent(intent); }}
      />
      {effectiveSessionIntent === "live" ? (
        <div className="session-form">
          <div className="scan-configuration-grid">
            <div className="configuration-field">
              <span className="nodedc-field__description">Тип установки / носитель</span>
              <Select
                label="Тип установки / носитель"
                value={mountType}
                options={mountTypeOptions}
                onChange={setMountType}
                disabled={isBusy || sessionLocked}
                variant="split"
              />
            </div>
            <div className="configuration-field">
              <span className="nodedc-field__description">Режим GNSS</span>
              <Select
                label="Режим GNSS"
                value={gnssMode}
                options={gnssModeOptions}
                onChange={setGnssMode}
                disabled={isBusy || sessionLocked}
                variant="split"
              />
            </div>
          </div>
          <TextField
            label="Название проекта"
            hint="Имя войдёт в единственный канонический START"
            value={projectName}
            onChange={(event) => {
              setProjectName(event.target.value);
              setProjectNameTouched(true);
            }}
            onBlur={() => setProjectName((value) => normalizeProjectName(value))}
            disabled={isBusy || preparedAcquisition !== null || sourceRuntimeBusy}
            autoComplete="off"
            aria-invalid={projectNameTouched && projectNameValidation.error ? true : undefined}
            description={projectNameTouched && projectNameValidation.error
              ? projectNameValidation.error
              : "Отдельной команды сохранения имени на K1 нет: оно отправляется только при START."}
            placeholder="Например, TEST001"
          />
          <Button
            variant="primary"
            icon={<Icon name="activity" />}
            disabled={
              isBusy ||
              !state?.k1_ip ||
              projectNameValidation.error !== null ||
              sourceRuntimeBusy ||
              launchBlockedByAcquisition ||
              controlRetryBlocked
            }
            onClick={() => void startLive()}
          >
            {pendingAction === "live"
              ? controlPhase === "connecting"
                ? "Синхронизация с K1…"
                : controlPhase === "workspace-requested"
                  ? "Входим в рабочее пространство…"
                  : controlPhase === "project-requested"
                    ? "Готовим проект и локальный приём…"
                    : controlPhase === "start-requested" || controlPhase === "initializing"
                      ? "Калибровка оборудования…"
                      : "Запускаем K1 и локальный приём…"
              : preparedCanonicalLaunch
                ? "Продолжить запуск сканирования и приёма"
                : "Запустить сканирование и локальный приём"}
          </Button>
          <p className="start-confirmation-note">
            Нажатие запуска — явное операторское действие для выбранного K1. Автоматических повторов START нет.
          </p>
          {control?.control_socket_open && !activeAcquisition && !isBusy ? (
            <Button
              variant="ghost"
              disabled={isBusy}
              onClick={() => void closeApplicationControlSession()}
            >
              Отменить запуск до START
            </Button>
          ) : null}
          <p className="live-instruction">
            {controlPhase === "failed"
                ? `Диалог остановлен без автоповтора: ${control?.failure?.message || "требуется ручная проверка K1"}`
                : controlPhase === "connecting"
                  ? "Выполняются операции 1–6 записанного диалога; следующий этап ждёт подтверждённый ответ K1."
                  : controlPhase === "workspace-requested"
                    ? "После подтверждённых операций 1–6 выполняется вход в рабочее пространство."
                    : controlPhase === "project-requested"
                      ? "Выполняются операции 8–10 и готовится локальный приём; имя ещё не отправляется на K1."
                      : controlPhase === "start-requested" || controlPhase === "initializing"
                        ? "Калибровка оборудования. Не перемещайте K1; временных переходов и повторных команд нет."
                        : controlPhase === "scanning"
                          ? "K1 подтвердил SCANNING и инициализацию. Остановка доступна в пространственной сцене."
                          : "Одна кнопка выражает намерение запустить сканирование. Совместимость подтверждается живым DeviceInfo; этапы идут строго по записанному порядку и только после ответов K1."}
          </p>
        </div>
      ) : (
        <div className="session-form session-form--replay">
          <TextField label="Путь к записи" hint="Локальный файл исходных данных" value={replayPath} onChange={(event) => setReplayPath(event.target.value)} spellCheck={false} placeholder="sessions/.../capture.tsv" />
          <TextField label="Скорость повтора" hint="Множитель" type="number" min="0.1" step="0.1" value={replaySpeed} onChange={(event) => setReplaySpeed(event.target.value)} />
          <div className="nodedc-field">
            <span className="nodedc-field__description">После последнего кадра начать запись заново.</span>
            <Checker checked={replayLoop} label="Повторять по кругу" onChange={setReplayLoop} />
          </div>
          <Button variant="primary" icon={<Icon name="video" />} disabled={isBusy || sessionLocked || replayPath.trim().length === 0} onClick={() => void submitReplay()}>
            {pendingAction === "replay" ? "Запускаем повтор…" : "Запустить повтор записи"}
          </Button>
        </div>
      )}
      <div className="session-footer">
        <p>
          {state?.source_mode === "replay"
            ? "Остановка завершит фактически запущенный повтор записи."
            : activeAcquisition || state?.source_mode === "live"
              ? vendorWriteCapable && activeAcquisition?.control_mode === "plugin-commanded"
                ? "Остановка отправит профилированную команду K1 и дождётся завершения локального сохранения."
                : "Остановка завершает только локальный приём и сохранение. Физическое состояние сканера остаётся неизвестным."
              : "Активного источника сейчас нет."}
        </p>
        <Button
          variant="secondary"
          disabled={isBusy || (!sourceRuntimeBusy && preparedAcquisition !== null) || (!sourceRuntimeBusy && activeAcquisition === null)}
          onClick={() => void stop(
            isSoftwareCommandedAcquisition(state) ? PHYSICAL_ACCEPTANCE : undefined,
          )}
        >
          {pendingAction === "stop"
            ? state?.source_mode === "replay" ? "Останавливаем повтор…" : "Останавливаем локальный приём…"
            : state?.source_mode === "replay" ? "Остановить повтор" : preparedAcquisition ? "Завершить подготовленный приём" : "Остановить локальный приём"}
        </Button>
        {activeAcquisition ? (
          <Button variant="ghost" disabled={isBusy} onClick={() => void abort()}>
            {pendingAction === "abort" ? "Прерываем локальную операцию…" : preparedAcquisition ? "Отменить подготовку" : "Аварийно завершить локальный приём"}
          </Button>
        ) : null}
      </div>
    </GlassSurface>
  );
}
