import { lazy, Suspense, useEffect, useRef, useState } from "react";
import {
  Button,
  GlassSurface,
  StatusBadge,
} from "@nodedc/ui-react";

import {
  fetchPolygonVehicleState,
  fetchPolygonWorkerStatus,
  sendPolygonRoverCommand,
  startPolygonWorker,
  stopPolygonWorker,
  type PolygonCommandAcceptance,
  type PolygonVehicleState,
  type PolygonWorkerStatus,
} from "../core/polygon/liveWorker";

interface ControlIntent {
  id: "forward" | "reverse" | "left" | "right";
  label: string;
  speedMps: number;
  steeringNormalized: number;
}

const CONTROL_INTENTS: ControlIntent[] = [
  { id: "forward", label: "Вперёд", speedMps: 1, steeringNormalized: 0 },
  { id: "left", label: "Влево", speedMps: 0.8, steeringNormalized: -0.55 },
  { id: "right", label: "Вправо", speedMps: 0.8, steeringNormalized: 0.55 },
  { id: "reverse", label: "Назад", speedMps: -0.65, steeringNormalized: 0 },
];

const PolygonRoverScene = lazy(async () => {
  const module = await import("./PolygonRoverScene");
  return { default: module.PolygonRoverScene };
});

function message(error: unknown): string {
  if (error instanceof Error && error.message.trim()) return error.message;
  return "Simulation Worker не подтвердил операцию.";
}

