"use client";

import { useMemo, useState } from "react";
import {
  api,
  LatLng,
  ParkingOccupancy,
  Zone,
  ZoneInput,
  ZoneParkingInput,
  ZoneType,
} from "@/lib/api";
import { useApi } from "@/hooks/useApi";
import { useVehicleTypes } from "@/lib/useVehicleTypes";
import { useLocale } from "@/i18n/LocaleProvider";
import { ZONE_COLORS, ZoneMap } from "@/components/ZoneMap";
import { ParkingFields, parkingIsValid } from "./ParkingFields";
import {
  Button,
  Card,
  ChoiceGrid,
  EmptyState,
  ErrorState,
  Field,
  Numeric,
  PageHeader,
  SkeletonCard,
  StatusBadge,
  Toggle,
  Tone,
} from "@/components/ui";

const TYPES: ZoneType[] = ["GREEN", "RED", "SLOW", "COMPOUND", "PARKING"];

const typeTone: Record<ZoneType, Tone> = {
  GREEN: "success",
  RED: "danger",
  SLOW: "warning",
  COMPOUND: "accent",
  PARKING: "info",
};

export default function Page() {
  const { t } = useLocale();
  const zones = useApi<Zone[]>(api.listZones, []);

  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [drawing, setDrawing] = useState(false);
  // A freshly-drawn polygon awaiting a name/type before it's saved.
  const [draft, setDraft] = useState<LatLng[] | null>(null);

  const list = zones.data ?? [];
  const selected = useMemo(
    () => list.find((z) => z.id === selectedId) ?? null,
    [list, selectedId],
  );

  const startDrawing = () => {
    setSelectedId(null);
    setDraft(null);
    setDrawing(true);
  };

  return (
    <div>
      <PageHeader
        titleKey="nav.zones"
        subtitle={
          zones.data ? (
            <>
              <Numeric>{zones.data.filter((z) => z.active).length}</Numeric> {t("zones.activeCount")}
              {zones.data.length > zones.data.filter((z) => z.active).length && (
                <>
                  {" · "}
                  <Numeric>
                    {zones.data.length - zones.data.filter((z) => z.active).length}
                  </Numeric>{" "}
                  {t("zones.inactive")}
                </>
              )}
            </>
          ) : undefined
        }
        actions={
          <Button variant="primary" onClick={startDrawing} disabled={drawing}>
            {drawing ? t("zones.drawingNow") : t("zones.draw")}
          </Button>
        }
      />

      <div className="grid gap-4 lg:grid-cols-[1fr_360px]">
        <div className="space-y-3">
          {/* Tall, like the fleet map: drawing a geofence on a letterbox is guesswork, and the
              page had a screen of dead space under it. */}
          <ZoneMap
            zones={list}
            selectedId={selectedId}
            drawing={drawing}
            onDrawn={(polygon) => {
              setDrawing(false);
              setDraft(polygon);
            }}
            onSelect={setSelectedId}
            className="h-[calc(100vh-19rem)] min-h-[420px] w-full overflow-hidden rounded-card border border-line"
          />
          <Legend />
          {drawing && (
            <div className="card tint tone-brand p-3 text-sm">{t("zones.drawHint")}</div>
          )}
        </div>

        <div className="space-y-4">
          {draft ? (
            <ZoneForm
              polygon={draft}
              onCancel={() => setDraft(null)}
              onSaved={() => {
                setDraft(null);
                zones.reload();
              }}
            />
          ) : selected ? (
            <ZoneDetail
              zone={selected}
              onChanged={() => zones.reload()}
              onDeleted={() => {
                setSelectedId(null);
                zones.reload();
              }}
              onClose={() => setSelectedId(null)}
            />
          ) : (
            <ZoneList state={zones} onSelect={setSelectedId} />
          )}
        </div>
      </div>
    </div>
  );
}

/* ----------------------------------------------------------------------- list */

