"use client";

import { useState } from "react";
import {
  api,
  CheckState,
  CommissioningBoard,
  CommissioningCheck,
  CommissioningVehicle,
  UnclaimedDevice,
} from "@/lib/api";
import { useLocale } from "@/i18n/LocaleProvider";
import { Icon } from "@/components/icons";
import {
  Button,
  Card,
  Dialog,
  EmptyState,
  Field,
  Numeric,
  SectionTitle,
  StatTile,
  StatusBadge,
  Tone,
} from "@/components/ui";
import { SelfTestControl } from "./SelfTestControl";

/**
 * The commissioning queue - vehicles that have been registered but not yet proven.
 *
 * <p>Lives as a tab inside Fleet rather than its own screen: "where are my vehicles" should have
 * exactly one answer. The two tabs are the same fleet at two stages, so keeping them a click apart
 * makes the pipeline visible instead of somewhere else to remember to look.
 *
 * <p>Presentational: the board is fetched and polled by the page, so the tab badge and this
 * content can never disagree about how many vehicles are waiting.
 */
const checkTone: Record<CheckState, Tone> = {
  PASS: "success",
  FAIL: "danger",
  WAITING: "neutral",
};

const checkLabel: Record<CommissioningCheck["name"], string> = {
  heartbeat: "com.checkHeartbeat",
  gps: "com.checkGps",
  battery: "com.checkBattery",
  signal: "com.checkSignal",
  protocol: "com.checkProtocol",
};

export function CommissioningPanel({
  board,
  reload,
  busy,
  setBusy,
  onImport,
}: {
  board: CommissioningBoard;
  reload: () => void;
  busy: string | null;
  setBusy: (v: string | null) => void;
  onImport: () => void;
}) {
  const { t } = useLocale();
  const [forcing, setForcing] = useState<CommissioningVehicle | null>(null);
  const [forceReason, setForceReason] = useState("");

  async function commission(id: string) {
    setBusy(id);
    try {
      await api.commissionVehicle(id);
      reload();
    } finally {
      setBusy(null);
    }
  }

  async function forceCommission() {
    if (!forcing) return;
    setBusy(forcing.id);
    try {
      await api.commissionVehicle(forcing.id, {
        force: true,
        reason: forceReason.trim(),
      });
      setForcing(null);
      setForceReason("");
      reload();
    } finally {
      setBusy(null);
    }
  }

  return (
    <div className="space-y-6">
      <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
        <StatTile label={t("common.total")} value={board.total} />
        <StatTile label={t("com.ready")} value={board.ready} tone="success" />
        <StatTile label={t("com.waiting")} value={board.waiting} tone="warning" />
        <StatTile label={t("com.failed")} value={board.failed} tone="danger" />
      </div>

      {board.total === 0 ? (
        <EmptyState
          icon={<Icon name="commissioning" />}
          title={t("com.emptyTitle")}
          description={t("com.emptyBody")}
          action={
            <Button variant="primary" onClick={onImport}>
              {t("com.import")}
            </Button>
          }
        />
      ) : (
        <div>
          <div className="mb-3 flex items-center justify-between">
            <SectionTitle>{t("com.title")}</SectionTitle>
            <span className="flex items-center gap-2 text-xs text-muted">
              <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-success" />
              {t("com.live")}
            </span>
          </div>
          <Card className="!p-0">
            <ul className="divide-y divide-line">
              {board.vehicles.map((v) => (
                <VehicleRow
                  key={v.id}
                  vehicle={v}
                  busy={busy !== null}
                  onCommission={() => commission(v.id)}
                  onForce={() => {
                    setForceReason("");
                    setForcing(v);
                  }}
                />
              ))}
            </ul>
          </Card>
        </div>
      )}

      {board.unclaimed.length > 0 && <UnclaimedSection devices={board.unclaimed} />}

      <Dialog
        open={forcing !== null}
        onClose={() => setForcing(null)}
        tone="danger"
        icon={<span className="text-xl">!</span>}
        title={t("com.forceTitle")}
        description={t("com.forceBody")}
        actions={
          <>
            <Button className="flex-1" onClick={() => setForcing(null)}>
              {t("common.cancel")}
            </Button>
            <Button
              variant="danger"
              className="flex-1"
              onClick={forceCommission}
              disabled={forceReason.trim().length === 0 || busy !== null}
            >
              {t("com.forceConfirm")}
            </Button>
          </>
        }
      >
        <Field
          label={t("com.forceReason")}
          value={forceReason}
          onChange={(e) => setForceReason(e.target.value)}
          placeholder={t("com.forceReasonHint")}
        />
      </Dialog>
    </div>
  );
}

