"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { api, SelfTest, SelfTestStepState } from "@/lib/api";
import { useLocale } from "@/i18n/LocaleProvider";
import { Button, StatusBadge, Tone } from "@/components/ui";

/**
 * The active commissioning checks: unlock the vehicle, then lock it again.
 *
 * <p>Polled rather than awaited, because the outcome genuinely does not exist when the request
 * returns - a lock command is fire-and-forget and the hardware reports back seconds later on a
 * different channel. Showing "dispatched" as if it were "done" is the single easiest way to make
 * this feature lie, so the run stays visibly RUNNING until the device answers.
 */
const POLL_MS = 2000;

const stepTone: Record<SelfTestStepState, Tone> = {
  PASS: "success",
  FAIL: "danger",
  PENDING: "neutral",
};

export function SelfTestControl({
  vehicleId,
  onFinished,
  compact = false,
}: {
  vehicleId: string;
  /** Fired once, when a run reaches a terminal state. */
  onFinished?: (run: SelfTest) => void;
  compact?: boolean;
}) {
  const { t } = useLocale();
  const [run, setRun] = useState<SelfTest | null>(null);
  const [starting, setStarting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  // Guards against firing onFinished repeatedly while the finished run stays on screen.
  const notified = useRef<string | null>(null);

  const running = run?.state === "RUNNING";

  const poll = useCallback(async (runId: string) => {
    try {
      setRun(await api.selfTest(runId));
    } catch {
      // A transient poll failure is not worth tearing the panel down; the next tick retries.
    }
  }, []);

  useEffect(() => {
    if (!run || run.state !== "RUNNING") return;
    const id = setInterval(() => poll(run.runId), POLL_MS);
    return () => clearInterval(id);
  }, [run, poll]);

  useEffect(() => {
    if (run && run.state !== "RUNNING" && notified.current !== run.runId) {
      notified.current = run.runId;
      onFinished?.(run);
    }
  }, [run, onFinished]);

  async function start() {
    setStarting(true);
    setError(null);
    try {
      setRun(await api.startSelfTest(vehicleId));
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setStarting(false);
    }
  }

  return (
    <div className={compact ? "flex items-center gap-2" : "space-y-3"}>
      <div className="flex flex-wrap items-center gap-2">
        {run?.steps.map((s) => (
          <span key={s.name} title={s.detail ?? undefined}>
            <StatusBadge tone={stepTone[s.state]}>
              {t(s.name === "unlock" ? "com.stepUnlock" : "com.stepLock")}
              {s.detail && <span className="ms-1 opacity-70">{s.detail}</span>}
            </StatusBadge>
          </span>
        ))}
      </div>

      <div className="flex items-center gap-2">
        <Button onClick={start} disabled={starting || running}>
          {running ? t("com.selfTestRunning") : t("com.selfTest")}
        </Button>
        {!compact && (
          <Button
            variant="ghost"
            onClick={() => api.ringVehicle(vehicleId).catch(() => undefined)}
          >
            {t("com.ring")}
          </Button>
        )}
      </div>

      {error && <p className="text-sm text-danger">{error}</p>}
      {!compact && run && run.state !== "RUNNING" && (
        <p
          className={`text-sm font-medium ${
            run.state === "PASSED" ? "text-success" : "text-danger"
          }`}
        >
          {t(run.state === "PASSED" ? "com.testPassed" : "com.testFailed")}
        </p>
      )}
    </div>
  );
}
