"use client";

import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { ArrowDown, ArrowUp, Flag, PackageCheck, Route as RouteIcon } from "lucide-react";
import { Alert } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { EmptyState } from "@/components/shared/states";
import { useCan } from "@/features/auth/use-can";
import { useI18n, useT } from "@/i18n";
import { friendlyErrorMessage } from "@/lib/errors";
import { formatDateTime, formatDistanceKm, formatNumber } from "@/lib/format";
import { queryKeys } from "@/lib/query-keys";
import { formatDuration, getRoutePlan, moveStop, reorderRoutePlan } from "@/services/dispatch";
import type { RouteStop } from "@/types/dispatch";

/**
 * The route a captain is driving, and the dispatcher's ability to change its order.
 *
 * **The version is the whole safety mechanism.** Routes are recomputed constantly — every
 * assignment, every completed stop, every deviation — so a reorder carries the version it was
 * looking at and the server refuses it with a 409 if that is no longer current. When that happens
 * this panel reloads rather than retrying: the right answer is to show the dispatcher the route
 * that exists now, not to re-apply their order to a route they never saw.
 *
 * Reordering is gated on `orders.assign`, not on the dispatch settings permission, because
 * changing what a captain is told to do next is the same authority as handing them an order.
 */
export function RoutePlanPanel({
  captainUlid,
  captainName,
}: {
  captainUlid: string;
  captainName: string;
}) {
  const t = useT();
  const { locale } = useI18n();
  const { can } = useCan();
  const queryClient = useQueryClient();
  const canReorder = can("orders.assign");

  const query = useQuery({
    queryKey: queryKeys.dispatch.routePlan(captainUlid),
    queryFn: async () => (await getRoutePlan(captainUlid)).Model ?? null,
  });

  const plan = query.data ?? null;

  // The dispatcher's draft, kept apart from the server's copy so a refetch cannot reshuffle a list
  // somebody is in the middle of arranging.
  //
  // It carries the version it was built from, and is *derived* away rather than cleared: when the
  // route is recomputed underneath — a stop completed, a new order assigned — the draft describes
  // stops that may no longer exist, and saving it would apply an order to a route nobody saw.
  const [draft, setDraft] = useState<{ version: number; stops: RouteStop[] } | null>(null);
  const liveDraft = draft !== null && plan !== null && draft.version === plan.version ? draft : null;

  const stops = liveDraft?.stops ?? plan?.stops ?? [];
  const dirty = liveDraft !== null;
  const stage = (next: RouteStop[]) =>
    plan === null ? undefined : setDraft({ version: plan.version, stops: next });

  const reorder = useMutation({
    mutationFn: () => reorderRoutePlan(captainUlid, plan?.version ?? 0, stops.map((s) => s.key)),
    onSuccess: (response) => {
      toast.success(response.Message ?? t("routePlan.saved"));
      setDraft(null);
      void queryClient.invalidateQueries({ queryKey: queryKeys.dispatch.routePlan(captainUlid) });
      // The captain's ETAs moved, and the map reads them from the fleet snapshot.
      void queryClient.invalidateQueries({ queryKey: queryKeys.tracking.live });
    },
    onError: (error) => {
      // Covers both refusals the server makes: a stale version (409) and an impossible sequence
      // such as a drop-off before its own pickup (422). Both messages arrive translated.
      toast.error(friendlyErrorMessage(error, t));
      setDraft(null);
      void queryClient.invalidateQueries({ queryKey: queryKeys.dispatch.routePlan(captainUlid) });
    },
  });

  return (
    <Card>
      <CardHeader className="flex flex-row flex-wrap items-center justify-between gap-2">
        <CardTitle className="flex items-center gap-2">
          <RouteIcon className="h-4 w-4 text-primary" aria-hidden />
          {t("routePlan.title", { name: captainName })}
        </CardTitle>
        {plan ? (
          <span className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
            <Badge variant="secondary">{t("routePlan.version", { version: String(plan.version) })}</Badge>
            <span>{plan.trigger_label}</span>
            {plan.computed_at ? <span>{formatDateTime(plan.computed_at, locale)}</span> : null}
          </span>
        ) : null}
      </CardHeader>

      <CardContent className="space-y-4">
        {query.isPending ? (
          <div className="space-y-2">
            <Skeleton className="h-6 w-48" />
            <Skeleton className="h-16 w-full" />
            <Skeleton className="h-16 w-full" />
          </div>
        ) : query.isError ? (
          <Alert variant="destructive" title={t("routePlan.loadFailed")}>
            {friendlyErrorMessage(query.error, t)}
          </Alert>
        ) : plan === null ? (
          <EmptyState
            title={t("routePlan.none")}
            description={t("routePlan.noneHint")}
            icon={Flag}
          />
        ) : (
          <>
            {plan.degraded ? (
              <Alert variant="warning" title={t("routePlan.degraded")}>
                {t("routePlan.degradedHint")}
              </Alert>
            ) : null}

            <div className="flex flex-wrap gap-x-6 gap-y-1 text-sm text-muted-foreground">
              <span>
                {t("routePlan.totalTime")}:{" "}
                <span className="font-medium text-foreground">
                  {formatDuration(plan.total_seconds) ?? "—"}
                </span>
              </span>
              <span>
                {t("routePlan.totalDistance")}:{" "}
                <span className="font-medium text-foreground">
                  {plan.total_meters === null
                    ? "—"
                    : formatDistanceKm(plan.total_meters / 1000, locale)}
                </span>
              </span>
              <span>
                {t("routePlan.engine")}:{" "}
                <span className="font-medium text-foreground" dir="ltr">
                  {plan.routing_engine}
                </span>
              </span>
              <span>
                {t("routePlan.stops")}:{" "}
                <span className="font-medium text-foreground numeric">
                  {formatNumber(stops.length, locale)}
                </span>
              </span>
            </div>

            <ol className="space-y-2">
              {stops.map((stop, index) => (
                <li
                  key={stop.key}
                  className="flex items-start gap-3 rounded-lg border p-3 text-sm"
                >
                  <span className="numeric flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary-soft text-xs font-semibold text-primary">
                    {index + 1}
                  </span>

                  <div className="min-w-0 flex-1">
                    <p className="flex items-center gap-2 font-medium text-foreground">
                      {stop.type === "pickup" ? (
                        <PackageCheck className="h-3.5 w-3.5 text-primary" aria-hidden />
                      ) : (
                        <Flag className="h-3.5 w-3.5 text-accent" aria-hidden />
                      )}
                      {stop.type === "pickup" ? t("routePlan.pickup") : t("routePlan.dropoff")}
                      {/* An internal id, not a UUID: the API does not expose one here, so this is
                          a reference for support to quote rather than a link. */}
                      <span className="text-xs font-normal text-muted-foreground" dir="ltr">
                        #{stop.order_id}
                        {stop.pickup_id !== null ? `/${stop.pickup_id}` : ""}
                      </span>
                    </p>
                    <p className="mt-0.5 text-xs text-muted-foreground">
                      {stop.eta_at
                        ? `${t("routePlan.eta")} ${formatDateTime(stop.eta_at, locale)}`
                        : t("routePlan.noEta")}
                      {stop.leg_seconds !== null ? (
                        <span className="ms-2">
                          +{formatDuration(stop.leg_seconds)}
                          {stop.leg_meters !== null
                            ? ` · ${formatDistanceKm(stop.leg_meters / 1000, locale)}`
                            : ""}
                        </span>
                      ) : null}
                    </p>
                    {stop.lat !== null && stop.lng !== null ? (
                      <p className="numeric mt-0.5 text-[0.7rem] text-muted-foreground" dir="ltr">
                        {stop.lat.toFixed(5)}, {stop.lng.toFixed(5)}
                      </p>
                    ) : null}
                  </div>

                  {canReorder ? (
                    <span className="flex shrink-0 flex-col gap-1">
                      <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        aria-label={t("routePlan.moveUp")}
                        disabled={index === 0 || reorder.isPending}
                        onClick={() => stage(moveStop(stops, index, -1))}
                      >
                        <ArrowUp className="h-3.5 w-3.5" aria-hidden />
                      </Button>
                      <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        aria-label={t("routePlan.moveDown")}
                        disabled={index === stops.length - 1 || reorder.isPending}
                        onClick={() => stage(moveStop(stops, index, 1))}
                      >
                        <ArrowDown className="h-3.5 w-3.5" aria-hidden />
                      </Button>
                    </span>
                  ) : null}
                </li>
              ))}
            </ol>

            {canReorder ? (
              <div className="flex flex-wrap items-center gap-2">
                <Button
                  type="button"
                  disabled={!dirty || reorder.isPending}
                  onClick={() => reorder.mutate()}
                >
                  {reorder.isPending ? t("common.saving") : t("routePlan.save")}
                </Button>
                <Button
                  type="button"
                  variant="outline"
                  disabled={!dirty || reorder.isPending}
                  onClick={() => setDraft(null)}
                >
                  {t("common.clear")}
                </Button>
                <p className="text-xs text-muted-foreground">{t("routePlan.saveHint")}</p>
              </div>
            ) : null}
          </>
        )}
      </CardContent>
    </Card>
  );
}