function VehicleRow({
  vehicle,
  busy,
  onCommission,
  onForce,
}: {
  vehicle: CommissioningVehicle;
  busy: boolean;
  onCommission: () => void;
  /** Opens the override prompt. Only offered once a check has actually failed. */
  onForce: () => void;
}) {
  const { t } = useLocale();
  return (
    <li className="flex flex-wrap items-center gap-4 p-4">
      {/* A floor is needed as well as min-w-0: a failing row carries an extra button, and without
          it the identity is the flex item that collapses - to "B…" - which is the one thing in the
          row an operator must be able to read. */}
      <div className="min-w-[11rem] flex-1">
        <p className="truncate text-sm font-semibold">{vehicle.qrCode}</p>
        <p className="truncate text-xs text-muted">
          {vehicle.model ?? "-"}
          {vehicle.imei ? (
            <>
              {" · "}
              <Numeric>{vehicle.imei}</Numeric>
            </>
          ) : (
            <> · {t("com.notPaired")}</>
          )}
        </p>
      </div>

      <div className="flex flex-wrap items-center gap-2">
        {vehicle.checks.map((c) => (
          <span key={c.name}>
            <StatusBadge tone={checkTone[c.state]}>
              {t(checkLabel[c.name] as never)}
              <CheckDetail check={c} />
            </StatusBadge>
          </span>
        ))}
      </div>

      {/* The lock test only makes sense once the device is actually talking to us. */}
      {vehicle.imei && vehicle.checks[0]?.state === "PASS" && (
        <SelfTestControl vehicleId={vehicle.id} compact />
      )}

      {/* Offered only on a genuine failure - a vehicle still WAITING just needs more time, and
          offering an override there would train operators to skip the wait. */}
      {!vehicle.ready && vehicle.checks.some((c) => c.state === "FAIL") && (
        <Button variant="ghost" onClick={onForce} disabled={busy}>
          {t("com.forceAction")}
        </Button>
      )}

      <Button onClick={onCommission} disabled={!vehicle.ready || busy}>
        {t("com.commission")}
      </Button>
    </li>
  );
}

function UnclaimedSection({ devices }: { devices: UnclaimedDevice[] }) {
  const { t } = useLocale();
  return (
    <div>
      <SectionTitle>{t("com.unclaimedTitle")}</SectionTitle>
      <p className="mb-3 max-w-2xl text-sm text-muted">{t("com.unclaimedBody")}</p>
      <Card className="!p-0">
        <ul className="divide-y divide-line">
          {devices.map((d) => (
            <li key={d.imei} className="flex flex-wrap items-center gap-4 p-4">
              <div className="min-w-[11rem] flex-1">
                <p className="truncate text-sm font-semibold">
                  <Numeric>{d.imei}</Numeric>
                </p>
                <p className="truncate text-xs text-muted">
                  {[d.deviceType, d.hardwareType].filter(Boolean).join(" · ") || "-"}
                </p>
              </div>
              <div className="text-xs text-muted">
                {t("com.colFrames")}: <Numeric>{d.frameCount}</Numeric>
              </div>
              {d.batteryPercent != null && (
                <StatusBadge tone="info">
                  <Numeric>{d.batteryPercent}%</Numeric>
                </StatusBadge>
              )}
            </li>
          ))}
        </ul>
      </Card>
    </div>
  );
}

/**
 * A check's detail, assembled client-side from a translation key plus a language-neutral value.
 * Value first so both languages read naturally: "3 frames" / "3 رسائل".
 */
function CheckDetail({ check }: { check: CommissioningCheck }) {
  const { t } = useLocale();
  if (!check.code && !check.value) return null;
  return (
    <span className="ms-1 opacity-70">
      {check.value && <Numeric>{check.value}</Numeric>}
      {check.value && check.code ? " " : ""}
      {check.code ? t(`check.${check.code}` as never) : ""}
    </span>
  );
}
