"use client";

import { useMemo, useState, useTransition } from "react";
import { PackageCheck, Truck } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { DetailCard } from "./detail-card";
import { FulfillmentStatusBadge } from "../../components/order-status-badge";
import { formatDate } from "../../lib/format-utils";
import { createShipment } from "@/lib/actions/orders";
import type {
  FulfillmentStatus,
  Order,
  ShipmentInfo,
} from "../../types";

interface FulfillmentCardProps {
  order: Order;
  /** Applies the persisted fulfillment + shipment state optimistically. */
  onOrderUpdated: (updates: {
    fulfillmentStatus: FulfillmentStatus;
    shipment?: ShipmentInfo;
    items: { id: string; shippedQuantity: number }[];
  }) => void;
}

/**
 * Per-line fulfillment. Lets an admin ship 1 of 3 units for a line — the order
 * stays PARTIALLY_FULFILLED until every unit is handed to the courier. Quantities
 * are capped at `quantity − shippedQuantity` server-side (`createShipment`), so
 * the UI can never over-ship even if two tabs are open.
 */
export function FulfillmentCard({ order, onOrderUpdated }: FulfillmentCardProps) {
  const [, startTransition] = useTransition();
  const [open, setOpen] = useState(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [carrier, setCarrier] = useState(order.shipment?.carrier ?? "");
  const [tracking, setTracking] = useState(order.shipment?.trackingNumber ?? "");

  // Keyed by order item id — pre-filled with each line's remaining qty so the
  // common full-shipment case needs no typing; lower a line to ship partially.
  const [shipments, setShipments] = useState<Record<string, number>>(() =>
    Object.fromEntries(
      order.items.map((item) => [item.id, item.quantity - item.shippedQuantity]),
    ),
  );

  const summary = useMemo(() => {
    const shipped = order.items.reduce((sum, i) => sum + i.shippedQuantity, 0);
    const ordered = order.items.reduce((sum, i) => sum + i.quantity, 0);
    return { shipped, ordered };
  }, [order.items]);

  const remainingCount = order.items.reduce(
    (sum, i) => sum + (i.quantity - i.shippedQuantity),
    0,
  );
  const canRecord =
    remainingCount > 0 && order.status !== "cancelled" && order.fulfillmentStatus !== "cancelled";

  const openDialog = () => {
    setCarrier(order.shipment?.carrier ?? "");
    setTracking(order.shipment?.trackingNumber ?? "");
    setShipments(
      Object.fromEntries(
        order.items.map((item) => [item.id, item.quantity - item.shippedQuantity]),
      ),
    );
    setError(null);
    setOpen(true);
  };

  const submit = () => {
    const lines = order.items
      .map((item) => ({
        itemId: item.id,
        name: item.name,
        quantity: Number(shipments[item.id] ?? 0),
        remaining: item.quantity - item.shippedQuantity,
      }))
      .filter((line) => line.quantity > 0);

    for (const line of lines) {
      if (!Number.isInteger(line.quantity) || line.quantity <= 0) {
        setError(`Shipped quantity for "${line.name}" must be a whole number.`);
        return;
      }
      if (line.quantity > line.remaining) {
        setError(
          `Only ${line.remaining} unit(s) of "${line.name}" remain to ship.`,
        );
        return;
      }
    }
    if (lines.length === 0) {
      setError("Set a shipped quantity on at least one item.");
      return;
    }

    setBusy(true);
    setError(null);
    startTransition(() => {
      void createShipment({
        orderId: order.id,
        carrier,
        trackingNumber: tracking,
        items: lines.map((l) => ({ orderItemId: l.itemId, quantity: l.quantity })),
      }).then((result) => {
        setBusy(false);
        if (!result.ok) {
          setError(result.error);
          return;
        }
        // Recompute post-shipment counts optimistically (server revalidates).
        const nextItems = order.items.map((item) => ({
          id: item.id,
          shippedQuantity: item.shippedQuantity + (shipments[item.id] ?? 0),
        }));
        const allShipped = nextItems.every(
          (it) => it.shippedQuantity >= (order.items.find((o) => o.id === it.id)?.quantity ?? 0),
        );
        const anyShipped = nextItems.some((it) => it.shippedQuantity > 0);
        onOrderUpdated({
          fulfillmentStatus: allShipped ? "fulfilled" : anyShipped ? "partially-fulfilled" : "unfulfilled",
          shipment: {
            carrier: carrier.trim(),
            trackingNumber: tracking.trim(),
            shippedAt: order.shipment?.shippedAt,
            estimatedDelivery: order.shipment?.estimatedDelivery,
          },
          items: nextItems,
        });
        setOpen(false);
      });
    });
  };

  const setLineQuantity = (itemId: string, value: string) => {
    const num = value === "" ? 0 : Number(value);
    setShipments((prev) => ({ ...prev, [itemId]: num }));
  };

  return (
    <>
      <DetailCard
        title="Fulfilment"
        icon={<Truck className="h-4 w-4 text-muted-foreground" />}
        action={<FulfillmentStatusBadge status={order.fulfillmentStatus} />}
      >
        <div className="space-y-3">
          <div>
            <p className="text-sm font-medium text-foreground/90">
              {summary.shipped} of {summary.ordered} units shipped
            </p>
            <div className="mt-1.5 h-1.5 w-full overflow-hidden rounded-full bg-muted">
              <div
                className="h-full rounded-full bg-green-500/80 transition-all"
                style={{
                  width: `${summary.ordered ? Math.round((summary.shipped / summary.ordered) * 100) : 0}%`,
                }}
              />
            </div>
          </div>

          {order.items.some((i) => i.shippedQuantity < i.quantity) && (
            <p className="text-xs leading-relaxed text-muted-foreground">
              {order.items
                .filter((i) => i.shippedQuantity < i.quantity)
                .map((i) => `${i.name} (${i.quantity - i.shippedQuantity} to ship)`)
                .join(" · ")}
            </p>
          )}

          {order.shipment?.trackingNumber && (
            <p className="border-t border-border/60 pt-2 text-xs text-muted-foreground">
              {order.shipment.carrier} ·{" "}
              <span className="font-mono text-foreground/80">
                {order.shipment.trackingNumber}
              </span>
              {order.shipment.shippedAt && (
                <span className="block pt-0.5">
                  Shipped {formatDate(order.shipment.shippedAt)}
                </span>
              )}
            </p>
          )}

          {error && (
            <p className="rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2 text-xs text-destructive">
              {error}
            </p>
          )}

          {canRecord && (
            <Button
              size="sm"
              onClick={openDialog}
              disabled={order.fulfillmentStatus === "fulfilled"}
              className="w-fit"
            >
              <PackageCheck className="mr-1.5 h-3.5 w-3.5" />
              Record shipment
            </Button>
          )}
        </div>
      </DetailCard>

      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent className="max-w-xl">
          <DialogHeader>
            <DialogTitle>Record a shipment</DialogTitle>
            <DialogDescription>
              Mark units as handed to the courier. Ship a line partially by
              entering fewer than the remaining quantity — the order stays
              Partially Fulfilled until everything ships.
            </DialogDescription>
          </DialogHeader>

          <div className="max-h-[45vh] space-y-3 overflow-y-auto pr-1 py-1">
            {order.items.map((item) => {
              const remaining = item.quantity - item.shippedQuantity;
              return (
                <div
                  key={item.id}
                  className="flex items-center justify-between gap-3 rounded-lg border border-border/60 px-3 py-2.5"
                >
                  <div className="min-w-0">
                    <p className="truncate text-sm font-medium">{item.name}</p>
                    <p className="text-xs text-muted-foreground">
                      {item.shippedQuantity} of {item.quantity} shipped ·{" "}
                      {remaining} remaining
                    </p>
                  </div>
                  <div className="flex w-28 shrink-0 items-center gap-2">
                    <Input
                      id={`ship-${item.id}`}
                      type="number"
                      min={0}
                      max={remaining}
                      step={1}
                      value={shipments[item.id] ?? 0}
                      onChange={(e) => setLineQuantity(item.id, e.target.value)}
                      disabled={remaining <= 0}
                    />
                    <Label htmlFor={`ship-${item.id}`} className="text-xs text-muted-foreground">
                      of {remaining}
                    </Label>
                  </div>
                </div>
              );
            })}

            <div className="grid gap-3 pt-1 sm:grid-cols-2">
              <div className="space-y-1.5">
                <Label htmlFor="ship-carrier">Carrier</Label>
                <Input
                  id="ship-carrier"
                  value={carrier}
                  onChange={(e) => setCarrier(e.target.value)}
                  placeholder="e.g. SA Paribahan, RedX, Pathao"
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor="ship-tracking">Tracking number</Label>
                <Input
                  id="ship-tracking"
                  value={tracking}
                  onChange={(e) => setTracking(e.target.value)}
                  placeholder="e.g. BX-84719302"
                />
              </div>
            </div>
          </div>

          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => setOpen(false)}
              disabled={busy}
            >
              Cancel
            </Button>
            <Button onClick={submit} disabled={busy}>
              {busy ? "Recording..." : "Record shipment"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}