function ZoneList({
  state,
  onSelect,
}: {
  state: { data: Zone[] | null; loading: boolean; error: unknown; reload: () => void };
  onSelect: (id: string) => void;
}) {
  const { t } = useLocale();

  if (state.loading) return <SkeletonCard rows={5} />;
  if (state.error) return <ErrorState onRetry={state.reload} />;
  if (!state.data?.length) {
    return (
      <EmptyState
        icon={<span className="text-xl">🗺️</span>}
        title={t("zones.emptyTitle")}
        description={t("zones.emptyBody")}
      />
    );
  }

  return (
    <Card className="!p-0">
      <div className="divide-y divide-line">
        {state.data.map((z) => (
          <button
            key={z.id}
            onClick={() => onSelect(z.id)}
            className="flex w-full items-center gap-3 px-4 py-3 text-start transition hover:bg-surface-raised"
          >
            <span
              className="h-3 w-3 shrink-0 rounded-sm"
              style={{ backgroundColor: ZONE_COLORS[z.type], opacity: z.active ? 1 : 0.4 }}
            />
            <div className="flex-1">
              <div className="text-sm font-medium">{z.name}</div>
              <div className="text-xs text-muted">
                {/* The friendly label, not the raw enum: the legend and the type picker both say
                    "Operating area", and a list saying GREEN next to them reads as a different
                    thing. */}
                {t(`zones.type${z.type}`)}
                {z.type === "SLOW" && z.speedLimit ? ` · ${z.speedLimit} km/h` : ""}
                {z.type === "PARKING" && z.parking ? (
                  <>
                    {" · "}
                    <Numeric>{z.parking.totalCapacity}</Numeric> {t("zones.slots")}
                    {" · "}
                    {z.parking.free ? (
                      t("zones.free")
                    ) : (
                      <>
                        <Numeric>{z.parking.parkingFee.toFixed(2)}</Numeric> {t("common.sar")}
                      </>
                    )}
                  </>
                ) : null}
              </div>
            </div>
            {!z.active && <StatusBadge tone="neutral">{t("zones.inactive")}</StatusBadge>}
          </button>
        ))}
      </div>
    </Card>
  );
}

function Legend() {
  const { t } = useLocale();
  return (
    <div className="flex flex-wrap gap-4 px-1">
      {TYPES.map((type) => (
        <div key={type} className="flex items-center gap-2 text-xs text-muted">
          <span
            className="h-3 w-3 rounded-sm"
            style={{ backgroundColor: ZONE_COLORS[type] }}
          />
          {t(`zones.type${type}`)}
        </div>
      ))}
    </div>
  );
}

/* --------------------------------------------------------------------- create */

function ZoneForm({
  polygon,
  onCancel,
  onSaved,
}: {
  polygon: LatLng[];
  onCancel: () => void;
  onSaved: () => void;
}) {
  const { t } = useLocale();
  const [name, setName] = useState("");
  const [type, setType] = useState<ZoneType>("GREEN");
  const [speedLimit, setSpeedLimit] = useState("15");
  const [parking, setParking] = useState<ZoneParkingInput>({
    open24x7: true,
    capacity: {},
    parkingFee: 0,
  });
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const submit = async (e: React.FormEvent) => {
    e.preventDefault();
    setBusy(true);
    setError(null);
    try {
      const body: ZoneInput = {
        name: name.trim(),
        type,
        polygon,
        // Speed limit only means anything for a SLOW zone.
        speedLimit: type === "SLOW" ? Number(speedLimit) || null : null,
        // Likewise the parking block: sending it on another type is refused server-side.
        parking: type === "PARKING" ? parking : null,
      };
      await api.createZone(body);
      onSaved();
    } catch (err) {
      setError(err instanceof Error ? err.message : t("common.error"));
    } finally {
      setBusy(false);
    }
  };

  return (
    <Card>
      <h2 className="mb-1 text-lg font-semibold">{t("zones.newTitle")}</h2>
      <p className="mb-4 text-xs text-muted">
{polygon.length} {t("zones.points")}
      </p>
      <form onSubmit={submit} className="space-y-4">
        <div>
          <label className="field-label">{t("zones.type")}</label>
          {/* A grid, not a pill: five options in a 360px column wrapped into ragged rows inside
              one rounded container and read as a broken control. The dot is the colour the zone
              will actually be drawn in, so the choice is not a guess. */}
          <div className="mt-1">
            <ChoiceGrid
              value={type}
              onChange={setType}
              options={TYPES.map((v) => ({
                value: v,
                label: t(`zones.type${v}`),
                dot: ZONE_COLORS[v],
              }))}
            />
          </div>
        </div>
        <Field
          label={t("zones.name")}
          required
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder={t("zones.namePlaceholder")}
        />
        {type === "SLOW" && (
          <Field
            label={t("zones.speedLimit")}
            type="number"
            value={speedLimit}
            onChange={(e) => setSpeedLimit(e.target.value)}
          />
        )}
        {type === "PARKING" && <ParkingFields value={parking} onChange={setParking} />}

        {error && (
          <div className="tint tone-danger rounded-card border p-3 text-sm">{error}</div>
        )}

        <div className="flex gap-3">
          <Button
            variant="primary"
            type="submit"
            disabled={busy || !name.trim() || (type === "PARKING" && !parkingIsValid(parking))}
            className="flex-1"
          >
            {busy ? t("common.loading") : t("zones.save")}
          </Button>
          <Button type="button" onClick={onCancel}>
            {t("common.cancel")}
          </Button>
        </div>
      </form>
    </Card>
  );
}

/* --------------------------------------------------------------------- detail */

