import { useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useLocation, useSearch } from "wouter";
import { useQueryClient } from "@tanstack/react-query";
import {
  useListIncomingServiceOrders,
  getListIncomingServiceOrdersQueryKey,
  useConfirmServiceOrderReceipt,
  useUpdateServiceOrderStatus,
  useBulkDeleteServiceOrders,
  useDeleteServiceOrder,
  type ServiceOrder,
} from "@workspace/api-client-react";
import {
  ArrowLeft,
  ArrowRight,
  Inbox,
  ImageIcon,
  Clock,
  CheckCheck,
  Flame,
  PackageCheck,
  XCircle,
  Loader2,
  Trash2,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { ToastAction } from "@/components/ui/toast";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { useAuth } from "@/contexts/AuthContext";
import { useToast } from "@/hooks/use-toast";
import { resolveServiceImageUrl } from "@/lib/image-url";
import { cn } from "@/lib/utils";
import { AppDock } from "@/components/app-dock";

export const ORDER_RECEIVER_ROLE = "order_receiver";

const UNDO_WINDOW_MS = 7000;

export function userCanReceiveOrders(roles: string[] | undefined | null): boolean {
  if (!roles) return false;
  return roles.includes("admin") || roles.includes(ORDER_RECEIVER_ROLE);
}

function relativeAge(iso: string, t: (k: string, o?: Record<string, unknown>) => string): string {
  const ms = Date.now() - new Date(iso).getTime();
  const mins = Math.max(0, Math.floor(ms / 60000));
  if (mins < 1) return t("incomingOrders.ageJustNow");
  if (mins < 60) return t("incomingOrders.ageMinutes", { count: mins });
  const hours = Math.floor(mins / 60);
  if (hours < 24) return t("incomingOrders.ageHours", { count: hours });
  const days = Math.floor(hours / 24);
  return t("incomingOrders.ageDays", { count: days });
}

function OrderImage({ src, alt }: { src: string | null; alt: string }) {
  const [errored, setErrored] = useState(false);
  if (!src || errored) {
    return (
      <div className="w-14 h-14 rounded-lg bg-slate-100 flex items-center justify-center shrink-0">
        <ImageIcon size={18} className="text-slate-300" />
      </div>
    );
  }
  return (
    <img
      src={src}
      alt={alt}
      className="w-14 h-14 rounded-lg object-cover shrink-0"
      onError={() => setErrored(true)}
    />
  );
}

function StatusIcon({ status }: { status: ServiceOrder["status"] }) {
  const cls = "shrink-0";
  if (status === "pending") return <Clock size={14} className={cn(cls, "text-slate-500")} />;
  if (status === "received") return <CheckCheck size={14} className={cn(cls, "text-sky-600")} />;
  if (status === "preparing") return <Flame size={14} className={cn(cls, "text-amber-600")} />;
  if (status === "completed") return <PackageCheck size={14} className={cn(cls, "text-emerald-600")} />;
  return <XCircle size={14} className={cn(cls, "text-rose-600")} />;
}

type TriState = "all" | "some" | "none";
function triState(selectedCount: number, total: number): TriState {
  if (total === 0 || selectedCount === 0) return "none";
  if (selectedCount >= total) return "all";
  return "some";
}

function IncomingOrderCard({
  order,
  meId,
  onActionDone,
  selected,
  onToggleSelected,
  onRequestDelete,
  highlighted = false,
}: {
  order: ServiceOrder;
  meId: number;
  onActionDone: () => void;
  selected: boolean;
  onToggleSelected: (id: number) => void;
  onRequestDelete: (id: number) => void;
  highlighted?: boolean;
}) {
  const { t, i18n } = useTranslation();
  const lang = i18n.language;
  const { toast } = useToast();
  const queryClient = useQueryClient();

  const claim = useConfirmServiceOrderReceipt();
  const updateStatus = useUpdateServiceOrderStatus();

  const isMine = order.assignedTo === meId;
  const serviceName = lang === "ar" ? order.service.nameAr : order.service.nameEn;
  const requesterName = order.requester
    ? lang === "ar"
      ? (order.requester.displayNameAr ?? order.requester.username)
      : (order.requester.displayNameEn ?? order.requester.username)
    : "";
  const img = resolveServiceImageUrl(order.service.imageUrl);
  const busy = claim.isPending || updateStatus.isPending;

  const invalidate = () => {
    queryClient.invalidateQueries({
      queryKey: getListIncomingServiceOrdersQueryKey(),
    });
    onActionDone();
  };

  const handleConfirmReceipt = () => {
    claim.mutate(
      { id: order.id },
      {
        onSuccess: () => {
          toast({ title: t("incomingOrders.claimed") });
          invalidate();
        },
        onError: (err: unknown) => {
          const apiErr = err as { status?: number; data?: { error?: string } } | null;
          const status = apiErr?.status;
          const code = apiErr?.data?.error;
          if (
            (status === 409 && code === "order_unavailable") ||
            status === 404
          ) {
            toast({
              title: t("incomingOrders.orderUnavailable"),
              variant: "destructive",
            });
          } else if (status === 409) {
            toast({
              title: t("incomingOrders.alreadyClaimed"),
              variant: "destructive",
            });
          } else {
            toast({
              title: t("incomingOrders.actionFailed"),
              variant: "destructive",
            });
          }
          invalidate();
        },
      },
    );
  };

  const handleSetStatus = (status: "preparing" | "completed" | "cancelled") => {
    if (status === "cancelled") {
      handleCancel();
      return;
    }
    updateStatus.mutate(
      { id: order.id, data: { status } },
      {
        onSuccess: () => {
          toast({ title: t("incomingOrders.marked") });
          invalidate();
        },
        onError: (err: unknown) => {
          const apiErr = err as { status?: number; data?: { error?: string } } | null;
          if (
            (apiErr?.status === 409 && apiErr?.data?.error === "order_unavailable") ||
            apiErr?.status === 404
          ) {
            toast({
              title: t("incomingOrders.orderUnavailable"),
              variant: "destructive",
            });
            invalidate();
          } else {
            toast({
              title: t("incomingOrders.actionFailed"),
              variant: "destructive",
            });
          }
        },
      },
    );
  };

  const handleCancel = () => {
    const previousStatus = order.status;
    if (previousStatus !== "received" && previousStatus !== "preparing") {
      return;
    }
    updateStatus.mutate(
      { id: order.id, data: { status: "cancelled" } },
      {
        onSuccess: () => {
          invalidate();

          const undo = () => {
            updateStatus.mutate(
              { id: order.id, data: { status: previousStatus } },
              {
                onSuccess: () => {
                  invalidate();
                  handle.dismiss();
                  toast({ title: t("incomingOrders.undone") });
                },
                onError: () => {
                  toast({
                    title: t("incomingOrders.restoreFailed"),
                    variant: "destructive",
                  });
                },
              },
            );
          };

          const handle = toast({
            title: t("incomingOrders.cancelled"),
            duration: UNDO_WINDOW_MS,
            action: (
              <ToastAction
                altText={t("incomingOrders.undo")}
                onClick={undo}
              >
                {t("incomingOrders.undo")}
              </ToastAction>
            ),
          });
        },
        onError: (err: unknown) => {
          const apiErr = err as { status?: number; data?: { error?: string } } | null;
          if (
            (apiErr?.status === 409 && apiErr?.data?.error === "order_unavailable") ||
            apiErr?.status === 404
          ) {
            toast({
              title: t("incomingOrders.orderUnavailable"),
              variant: "destructive",
            });
            invalidate();
          } else {
            toast({
              title: t("incomingOrders.actionFailed"),
              variant: "destructive",
            });
          }
        },
      },
    );
  };

  return (
    <div
      className={cn(
        "glass-panel rounded-xl p-3 flex flex-col gap-3 transition-colors",
        selected && "ring-2 ring-amber-400 bg-amber-50/40",
        !selected && highlighted && "ring-2 ring-primary ring-offset-2",
      )}
      data-testid={`incoming-order-card-${order.id}`}
    >
      <div className="flex items-start gap-3">
        <div className="pt-1 shrink-0">
          <Checkbox
            checked={selected}
            onCheckedChange={() => onToggleSelected(order.id)}
            aria-label={t("incomingOrders.select")}
            data-testid={`order-select-${order.id}`}
          />
        </div>
        <OrderImage src={img} alt={serviceName} />
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground">
            <StatusIcon status={order.status} />
            <span>{t(`orderStatus.${order.status}`)}</span>
            <span aria-hidden="true">·</span>
            <span>{relativeAge(order.createdAt, t)}</span>
          </div>
          <h3 className="text-sm font-semibold text-foreground leading-tight truncate mt-0.5">
            {serviceName}
          </h3>
          <div className="text-xs text-muted-foreground truncate">
            {t("incomingOrders.from")}{" "}
            <span className="text-foreground/80 font-medium">{requesterName}</span>
          </div>
          {order.notes && (
            <div className="mt-1.5 text-xs text-foreground/80 line-clamp-3 whitespace-pre-wrap">
              {order.notes}
            </div>
          )}
        </div>
        <button
          type="button"
          onClick={() => onRequestDelete(order.id)}
          className="p-1.5 rounded-md text-rose-700 hover:bg-rose-50 hover:text-rose-800 transition-colors shrink-0"
          aria-label={t("incomingOrders.delete")}
          data-testid={`order-delete-${order.id}`}
        >
          <Trash2 size={16} />
        </button>
      </div>

      <div className="flex flex-wrap gap-2 justify-end">
        {order.status === "pending" && !order.assignedTo && (
          <Button size="sm" onClick={handleConfirmReceipt} disabled={busy}>
            {claim.isPending && <Loader2 size={14} className="animate-spin me-1.5" />}
            {claim.isPending
              ? t("incomingOrders.confirming")
              : t("incomingOrders.confirmReceipt")}
          </Button>
        )}

        {isMine && order.status === "received" && (
          <Button
            size="sm"
            onClick={() => handleSetStatus("preparing")}
            disabled={busy}
          >
            {t("incomingOrders.markPreparing")}
          </Button>
        )}

        {isMine && order.status === "preparing" && (
          <Button
            size="sm"
            onClick={() => handleSetStatus("completed")}
            disabled={busy}
            className="bg-emerald-600 hover:bg-emerald-700 text-white"
          >
            {t("incomingOrders.markCompleted")}
          </Button>
        )}

        {isMine &&
          (order.status === "received" || order.status === "preparing") && (
            <Button
              size="sm"
              variant="ghost"
              className="text-rose-700 hover:text-rose-800 hover:bg-rose-50"
              onClick={() => handleSetStatus("cancelled")}
              disabled={busy}
            >
              {t("incomingOrders.cancel")}
            </Button>
          )}
      </div>
    </div>
  );
}

export default function OrdersIncomingPage() {
  const { t, i18n } = useTranslation();
  const [, setLocation] = useLocation();
  const { user } = useAuth();
  const { toast } = useToast();
  const queryClient = useQueryClient();
  const lang = i18n.language;
  const isRtl = lang === "ar";
  const BackIcon = isRtl ? ArrowRight : ArrowLeft;

  const allowed = userCanReceiveOrders(user?.roles);

  const { data: orders, isLoading, isError, refetch } = useListIncomingServiceOrders({
    query: {
      queryKey: getListIncomingServiceOrdersQueryKey(),
      enabled: !!user && allowed,
    },
  });

  const meId = user?.id ?? -1;
  const sorted = (orders ?? [])
    .slice()
    .sort(
      (a, b) =>
        new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
    );
  const mine = sorted.filter((o) => o.assignedTo === meId);
  const unclaimed = sorted.filter((o) => o.status === "pending" && !o.assignedTo);
  const mineIds = useMemo(() => mine.map((o) => o.id), [mine]);
  const unclaimedIds = useMemo(() => unclaimed.map((o) => o.id), [unclaimed]);
  const allVisibleIds = useMemo(
    () => [...mineIds, ...unclaimedIds],
    [mineIds, unclaimedIds],
  );

  // Deep-link from a notification: /orders/incoming?order=<id> scrolls to
  // and flashes the matching order card, then strips the param so
  // re-renders don't re-trigger the jump.
  const orderSearch = useSearch();
  const [highlightOrderId, setHighlightOrderId] = useState<number | null>(null);
  const highlightHandledRef = useRef<string | null>(null);
  useEffect(() => {
    const params = new URLSearchParams(orderSearch);
    const orderParam = params.get("order");
    if (!orderParam) return;
    if (highlightHandledRef.current === orderParam) return;
    const id = Number(orderParam);
    if (!Number.isInteger(id) || id <= 0) return;
    highlightHandledRef.current = orderParam;
    setHighlightOrderId(id);
    if (typeof window !== "undefined") {
      params.delete("order");
      const qs = params.toString();
      window.history.replaceState(
        null,
        "",
        `${window.location.pathname}${qs ? `?${qs}` : ""}`,
      );
    }
  }, [orderSearch]);
  useEffect(() => {
    if (highlightOrderId == null) return;
    if (![...mine, ...unclaimed].some((o) => o.id === highlightOrderId)) return;
    const rafId = window.requestAnimationFrame(() => {
      const el = document.querySelector(
        `[data-testid="incoming-order-card-${highlightOrderId}"]`,
      );
      if (el && "scrollIntoView" in el) {
        (el as HTMLElement).scrollIntoView({
          block: "center",
          behavior: "smooth",
        });
      }
    });
    const clear = window.setTimeout(() => {
      setHighlightOrderId(null);
      highlightHandledRef.current = null;
    }, 2000);
    return () => {
      window.cancelAnimationFrame(rafId);
      window.clearTimeout(clear);
    };
  }, [highlightOrderId, mine, unclaimed]);

  const [selected, setSelected] = useState<Set<number>>(new Set());
  // confirmIds === null → no dialog; otherwise the ids that confirming will delete.
  const [confirmIds, setConfirmIds] = useState<number[] | null>(null);

  const bulkDelete = useBulkDeleteServiceOrders();
  const deleteOne = useDeleteServiceOrder();
  const isDeleting = bulkDelete.isPending || deleteOne.isPending;

  // Drop ids that are no longer visible (e.g. another receiver claimed them
  // and they fell out of our queue) so the count stays truthful.
  const validSelected = useMemo(() => {
    const visible = new Set(allVisibleIds);
    const next = new Set<number>();
    for (const id of selected) if (visible.has(id)) next.add(id);
    return next;
  }, [selected, allVisibleIds]);

  const selectedCount = validSelected.size;
  const mineSelectedCount = mineIds.filter((id) => validSelected.has(id)).length;
  const unclaimedSelectedCount = unclaimedIds.filter((id) =>
    validSelected.has(id),
  ).length;
  const mineState = triState(mineSelectedCount, mineIds.length);
  const unclaimedState = triState(unclaimedSelectedCount, unclaimedIds.length);

  const clearSelection = () => setSelected(new Set());

  const toggleOne = (id: number) => {
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const setSectionSelected = (sectionIds: number[], on: boolean) => {
    setSelected((prev) => {
      const next = new Set(prev);
      if (on) for (const id of sectionIds) next.add(id);
      else for (const id of sectionIds) next.delete(id);
      return next;
    });
  };

  const requestDelete = (id: number) => setConfirmIds([id]);
  const requestBulkDelete = () => {
    const ids = Array.from(validSelected);
    if (ids.length === 0) return;
    setConfirmIds(ids);
  };

  const showDeletedToast = (deleted: number, total: number) => {
    if (deleted > 0 && deleted === total) {
      toast({ title: t("incomingOrders.deleted", { count: deleted }) });
    } else if (deleted > 0) {
      toast({
        title: t("incomingOrders.deletePartial", { deleted, total }),
        variant: "destructive",
      });
    } else {
      toast({
        title: t("incomingOrders.deleteFailed"),
        variant: "destructive",
      });
    }
  };

  const finishDelete = (deletedIds: number[]) => {
    if (deletedIds.length > 0) {
      setSelected((prev) => {
        const next = new Set(prev);
        for (const id of deletedIds) next.delete(id);
        return next;
      });
    }
    setConfirmIds(null);
    queryClient.invalidateQueries({
      queryKey: getListIncomingServiceOrdersQueryKey(),
    });
    refetch();
  };

  const performDelete = () => {
    const ids = confirmIds ?? [];
    if (ids.length === 0) {
      setConfirmIds(null);
      return;
    }
    if (ids.length === 1) {
      const [only] = ids;
      deleteOne.mutate(
        { id: only },
        {
          onSuccess: () => {
            showDeletedToast(1, 1);
            finishDelete([only]);
          },
          onError: () => {
            showDeletedToast(0, 1);
            setConfirmIds(null);
          },
        },
      );
      return;
    }
    bulkDelete.mutate(
      { data: { ids } },
      {
        onSuccess: (resp) => {
          showDeletedToast(resp.deletedIds.length, ids.length);
          finishDelete(resp.deletedIds);
        },
        onError: () => {
          showDeletedToast(0, ids.length);
          setConfirmIds(null);
        },
      },
    );
  };

  const confirmCount = confirmIds?.length ?? 0;

  return (
    <div className="min-h-screen os-bg flex flex-col">
      <div className="glass-panel border-b border-slate-200/70 px-4 py-4 flex items-center gap-3 sticky top-0 z-10">
        <button
          onClick={() => setLocation("/")}
          className="p-2 rounded-xl hover:bg-slate-100 text-muted-foreground hover:text-foreground transition-colors"
          aria-label={t("incomingOrders.back")}
        >
          <BackIcon size={20} />
        </button>
        <div className="flex items-center gap-2 flex-1 min-w-0">
          <Inbox size={20} className="text-amber-500 shrink-0" />
          <h1 className="text-lg font-semibold text-foreground truncate">
            {t("incomingOrders.title")}
          </h1>
        </div>
      </div>

      <div className="flex-1 p-4 pb-24 max-w-2xl mx-auto w-full">
        {!allowed ? (
          <div className="flex flex-col items-center justify-center py-20 gap-3 text-center">
            <Inbox size={36} className="text-slate-300" />
            <div className="text-sm font-medium text-foreground">
              {t("incomingOrders.noAccess")}
            </div>
          </div>
        ) : isLoading ? (
          <div className="flex items-center justify-center py-20 text-muted-foreground">
            {t("common.loading")}
          </div>
        ) : isError ? (
          <div className="flex flex-col items-center justify-center py-20 gap-3 text-center">
            <div className="text-sm text-rose-700">
              {t("incomingOrders.loadError")}
            </div>
            <Button variant="outline" size="sm" onClick={() => refetch()}>
              {t("incomingOrders.retry")}
            </Button>
          </div>
        ) : mine.length === 0 && unclaimed.length === 0 ? (
          <div className="flex flex-col items-center justify-center py-20 gap-3 text-center">
            <Inbox size={36} className="text-slate-300" />
            <div className="text-sm font-medium text-foreground">
              {t("incomingOrders.empty")}
            </div>
            <div className="text-xs text-muted-foreground">
              {t("incomingOrders.emptyHint")}
            </div>
          </div>
        ) : (
          <div className="flex flex-col gap-6">
            {mine.length > 0 && (
              <section>
                <div className="flex items-center justify-between mb-2 px-1">
                  <h2 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                    {t("incomingOrders.subtitleMine")}
                  </h2>
                  <label className="flex items-center gap-2 text-xs text-foreground/80 cursor-pointer">
                    <Checkbox
                      checked={
                        mineState === "all"
                          ? true
                          : mineState === "some"
                            ? "indeterminate"
                            : false
                      }
                      onCheckedChange={(v) =>
                        setSectionSelected(mineIds, v === true)
                      }
                      aria-label={t("incomingOrders.selectAll")}
                      data-testid="select-all-mine"
                    />
                    <span>{t("incomingOrders.selectAll")}</span>
                  </label>
                </div>
                <div className="flex flex-col gap-2">
                  {mine.map((o) => (
                    <IncomingOrderCard
                      key={o.id}
                      order={o}
                      meId={meId}
                      highlighted={o.id === highlightOrderId}
                      onActionDone={refetch}
                      selected={validSelected.has(o.id)}
                      onToggleSelected={toggleOne}
                      onRequestDelete={requestDelete}
                    />
                  ))}
                </div>
              </section>
            )}
            {unclaimed.length > 0 && (
              <section>
                <div className="flex items-center justify-between mb-2 px-1">
                  <h2 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                    {t("incomingOrders.subtitleUnclaimed")}
                  </h2>
                  <label className="flex items-center gap-2 text-xs text-foreground/80 cursor-pointer">
                    <Checkbox
                      checked={
                        unclaimedState === "all"
                          ? true
                          : unclaimedState === "some"
                            ? "indeterminate"
                            : false
                      }
                      onCheckedChange={(v) =>
                        setSectionSelected(unclaimedIds, v === true)
                      }
                      aria-label={t("incomingOrders.selectAll")}
                      data-testid="select-all-unclaimed"
                    />
                    <span>{t("incomingOrders.selectAll")}</span>
                  </label>
                </div>
                <div className="flex flex-col gap-2">
                  {unclaimed.map((o) => (
                    <IncomingOrderCard
                      key={o.id}
                      order={o}
                      meId={meId}
                      highlighted={o.id === highlightOrderId}
                      onActionDone={refetch}
                      selected={validSelected.has(o.id)}
                      onToggleSelected={toggleOne}
                      onRequestDelete={requestDelete}
                    />
                  ))}
                </div>
              </section>
            )}
          </div>
        )}
      </div>

      {selectedCount > 0 && (
        <div
          className="fixed bottom-0 inset-x-0 z-20 border-t border-slate-200 bg-white/95 backdrop-blur px-4 py-3 flex items-center gap-3 max-w-2xl mx-auto"
          data-testid="bulk-action-bar"
        >
          <div className="flex-1 text-sm text-foreground">
            {t("incomingOrders.selectedCount", { count: selectedCount })}
          </div>
          <Button
            variant="ghost"
            size="sm"
            onClick={clearSelection}
            disabled={isDeleting}
            data-testid="clear-selection"
          >
            {t("incomingOrders.clearSelection")}
          </Button>
          <Button
            variant="destructive"
            size="sm"
            onClick={requestBulkDelete}
            disabled={isDeleting}
            data-testid="bulk-delete"
          >
            {isDeleting ? (
              <Loader2 size={14} className="animate-spin me-1.5" />
            ) : (
              <Trash2 size={14} className="me-1.5" />
            )}
            {t("incomingOrders.delete")}
          </Button>
        </div>
      )}

      <AlertDialog
        open={confirmIds !== null}
        onOpenChange={(open) => {
          if (!open && !isDeleting) setConfirmIds(null);
        }}
      >
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>
              {t("incomingOrders.deleteConfirmTitle", { count: confirmCount })}
            </AlertDialogTitle>
            <AlertDialogDescription>
              {t("incomingOrders.deleteConfirmBody", { count: confirmCount })}
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel disabled={isDeleting}>
              {t("common.cancel")}
            </AlertDialogCancel>
            <AlertDialogAction
              onClick={(e) => {
                e.preventDefault();
                performDelete();
              }}
              disabled={isDeleting}
              className="bg-rose-600 hover:bg-rose-700 text-white"
              data-testid="confirm-delete"
            >
              {isDeleting && (
                <Loader2 size={14} className="animate-spin me-1.5" />
              )}
              {t("incomingOrders.delete")}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
      <AppDock currentSlug="orders-incoming" />
    </div>
  );
}
