"use client";

import { useState } from "react";
import { api, DeviceProfile, IotDeviceRow, UnclaimedDevice } from "@/lib/api";
import { useApi } from "@/hooks/useApi";
import { useLocale } from "@/i18n/LocaleProvider";
import {
  Button,
  Card,
  EmptyState,
  ErrorState,
  Field,
  Modal,
  Numeric,
  SectionTitle,
  Select,
  SkeletonTable,
  StatusBadge,
} from "@/components/ui";

/**
 * IoT stock: the modules you own, whether or not one is fitted to a vehicle yet.
 *
 * <p>Two facts are shown side by side because they answer different questions. <b>Fitted</b> says
 * whether a vehicle claims this device; <b>talking</b> says whether it is reaching us right now. A
 * device can be fitted and silent (a dead SIM) or spare and chattering (a unit powered on in the
 * warehouse), and telling those apart is most of diagnosing a fleet.
 */
export function IotDevicesPanel({ profiles }: { profiles: DeviceProfile[] }) {
  const { t } = useLocale();
  const stock = useApi<IotDeviceRow[]>(() => api.iotDevices(), []);
  const detected = useApi<UnclaimedDevice[]>(() => api.detectedDevices(), []);
  const [adding, setAdding] = useState(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const [imei, setImei] = useState("");
  const [iotProfile, setIotProfile] = useState("");
  const [hardwareType, setHardwareType] = useState("");
  const [simPhone, setSimPhone] = useState("");

  function refresh() {
    stock.reload();
    detected.reload();
  }

  async function register(values: {
    imei: string;
    iotProfile?: string;
    hardwareType?: string;
    simPhone?: string;
  }) {
    setBusy(true);
    setError(null);
    try {
      await api.registerDevice(values);
      setAdding(false);
      setImei("");
      setIotProfile("");
      setHardwareType("");
      setSimPhone("");
      refresh();
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setBusy(false);
    }
  }

  async function remove(row: IotDeviceRow) {
    setBusy(true);
    try {
      await api.deleteDevice(row.device.id);
      refresh();
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="space-y-6">
      <div className="flex flex-wrap items-start justify-between gap-4">
        <p className="max-w-2xl text-sm text-muted">{t("dev.body")}</p>
        <Button variant="primary" onClick={() => setAdding(true)}>
          {t("dev.add")}
        </Button>
      </div>

      {/* The fast path for a box of modules: power them on and they list themselves, rather than
          someone typing fifteen digits fifty times. */}
      {detected.data && detected.data.length > 0 && (
        <div>
          <SectionTitle>{t("dev.detected")}</SectionTitle>
          <p className="mb-3 max-w-2xl text-sm text-muted">{t("dev.detectedBody")}</p>
          <Card className="!p-0">
            <ul className="divide-y divide-line">
              {detected.data.map((d) => (
                <li key={d.imei} className="flex flex-wrap items-center gap-4 p-4">
                  <div className="min-w-[12rem] flex-1">
                    <p className="text-sm font-semibold">
                      <Numeric>{d.imei}</Numeric>
                    </p>
                    <p className="text-xs text-muted">
                      {[d.deviceType, d.hardwareType].filter(Boolean).join(" · ") || "-"}
                    </p>
                  </div>
                  {d.profileId && <StatusBadge tone="info">{d.profileId}</StatusBadge>}
                  <Button
                    onClick={() =>
                      register({
                        imei: d.imei,
                        iotProfile: d.profileId ?? undefined,
                        hardwareType: d.hardwareType ?? undefined,
                      })
                    }
                    disabled={busy}
                  >
                    {t("dev.addDetected")}
                  </Button>
                </li>
              ))}
            </ul>
          </Card>
        </div>
      )}

      {stock.loading && !stock.data && <SkeletonTable rows={5} />}
      {stock.error ? <ErrorState onRetry={refresh} /> : null}

      {stock.data &&
        (stock.data.length === 0 ? (
          <EmptyState icon={<span className="text-xl">📡</span>} title={t("dev.empty")} />
        ) : (
          <>
            {/* Named, because without a heading this list reads as more of the detected block
                above it, and the two mean opposite things. */}
            <SectionTitle>
              {t("dev.stock")}
              <span className="ms-2 text-sm font-normal text-muted">
                <Numeric>{stock.data.length}</Numeric>
                {" · "}
                <Numeric>{stock.data.filter((r) => !r.assignedToQrCode).length}</Numeric>{" "}
                {t("dev.spare")}
              </span>
            </SectionTitle>
            <Card className="!p-0">
              <ul className="divide-y divide-line">
                {stock.data.map((row) => (
                  <li key={row.device.id} className="flex flex-wrap items-center gap-4 p-4">
                    <div className="min-w-[12rem] flex-1">
                      <p className="text-sm font-semibold">
                        <Numeric>{row.device.imei}</Numeric>
                      </p>
                      <p className="text-xs text-muted">
                        {[row.device.hardwareType, row.device.simPhone]
                          .filter(Boolean)
                          .join(" · ") || "-"}
                      </p>
                    </div>

                    {row.device.iotProfile && (
                      <StatusBadge tone="info">{row.device.iotProfile}</StatusBadge>
                    )}

                    <StatusBadge tone={row.assignedToQrCode ? "success" : "neutral"}>
                      {row.assignedToQrCode
                        ? `${t("dev.fitted")}: ${row.assignedToQrCode}`
                        : t("dev.spare")}
                    </StatusBadge>

                    <StatusBadge tone={row.online ? "success" : "neutral"}>
                      {row.online ? t("dev.online") : t("dev.offline")}
                    </StatusBadge>

                    {/* Refused server-side while fitted, so this only ever removes real spares. */}
                    {!row.assignedToQrCode && (
                      <Button variant="ghost" onClick={() => remove(row)} disabled={busy}>
                        {t("dev.remove")}
                      </Button>
                    )}
                  </li>
                ))}
              </ul>
            </Card>
          </>
        ))}

      {error && <p className="text-sm text-danger">{error}</p>}

      <Modal
        open={adding}
        onClose={() => setAdding(false)}
        title={t("dev.add")}
        actions={
          <>
            <Button onClick={() => setAdding(false)}>{t("common.cancel")}</Button>
            <Button
              variant="primary"
              disabled={busy || imei.trim().length < 15}
              onClick={() =>
                register({
                  imei: imei.trim(),
                  iotProfile: iotProfile || undefined,
                  hardwareType: hardwareType.trim() || undefined,
                  simPhone: simPhone.trim() || undefined,
                })
              }
            >
              {t("common.save")}
            </Button>
          </>
        }
      >
        <div className="space-y-4">
          <Field
            label={t("dev.imei")}
            value={imei}
            onChange={(e) => setImei(e.target.value)}
            placeholder="860537062671375"
            dir="ltr"
            inputMode="numeric"
          />
          <Select
            label={t("dev.profile")}
            value={iotProfile}
            onChange={(e) => setIotProfile(e.target.value)}
            placeholder="-"
            options={profiles.map((p) => ({
              value: p.id,
              label: `${p.vendor}${p.model ? " " + p.model : ""} (${p.transport})`,
            }))}
          />
          <div className="grid gap-4 sm:grid-cols-2">
            <Field
              label={t("dev.hardware")}
              value={hardwareType}
              onChange={(e) => setHardwareType(e.target.value)}
              placeholder="M113"
              dir="ltr"
            />
            <Field
              label={t("dev.sim")}
              value={simPhone}
              onChange={(e) => setSimPhone(e.target.value)}
              placeholder="+9665…"
              dir="ltr"
            />
          </div>
          {error && <p className="text-sm text-danger">{error}</p>}
        </div>
      </Modal>
    </div>
  );
}