function ZoneDetail({
  zone,
  onChanged,
  onDeleted,
  onClose,
}: {
  zone: Zone;
  onChanged: () => void;
  onDeleted: () => void;
  onClose: () => void;
}) {
  const { t, locale } = useLocale();
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [confirmDelete, setConfirmDelete] = useState(false);

  const guard = async (fn: () => Promise<unknown>) => {
    setBusy(true);
    setError(null);
    try {
      await fn();
    } catch (err) {
      setError(err instanceof Error ? err.message : t("common.error"));
    } finally {
      setBusy(false);
    }
  };

  return (
    <Card>
      <div className="mb-4 flex items-start justify-between gap-3">
        <div>
          <h2 className="text-lg font-semibold">{zone.name}</h2>
          <div className="mt-1">
            <StatusBadge tone={typeTone[zone.type]}>{t(`zones.type${zone.type}`)}</StatusBadge>
          </div>
        </div>
        <Button onClick={onClose}>{t("common.cancel")}</Button>
      </div>

      <div className="card divide-y divide-line">
        <div className="flex items-center justify-between px-4 py-3">
          <span className="text-sm text-muted">{t("zones.active")}</span>
          <Toggle
            checked={zone.active}
            onChange={(v) => guard(() => api.setZoneActive(zone.id, v).then(onChanged))}
            label={t("zones.active")}
          />
        </div>
        {zone.type === "SLOW" && (
          <div className="flex items-center justify-between px-4 py-3">
            <span className="text-sm text-muted">{t("zones.speedLimit")}</span>
            <span className="text-sm font-medium">{zone.speedLimit ?? "-"} km/h</span>
          </div>
        )}
        {zone.type === "PARKING" && zone.parking && (
          <>
            <div className="flex items-center justify-between gap-3 px-4 py-3">
              <span className="text-sm text-muted">{t("zones.riderName")}</span>
              <span className="text-sm font-medium text-end">
                {(locale === "ar"
                  ? zone.parking.riderNameAr || zone.parking.riderNameEn
                  : zone.parking.riderNameEn || zone.parking.riderNameAr) || "-"}
              </span>
            </div>
            <div className="flex items-center justify-between px-4 py-3">
              <span className="text-sm text-muted">{t("zones.price")}</span>
              <span className="text-sm font-medium">
                {zone.parking.free ? (
                  <StatusBadge tone="success">{t("zones.free")}</StatusBadge>
                ) : (
                  <>
                    <Numeric>{zone.parking.parkingFee.toFixed(2)}</Numeric> {t("common.sar")}
                  </>
                )}
              </span>
            </div>
            <div className="flex items-center justify-between px-4 py-3">
              <span className="text-sm text-muted">{t("zones.hours")}</span>
              <span className="text-sm font-medium">
                {zone.parking.open24x7 ? (
                  t("zones.always")
                ) : (
                  <Numeric>
                    {zone.parking.opensAt ?? "-"} - {zone.parking.closesAt ?? "-"}
                  </Numeric>
                )}
              </span>
            </div>
            {zone.parking.note && (
              <div className="px-4 py-3">
                <div className="text-sm text-muted">{t("zones.note")}</div>
                <div className="mt-1 text-sm">{zone.parking.note}</div>
              </div>
            )}
          </>
        )}
        <div className="flex items-center justify-between px-4 py-3">
          <span className="text-sm text-muted">{t("zones.points")}</span>
          <span className="text-sm font-medium">{zone.polygon.length}</span>
        </div>
      </div>

      {zone.type === "PARKING" && (
        <ParkingOccupancyCard zone={zone} onChanged={onChanged} />
      )}

      {error && (
        <div className="tint tone-danger mt-4 rounded-card border p-3 text-sm">{error}</div>
      )}

      {confirmDelete ? (
        <div className="mt-4 space-y-3">
          <p className="text-sm text-muted">{t("zones.deleteConfirm")}</p>
          <div className="flex gap-3">
            <Button
              variant="danger"
              disabled={busy}
              className="flex-1"
              onClick={() => guard(() => api.deleteZone(zone.id).then(onDeleted))}
            >
              {t("zones.deleteYes")}
            </Button>
            <Button onClick={() => setConfirmDelete(false)}>{t("common.cancel")}</Button>
          </div>
        </div>
      ) : (
        <Button variant="danger" className="mt-4 w-full" onClick={() => setConfirmDelete(true)}>
          {t("zones.delete")}
        </Button>
      )}
    </Card>
  );
}

/* -------------------------------------------------------------------- parking */

/**
 * Capacity against live occupancy for one spot, plus editing of the parking fields.
 *
 * <p>Occupancy is the number that makes a parking spot worth modelling at all: a capacity nobody
 * checks is just a note. It is shown per vehicle type because a rack full of scooters still has
 * room for e-bikes, and an "8/10" that hides that fact sends a rebalancing van to the wrong place.
 */
