/**
 * Sortable, checkbox-selectable table of PO line items.
 *
 * Columns: checkbox · image · title · UPC · supplier#/notions# · shelf ·
 * basket · on-order · total sold · cost ea · last sold · first in ·
 * [notions inv (conditional)] · MOQ (editable, local) · qty (editable,
 * highlighted on MOQ mismatch) · remove
 *
 * Sorting is local-only (no server round-trip), driven by clickable
 * column headers. The Notions column toggles based on the supplier prop.
 * MOQ is inline-editable and updates a per-row `moqOverride` field —
 * never sent to the backend, never persisted.
 */

import { useMemo, useState, useCallback } from "react";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { X as XIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { formatCurrency, formatNumber, formatDateShort } from "@/utils/productUtils";
import type { PoLineItem } from "./types";
import { computeCostEach } from "./types";
import { NOTIONS_SUPPLIER_ID } from "./constants";

type SortKey =
  | "title"
  | "barcode"
  | "supplier_ref"
  | "current_stock"
  | "baskets"
  | "on_order_qty"
  | "total_sold"
  | "current_cost_price"
  | "date_last_sold"
  | "date_first_received"
  | "notions_inv_count"
  | "moq"
  | "qty";

type SortDir = "asc" | "desc";

interface LineItemsTableProps {
  items: PoLineItem[];
  selectedPids: Set<number>;
  supplierId: number | undefined;
  onToggleSelect: (pid: number) => void;
  onToggleSelectAll: (selectAll: boolean) => void;
  onChangeQty: (pid: number, qty: number) => void;
  onChangeMoqOverride: (pid: number, moq: number | undefined) => void;
  onRemove: (pid: number) => void;
}

/** Effective MOQ for a row, considering the user's local override. */
function effectiveMoq(item: PoLineItem): number | null {
  if (item.moqOverride != null) return item.moqOverride;
  return item.moq;
}

/** True if the row's qty isn't a multiple of its (effective) MOQ. */
function isQtyMoqMismatch(item: PoLineItem): boolean {
  const moq = effectiveMoq(item);
  if (!moq || moq <= 0) return false;
  if (item.qty <= 0) return false;
  return item.qty % moq !== 0;
}

function compareValues(a: unknown, b: unknown, dir: SortDir): number {
  const sign = dir === "asc" ? 1 : -1;
  // Push nulls/undefineds to the bottom regardless of direction
  if (a == null && b == null) return 0;
  if (a == null) return 1;
  if (b == null) return -1;
  if (typeof a === "number" && typeof b === "number") {
    return (a - b) * sign;
  }
  // Date strings sort lexicographically as ISO; fall back to string compare
  return String(a).localeCompare(String(b)) * sign;
}

export function LineItemsTable({
  items,
  selectedPids,
  supplierId,
  onToggleSelect,
  onToggleSelectAll,
  onChangeQty,
  onChangeMoqOverride,
  onRemove,
}: LineItemsTableProps) {
  const [sortKey, setSortKey] = useState<SortKey | null>(null);
  const [sortDir, setSortDir] = useState<SortDir>("asc");

  const isNotions = Number(supplierId) === NOTIONS_SUPPLIER_ID;

  const sorted = useMemo(() => {
    if (!sortKey) return items;
    const accessors: Record<SortKey, (i: PoLineItem) => unknown> = {
      title: (i) => i.title?.toLowerCase(),
      barcode: (i) => i.barcode,
      supplier_ref: (i) => (isNotions ? i.notions_reference : i.vendor_reference),
      current_stock: (i) => i.current_stock,
      baskets: (i) => i.baskets,
      on_order_qty: (i) => i.on_order_qty,
      total_sold: (i) => i.total_sold,
      current_cost_price: (i) => computeCostEach(i, supplierId),
      date_last_sold: (i) => i.date_last_sold,
      date_first_received: (i) => i.date_first_received,
      notions_inv_count: (i) => i.notions_inv_count,
      moq: (i) => effectiveMoq(i),
      qty: (i) => i.qty,
    };
    const accessor = accessors[sortKey];
    return [...items].sort((a, b) => compareValues(accessor(a), accessor(b), sortDir));
  }, [items, sortKey, sortDir, isNotions, supplierId]);

  const handleSort = useCallback(
    (key: SortKey) => {
      if (sortKey === key) {
        setSortDir((d) => (d === "asc" ? "desc" : "asc"));
      } else {
        setSortKey(key);
        setSortDir("asc");
      }
    },
    [sortKey]
  );

  const allSelected =
    items.length > 0 && items.every((i) => selectedPids.has(i.pid));
  const someSelected = !allSelected && items.some((i) => selectedPids.has(i.pid));

  if (items.length === 0) {
    return (
      <div className="rounded-md border border-dashed p-12 text-center text-muted-foreground">
        <p className="text-sm">No products added yet.</p>
      </div>
    );
  }

  const SortableHead = ({
    label,
    sortBy,
    align = "left",
    className,
  }: {
    label: string;
    sortBy: SortKey;
    align?: "left" | "right" | "center";
    className?: string;
  }) => {
    const isActive = sortKey === sortBy;
    return (
      <TableHead
        className={cn(
          align === "right" && "text-right",
          align === "center" && "text-center",
          className
        )}
      >
        <button
          type="button"
          onClick={() => handleSort(sortBy)}
          className={cn(
            "inline-flex items-center gap-1 hover:text-foreground transition-colors",
            isActive ? "text-foreground" : "text-muted-foreground",
            align === "right" && "flex-row-reverse",
            align === "center" && "justify-center w-full"
          )}
        >
          {label}
        </button>
      </TableHead>
    );
  };

  return (
    <div className="rounded-md border overflow-x-auto">
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead className="w-10">
              <Checkbox
                checked={allSelected ? true : someSelected ? "indeterminate" : false}
                onCheckedChange={(v) => onToggleSelectAll(Boolean(v))}
                aria-label="Select all rows"
              />
            </TableHead>
            <SortableHead label="Qty" sortBy="qty" align="center" />
            <TableHead className="w-[72px] text-center">Image</TableHead>
            <SortableHead label="Product" sortBy="title" />
            <SortableHead label="UPC" sortBy="barcode" align="left" />
            <SortableHead
              label={isNotions ? "Notions #" : "Supplier #"}
              sortBy="supplier_ref"
              className="whitespace-nowrap"
            />
            <SortableHead label="MOQ" sortBy="moq" align="center" />
            <SortableHead label="Shelf" sortBy="current_stock" align="center" />
            <SortableHead label="Basket" sortBy="baskets" align="center" />
            <SortableHead label="On Order" sortBy="on_order_qty" align="center" />
            <SortableHead label="Total Sold" sortBy="total_sold" align="center" />
            <SortableHead label="Cost" sortBy="current_cost_price" align="center" />
            <SortableHead label="Last Sold" sortBy="date_last_sold" align="center" className="whitespace-nowrap"/>
            <SortableHead label="First In" sortBy="date_first_received" align="center" className="whitespace-nowrap"/>
            {isNotions && (
              <SortableHead
                label="Notions Inv."
                sortBy="notions_inv_count"
                align="center"
              />
            )}
            <TableHead className="w-10"></TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {sorted.map((item) => {
            const isSelected = selectedPids.has(item.pid);
            const moq = effectiveMoq(item);
            const mismatch = isQtyMoqMismatch(item);
            return (
              <TableRow
                key={item.pid}
                className={cn(isSelected && "bg-muted/50")}
              >
                <TableCell>
                  <Checkbox
                    checked={isSelected}
                    onCheckedChange={() => onToggleSelect(item.pid)}
                    aria-label={`Select ${item.title}`}
                  />
                </TableCell>
                <TableCell className="text-center">
                  <Input
                    type="text"
                    inputMode="numeric"
                    value={item.qty}
                    onChange={(e) => {
                      const n = Math.max(
                        0,
                        Math.round(Number(e.target.value.replace(/[^0-9]/g, "")) || 0)
                      );
                      onChangeQty(item.pid, n);
                    }}
                    className={cn(
                      "w-14 h-8 text-center",
                      mismatch &&
                        "border-amber-500 focus-visible:ring-amber-500 bg-amber-50"
                    )}
                    aria-label={`Quantity for ${item.title}`}
                    title={
                      mismatch
                        ? `Not a multiple of MOQ (${moq})`
                        : undefined
                    }
                  />
                </TableCell>
                <TableCell>
                  {item.image_url ? (
                    <img
                      src={item.image_url}
                      alt={item.title}
                      className="h-[60px] w-[60px] object-contain rounded"
                      loading="lazy"
                    />
                  ) : (
                    <div className="h-[60px] w-[60px] rounded bg-muted" />
                  )}
                </TableCell>
                <TableCell className="max-w-[350px] min-w-[200px]">
                  <div className="font-medium line-clamp-2" title={item.title}>
                    {item.title}
                  </div>
                </TableCell>
                <TableCell className="font-mono text-xs whitespace-nowrap text-center">
                  {item.barcode || "—"}
                </TableCell>
                <TableCell className="font-mono text-xs whitespace-nowrap text-center">
                  {(isNotions ? item.notions_reference : item.vendor_reference) || "—"}
                </TableCell>
                <TableCell className="text-center">
                  <Input
                    type="text"
                    inputMode="numeric"
                    value={moq ?? ""}
                    onChange={(e) => {
                      const v = e.target.value.replace(/[^0-9]/g, "");
                      if (v === "") {
                        onChangeMoqOverride(item.pid, 0);
                      } else {
                        const n = Math.max(0, Math.round(Number(v)));
                        onChangeMoqOverride(item.pid, Number.isFinite(n) ? n : 0);
                      }
                    }}
                    className="w-14 h-8 text-center text-xs"
                    aria-label={`MOQ for ${item.title}`}
                  />
                </TableCell>
                <TableCell className="text-center">
                  {item.current_stock != null ? formatNumber(item.current_stock) : "—"}
                </TableCell>
                <TableCell className="text-center">
                  {item.baskets != null ? formatNumber(item.baskets) : "—"}
                </TableCell>
                <TableCell className="text-center">
                  {item.on_order_qty != null ? formatNumber(item.on_order_qty) : "—"}
                </TableCell>
                <TableCell className="text-center">
                  {item.total_sold != null ? formatNumber(item.total_sold) : "—"}
                </TableCell>
                <TableCell className="text-center whitespace-nowrap">
                  {(() => {
                    const cost = computeCostEach(item, supplierId);
                    return cost != null ? formatCurrency(cost) : "—";
                  })()}
                </TableCell>
                <TableCell className="text-xs whitespace-nowrap text-center">
                  {item.date_last_sold ? formatDateShort(item.date_last_sold) : "—"}
                </TableCell>
                <TableCell className="text-xs whitespace-nowrap text-center">
                  {item.date_first_received ? formatDateShort(item.date_first_received) : "—"}
                </TableCell>
                {isNotions && (
                  <TableCell className="text-center">
                    {item.notions_inv_count != null
                      ? formatNumber(item.notions_inv_count)
                      : "—"}
                  </TableCell>
                )}
                <TableCell>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-8 w-8 p-0 hover:text-destructive hover:bg-transparent"
                    onClick={() => onRemove(item.pid)}
                    aria-label={`Remove ${item.title}`}
                  >
                    <XIcon className="h-4 w-4" />
                  </Button>
                </TableCell>
              </TableRow>
            );
          })}
        </TableBody>
      </Table>
    </div>
  );
}