export function PolygonLivePanel() {
  const [worker, setWorker] = useState<PolygonWorkerStatus | null>(null);
  const [live, setLive] = useState<PolygonVehicleState | null>(null);
  const [trajectory, setTrajectory] = useState<PolygonVehicleState[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [actionBusy, setActionBusy] = useState(false);
  const [controlIntent, setControlIntent] = useState<ControlIntent | null>(null);
  const [commandAcceptance, setCommandAcceptance] =
    useState<PolygonCommandAcceptance | null>(null);
  const [generation, setGeneration] = useState(0);
  const commandInFlight = useRef(false);

  useEffect(() => {
    if (actionBusy) return;
    const controller = new AbortController();
    let timer: number | null = null;
    const poll = async () => {
      try {
        const status = await fetchPolygonWorkerStatus({ signal: controller.signal });
        if (controller.signal.aborted) return;
        setWorker(status);
        setError(null);
        if (status.available && status.activeRunId && status.runState === "running") {
          const state = await fetchPolygonVehicleState({ signal: controller.signal });
          if (controller.signal.aborted) return;
          setLive(state);
          setTrajectory((current) => {
            const sameRun = current[0]?.runId === state.runId;
            const next = sameRun ? [...current, state] : [state];
            return next.slice(-120);
          });
        } else {
          setLive(null);
          if (!status.activeRunId) setTrajectory([]);
        }
      } catch (pollError) {
        if (controller.signal.aborted) return;
        setError(message(pollError));
      } finally {
        if (!controller.signal.aborted) {
          timer = window.setTimeout(() => void poll(), 1_000);
        }
      }
    };
    void poll();
    return () => {
      controller.abort();
      if (timer !== null) window.clearTimeout(timer);
    };
  }, [actionBusy, generation]);

  const runActive = Boolean(worker?.activeRunId);

  useEffect(() => {
    const runId = worker?.activeRunId;
    if (!runId || worker.runState !== "running" || !controlIntent) return;
    const controller = new AbortController();
    let timer: number | null = null;
    const publish = async () => {
      if (commandInFlight.current || controller.signal.aborted) return;
      commandInFlight.current = true;
      try {
        const accepted = await sendPolygonRoverCommand(runId, {
          speedMps: controlIntent.speedMps,
          steeringNormalized: controlIntent.steeringNormalized,
          idempotencyKey: crypto.randomUUID(),
          signal: controller.signal,
        });
        if (controller.signal.aborted) return;
        setCommandAcceptance(accepted);
        setError(null);
      } catch (commandError) {
        if (controller.signal.aborted) return;
        setControlIntent(null);
        setError(message(commandError));
      } finally {
        commandInFlight.current = false;
        if (!controller.signal.aborted) {
          timer = window.setTimeout(() => void publish(), 100);
        }
      }
    };
    void publish();
    return () => {
      controller.abort();
      if (timer !== null) window.clearTimeout(timer);
    };
  }, [controlIntent, worker?.activeRunId, worker?.runState]);

  useEffect(() => {
    if (!worker?.activeRunId) {
      setControlIntent(null);
      setCommandAcceptance(null);
    }
  }, [worker?.activeRunId]);

  const controllerProvider = worker?.providerProfile?.providers.find((provider) =>
    provider.roles.includes("controller"));
  const providerStack = worker?.providerProfile?.providers
    .map((provider) => provider.providerId)
    .join(" · ");

  const stopMotion = async () => {
    const runId = worker?.activeRunId;
    setControlIntent(null);
    if (!runId || worker?.runState !== "running") return;
    try {
      const accepted = await sendPolygonRoverCommand(runId, {
        speedMps: 0,
        steeringNormalized: 0,
        idempotencyKey: crypto.randomUUID(),
      });
      setCommandAcceptance(accepted);
      setError(null);
    } catch (commandError) {
      setError(message(commandError));
    }
  };

  const runAction = async () => {
    if (!worker?.controlAvailable || actionBusy) return;
    setActionBusy(true);
    setError(null);
    try {
      const idempotencyKey = crypto.randomUUID();
      if (worker.activeRunId) {
        await stopMotion();
      }
      const next = worker.activeRunId
        ? await stopPolygonWorker(worker.activeRunId, { idempotencyKey })
        : await startPolygonWorker({ idempotencyKey });
      setWorker(next);
      if (!next.activeRunId) {
        setLive(null);
        setTrajectory([]);
      }
      setGeneration((value) => value + 1);
    } catch (actionError) {
      setError(message(actionError));
    } finally {
      setActionBusy(false);
    }
  };

  return (
    <GlassSurface className="polygon-live-panel" padding="lg">
      <header className="polygon-live-heading">
        <div>
          <span className="section-eyebrow">ПОЛИГОН / LIVE</span>
          <h2>Stock Ackermann Rover</h2>
          <p>
            Провайдеры симуляции исполняются на отдельном worker; браузер показывает
            канонический срез ENU/FLU.
          </p>
        </div>
        <div>
          <StatusBadge
            tone={worker?.available ? (runActive ? "accent" : "success") : "neutral"}
          >
            {worker?.available ? (runActive ? "Симуляция идёт" : "Worker готов") : "Worker offline"}
          </StatusBadge>
          <Button
            size="compact"
            variant={runActive ? "secondary" : "primary"}
            disabled={!worker?.controlAvailable || actionBusy}
            onClick={() => void runAction()}
          >
            {actionBusy ? "Ожидаем провайдеры…" : runActive ? "Остановить" : "Запустить"}
          </Button>
        </div>
      </header>

      <div className="polygon-live-layout">
        <Suspense
          fallback={
            <div className="polygon-rover-scene polygon-rover-scene--loading">
              Загружаем 3D-сцену…
            </div>
          }
        >
          <PolygonRoverScene
            live={live}
            trajectory={trajectory}
            workerAvailable={Boolean(worker?.available)}
          />
        </Suspense>

        <div className="polygon-live-telemetry">
          <div className="polygon-rover-controls">
            <div className="polygon-rover-controls__heading">
              <span>
                Управление {controllerProvider?.providerId ?? "машиной"}
              </span>
              <StatusBadge tone={commandAcceptance?.controllerReady ? "success" : "neutral"}>
                {commandAcceptance?.controllerReady ? "Controller ready" : "Ожидает прогона"}
              </StatusBadge>
            </div>
            <div className="polygon-rover-controls__grid">
              {CONTROL_INTENTS.map((intent) => (
                <Button
                  key={intent.id}
                  size="compact"
                  variant={controlIntent?.id === intent.id ? "primary" : "secondary"}
                  disabled={!runActive || worker?.runState !== "running" || actionBusy}
                  onClick={() => setControlIntent(intent)}
                >
                  {intent.label}
                </Button>
              ))}
              <Button
                size="compact"
                variant="secondary"
                disabled={!runActive || worker?.runState !== "running" || actionBusy}
                onClick={() => void stopMotion()}
              >
                Стоп
              </Button>
            </div>
            <small>
              {controlIntent
                ? `${controlIntent.label}: ${controlIntent.speedMps.toFixed(2)} m/s · steering ${controlIntent.steeringNormalized.toFixed(2)}`
                : "Команда 250 мс; потеря браузера автоматически обнуляет скорость."}
            </small>
          </div>
          <div>
            <span>Прогон</span>
            <strong>{worker?.activeRunId ?? "—"}</strong>
          </div>
          <div>
            <span>Sim time</span>
            <strong>{live ? `${(live.simTimeNs / 1e9).toFixed(2)} s` : "—"}</strong>
          </div>
          <div>
            <span>Позиция ENU</span>
            <strong>
              {live
                ? `${live.position.x.toFixed(2)} · ${live.position.y.toFixed(2)} · ${live.position.z.toFixed(2)} m`
                : "—"}
            </strong>
          </div>
          <div>
            <span>Провайдерный стек</span>
            <strong>{providerStack || "—"}</strong>
          </div>
          <div>
            <span>Активные процессы</span>
            <strong>{worker?.activeProviderIds.join(" · ") || "—"}</strong>
          </div>
          <div>
            <span>Источник live-состояния</span>
            <strong>{live ? `${live.sourceProvider} · ${live.sourceSignal}` : "—"}</strong>
          </div>
          <div>
            <span>Последняя команда</span>
            <strong>
              {commandAcceptance
                ? `#${commandAcceptance.sequence} · ${commandAcceptance.speedMps.toFixed(2)} m/s · ${commandAcceptance.steeringNormalized.toFixed(2)}`
                : "—"}
            </strong>
          </div>
          <div className="polygon-live-boundary">
            <StatusBadge tone="success">Virtual only</StatusBadge>
            <p>
              Команды проходят только через заявленный controller provider
              {controllerProvider ? ` ${controllerProvider.providerId}` : ""}. Физического
              actuator authority нет; live-поза остаётся диагностической.
            </p>
          </div>
          {error && <p className="polygon-live-error">{error}</p>}
        </div>
      </div>
    </GlassSurface>
  );
}