function ParkingOccupancyCard({ zone, onChanged }: { zone: Zone; onChanged: () => void }) {
  const { t } = useLocale();
  const { label: typeLabel } = useVehicleTypes();
  const occupancy = useApi<ParkingOccupancy[]>(() => api.parkingOccupancy(), []);
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState<ZoneParkingInput>({});
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const mine = occupancy.data?.find((o) => o.zoneId === zone.id) ?? null;
  const capacity = zone.parking?.capacity ?? {};
  // Driven by what the spot actually declares, so a capacity for an operator-defined type shows
  // up without this screen knowing the type exists.
  const declared = Object.keys(capacity).filter((v) => (capacity[v] ?? 0) > 0);

  const startEdit = () => {
    setDraft({
      riderNameEn: zone.parking?.riderNameEn ?? "",
      riderNameAr: zone.parking?.riderNameAr ?? "",
      note: zone.parking?.note ?? "",
      open24x7: zone.parking?.open24x7 ?? true,
      opensAt: zone.parking?.opensAt ?? null,
      closesAt: zone.parking?.closesAt ?? null,
      capacity: { ...capacity },
      parkingFee: zone.parking?.parkingFee ?? 0,
    });
    setError(null);
    setEditing(true);
  };

  const save = async () => {
    setBusy(true);
    setError(null);
    try {
      // The gateway validates name/type/polygon on every update, so they travel unchanged.
      await api.updateZone(zone.id, {
        name: zone.name,
        type: zone.type,
        polygon: zone.polygon,
        speedLimit: zone.speedLimit,
        parking: draft,
      });
      setEditing(false);
      onChanged();
    } catch (e) {
      setError(e instanceof Error ? e.message : t("common.error"));
    } finally {
      setBusy(false);
    }
  };

  if (editing) {
    return (
      <Card className="mt-4">
        <ParkingFields value={draft} onChange={setDraft} />
        {error && (
          <div className="tint tone-danger mt-4 rounded-card border p-3 text-sm">{error}</div>
        )}
        <div className="mt-4 flex gap-3">
          <Button
            variant="primary"
            className="flex-1"
            disabled={busy || !parkingIsValid(draft)}
            onClick={save}
          >
            {busy ? t("common.loading") : t("common.save")}
          </Button>
          <Button onClick={() => setEditing(false)}>{t("common.cancel")}</Button>
        </div>
      </Card>
    );
  }

  return (
    <Card className="mt-4">
      <div className="mb-3 flex items-center justify-between gap-3">
        <h3 className="text-sm font-semibold">{t("zones.occupancy")}</h3>
        {mine && (
          <StatusBadge tone={mine.openNow ? "success" : "neutral"}>
            {mine.openNow ? t("zones.openNow") : t("zones.closedNow")}
          </StatusBadge>
        )}
      </div>

      {occupancy.loading && !occupancy.data && <SkeletonCard rows={2} />}
      {occupancy.error ? <ErrorState onRetry={occupancy.reload} /> : null}

      {occupancy.data &&
        (declared.length === 0 ? (
          <p className="text-sm text-muted">{t("zones.noCapacity")}</p>
        ) : (
          <div className="space-y-3">
            {declared.map((type) => {
              const cap = capacity[type] ?? 0;
              const used = mine?.byType?.[type] ?? 0;
              const pct = cap > 0 ? Math.min(100, Math.round((used / cap) * 100)) : 0;
              // Over capacity is a real state, not a rendering bug: nothing physically stops a
              // rider leaving an eleventh scooter at a ten-slot rack, and ops needs to see it.
              const over = used > cap;
              return (
                <div key={type}>
                  <div className="mb-1 flex items-center justify-between text-sm">
                    <span>{typeLabel(type)}</span>
                    <span className={over ? "font-semibold text-danger" : "text-muted"}>
                      <Numeric>
                        {used} / {cap}
                      </Numeric>
                    </span>
                  </div>
                  <div className="h-2 w-full overflow-hidden rounded-full bg-surface-raised">
                    <div
                      className={`h-full rounded-full ${over ? "bg-danger" : "bg-brand"}`}
                      style={{ width: `${over ? 100 : pct}%` }}
                    />
                  </div>
                </div>
              );
            })}
            {mine && (
              <p className="text-xs text-muted">
                {t("zones.totalParked")}:{" "}
                <Numeric>
                  {mine.total} / {zone.parking?.totalCapacity ?? 0}
                </Numeric>
              </p>
            )}
          </div>
        ))}

      <Button className="mt-4 w-full" onClick={startEdit}>
        {t("zones.editParking")}
      </Button>
    </Card>
  );
}
