"use client";

import { useState, useEffect, useRef } from "react";
import { Plus, Trash2 } from "lucide-react";
import { formatCurrency } from "@/lib/utils";
import type { LineItemInput } from "@/lib/validations/po";
import { SearchableSelect } from "@/components/ui/searchable-select";
import type { AccountGroup } from "@/app/(portal)/po/new/new-po-form";

const UOM_OPTIONS = [
  { value: "pc",   label: "pc — Piece" },
  { value: "set",  label: "set — Set" },
  { value: "pk",   label: "pk — Pack" },
  { value: "box",  label: "box — Box" },
  { value: "pair", label: "pair — Pair" },
  { value: "roll", label: "roll — Roll" },
  { value: "kg",   label: "kg — Kilogram" },
  { value: "g",    label: "g — Gram" },
  { value: "L",    label: "L — Litre" },
  { value: "mL",   label: "mL — Millilitre" },
  { value: "m",    label: "m — Metre" },
  { value: "m2",   label: "m² — Sq. Metre" },
  { value: "hr",    label: "hr — Hour" },
  { value: "day",   label: "day — Day" },
  { value: "week",  label: "week — Week" },
  { value: "month", label: "month — Month" },
  { value: "year",  label: "year — Year" },
  { value: "lump", label: "lump — Lump Sum" },
  { value: "Ltr",  label: "Ltr — Litre (alt)" },
];

type ProductHit = {
  id: string;
  code: string;
  name: string;
  description: string | null;
  lastPrice: number | null;
  vendorPrices: { vendorId: string; vendorName: string; price: number }[];
};

export type AccountOption = { id: string; name: string; code: string };

interface Props {
  items: LineItemInput[];
  onChange?: (items: LineItemInput[]) => void;
  readOnly?: boolean;
  originalItems?: LineItemInput[];
  /** Label shown in the diff banner when originalItems is provided */
  originalItemsLabel?: string;
  /** When true, show per-row account selector */
  multiAccount?: boolean;
  /** Grouped accounts for the searchable per-row selector */
  accounts?: AccountGroup[];
  /** The PO-level default account id — pre-selected in each row */
  defaultAccountId?: string;
}

type EditRow = {
  name: string;
  description: string;
  quantity: string;
  unit: string;
  size: string;
  unitPrice: string;
  gstRate: string;
  productId?: string;
  accountId?: string;
};

function toEditRow(item: LineItemInput): EditRow {
  return {
    name: item.name,
    description: item.description ?? "",
    quantity: String(item.quantity),
    unit: item.unit,
    size: item.size ?? "",
    unitPrice: item.unitPrice ? String(item.unitPrice) : "",
    gstRate: String(item.gstRate ?? 0.18),
    productId: item.productId,
    accountId: item.accountId,
  };
}

function toLineItem(row: EditRow): LineItemInput {
  return {
    name: row.name,
    description: row.description || undefined,
    quantity: parseFloat(row.quantity) || 0,
    unit: row.unit,
    size: row.size || undefined,
    unitPrice: parseFloat(row.unitPrice) || 0,
    gstRate: row.gstRate !== "" && row.gstRate != null ? parseFloat(row.gstRate) : 0.18,
    productId: row.productId || undefined,
    accountId: row.accountId || undefined,
  };
}

function calcTotals(items: LineItemInput[]) {
  const taxable = items.reduce((s, i) => s + i.quantity * i.unitPrice, 0);
  const gst = items.reduce((s, i) => s + i.quantity * i.unitPrice * (i.gstRate ?? 0.18), 0);
  return { taxable, gst, grand: taxable + gst };
}

function NameCell({
  name,
  description,
  productId,
  onChange,
}: {
  name: string;
  description: string;
  productId?: string;
  onChange: (name: string, description: string, pid?: string, price?: number) => void;
}) {
  const [hits, setHits] = useState<ProductHit[]>([]);
  const [open, setOpen] = useState(false);
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const wrapRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    function handleClick(e: MouseEvent) {
      if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) {
        setOpen(false);
      }
    }
    document.addEventListener("mousedown", handleClick);
    return () => document.removeEventListener("mousedown", handleClick);
  }, []);

  function handleNameInput(v: string) {
    onChange(v, description, undefined);
    if (timerRef.current) clearTimeout(timerRef.current);
    if (v.length < 2) { setHits([]); setOpen(false); return; }
    timerRef.current = setTimeout(async () => {
      try {
        const res = await fetch(`/api/products/search?q=${encodeURIComponent(v)}`);
        const data: ProductHit[] = await res.json();
        setHits(data);
        setOpen(data.length > 0);
      } catch {
        setHits([]);
      }
    }, 250);
  }

  function select(hit: ProductHit) {
    onChange(hit.name, hit.description ?? description, hit.id, hit.lastPrice ?? undefined);
    setOpen(false);
    setHits([]);
  }

  return (
    <div ref={wrapRef} className="relative w-full space-y-1">
      <div className="relative">
        <input
          value={name}
          onChange={(e) => handleNameInput(e.target.value)}
          onFocus={() => { if (hits.length > 0) setOpen(true); }}
          className="w-full rounded border border-neutral-200 px-2 py-1.5 text-sm focus:border-primary-500 focus:outline-none"
          placeholder="Item name *"
          required
        />
        {productId && (
          <span className="absolute right-2 top-1/2 -translate-y-1/2 text-xs text-primary-500 pointer-events-none select-none">
            ✓
          </span>
        )}
        {open && (
          <ul className="absolute z-50 left-0 right-0 top-full mt-0.5 max-h-52 overflow-y-auto rounded-lg border border-neutral-200 bg-white shadow-lg text-sm">
            {hits.map((hit) => (
              <li key={hit.id}>
                <button
                  type="button"
                  onMouseDown={(e) => { e.preventDefault(); select(hit); }}
                  className="w-full text-left px-3 py-2 hover:bg-primary-50 flex items-start gap-2"
                >
                  <span className="font-mono text-xs text-neutral-400 shrink-0 mt-0.5 w-24 truncate">{hit.code}</span>
                  <span className="flex-1 min-w-0">
                    <span className="font-medium text-neutral-900">{hit.name}</span>
                    {hit.description && (
                      <span className="block text-xs text-neutral-500 truncate">{hit.description}</span>
                    )}
                    {hit.vendorPrices.length > 0 && (
                      <span className="block text-xs text-neutral-400 truncate mt-0.5">
                        {hit.vendorPrices.map(vp => `${vp.vendorName}: ${formatCurrency(vp.price)}`).join(" · ")}
                      </span>
                    )}
                  </span>
                  {hit.lastPrice != null && hit.vendorPrices.length === 0 && (
                    <span className="shrink-0 text-xs text-neutral-500">{formatCurrency(hit.lastPrice)}</span>
                  )}
                </button>
              </li>
            ))}
          </ul>
        )}
      </div>
      <input
        value={description}
        onChange={(e) => onChange(name, e.target.value, productId)}
        className="w-full rounded border border-neutral-200 px-2 py-1 text-xs text-neutral-500 focus:border-primary-500 focus:outline-none"
        placeholder="Description (optional)"
      />
    </div>
  );
}

export function LineItemsEditor({
  items,
  onChange,
  readOnly = false,
  originalItems,
  originalItemsLabel,
  multiAccount = false,
  accounts = [],
  defaultAccountId,
}: Props) {
  const [rows, setRows] = useState<EditRow[]>(() => items.map(toEditRow));

  function updateRows(next: EditRow[]) {
    setRows(next);
    onChange?.(next.map(toLineItem));
  }

  function update(index: number, field: keyof EditRow, value: string) {
    updateRows(rows.map((row, i) => (i === index ? { ...row, [field]: value } : row)));
  }

  function updateNameCell(index: number, name: string, description: string, productId?: string, price?: number) {
    updateRows(
      rows.map((row, i) => {
        if (i !== index) return row;
        return {
          ...row,
          name,
          description,
          productId: productId ?? undefined,
          unitPrice: price != null ? String(price) : row.unitPrice,
        };
      })
    );
  }

  function add() {
    updateRows([...rows, {
      name: "", description: "", quantity: "1", unit: "pc", size: "", unitPrice: "", gstRate: "0.18",
      accountId: defaultAccountId,
    }]);
  }

  function remove(index: number) {
    updateRows(rows.filter((_, i) => i !== index));
  }

  const accountMap = Object.fromEntries(
    (accounts ?? []).flatMap((g) => g.items).map((a) => [a.id, a])
  );

  // ── Read-only view ───────────────────────────────────────────────────────────
  if (readOnly) {
    const hasSize = items.some((item) => item.size);
    const hasDiff = originalItems && originalItems.length > 0;
    const showAccount = items.some((item) => item.accountId);
    const { taxable, gst, grand } = calcTotals(items);

    return (
      <div className="overflow-x-auto">
        {hasDiff && (
          <p className="mb-2 text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded px-3 py-1.5">
            {originalItemsLabel ?? "Line items were amended by manager. Current values shown; original values shown with strikethrough."}
          </p>
        )}
        <table className="w-full text-sm">
          <thead>
            <tr className="border-b border-neutral-200">
              <th className="pb-2 text-left font-medium text-neutral-600 w-full">Item</th>
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">Qty</th>
              <th className="pb-2 text-left font-medium text-neutral-600 pl-3 whitespace-nowrap">Unit</th>
              {hasSize && <th className="pb-2 text-left font-medium text-neutral-600 pl-3 whitespace-nowrap">Size</th>}
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">Unit Price</th>
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">Taxable</th>
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">GST%</th>
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">Total</th>
              {showAccount && <th className="pb-2 text-left font-medium text-neutral-600 pl-4 whitespace-nowrap">Account</th>}
            </tr>
          </thead>
          <tbody className="divide-y divide-neutral-100">
            {items.map((item, i) => {
              const orig = originalItems?.[i];
              const qtyChanged = orig && Number(orig.quantity) !== item.quantity;
              const priceChanged = orig && Number(orig.unitPrice) !== item.unitPrice;
              const nameChanged = orig && orig.name !== item.name;
              const gstChanged = orig && Number(orig.gstRate ?? 0.18) !== (item.gstRate ?? 0.18);
              const taxableAmt = item.quantity * item.unitPrice;
              const gstAmt = taxableAmt * (item.gstRate ?? 0.18);
              const acct = item.accountId ? accountMap[item.accountId] : null;
              return (
                <tr key={i}>
                  <td className="py-2 pr-4">
                    {nameChanged && <span className="block text-neutral-400 line-through text-xs">{orig.name}</span>}
                    <span className={nameChanged ? "text-amber-700 font-medium" : "text-neutral-900"}>{item.name}</span>
                    {item.description && (
                      <span className="block text-xs text-neutral-500 mt-0.5">{item.description}</span>
                    )}
                  </td>
                  <td className="py-2 pl-4 text-right">
                    {qtyChanged && <span className="block text-neutral-400 line-through text-xs">{Number(orig.quantity)}</span>}
                    <span className={qtyChanged ? "text-amber-700 font-medium" : ""}>{item.quantity}</span>
                  </td>
                  <td className="py-2 pl-3 text-neutral-500">{item.unit}</td>
                  {hasSize && <td className="py-2 pl-3 text-neutral-500">{item.size ?? "—"}</td>}
                  <td className="py-2 pl-4 text-right">
                    {priceChanged && <span className="block text-neutral-400 line-through text-xs">{formatCurrency(Number(orig.unitPrice))}</span>}
                    <span className={priceChanged ? "text-amber-700 font-medium" : ""}>{formatCurrency(item.unitPrice)}</span>
                  </td>
                  <td className="py-2 pl-4 text-right">{formatCurrency(taxableAmt)}</td>
                  <td className="py-2 pl-4 text-right text-neutral-500">
                    {gstChanged && <span className="block text-neutral-400 line-through text-xs">{Math.round((orig.gstRate ?? 0.18) * 100)}%</span>}
                    <span className={gstChanged ? "text-amber-700 font-medium" : ""}>{Math.round((item.gstRate ?? 0.18) * 100)}%</span>
                  </td>
                  <td className="py-2 pl-4 text-right">{formatCurrency(taxableAmt + gstAmt)}</td>
                  {showAccount && (
                    <td className="py-2 pl-4 text-xs text-neutral-500 font-mono">
                      {acct ? acct.code : "—"}
                    </td>
                  )}
                </tr>
              );
            })}
          </tbody>
          <tfoot>
            <tr className="border-t border-neutral-100">
              <td colSpan={hasSize ? (showAccount ? 6 : 5) : (showAccount ? 5 : 4)} className="pt-3 text-right text-sm text-neutral-500">Taxable subtotal</td>
              <td className="pt-3 pl-4 text-right text-sm text-neutral-700" colSpan={3}>{formatCurrency(taxable)}</td>
            </tr>
            <tr>
              <td colSpan={hasSize ? (showAccount ? 6 : 5) : (showAccount ? 5 : 4)} className="py-0.5 text-right text-sm text-neutral-500">GST</td>
              <td className="py-0.5 pl-4 text-right text-sm text-neutral-700" colSpan={3}>{formatCurrency(gst)}</td>
            </tr>
            <tr className="border-t border-neutral-200">
              <td colSpan={hasSize ? (showAccount ? 6 : 5) : (showAccount ? 5 : 4)} className="pt-2 text-right text-sm font-semibold text-neutral-900">Grand Total</td>
              <td className="pt-2 pl-4 text-right text-sm font-semibold text-neutral-900" colSpan={3}>{formatCurrency(grand)}</td>
            </tr>
          </tfoot>
        </table>
      </div>
    );
  }

  // ── Edit view ────────────────────────────────────────────────────────────────
  const liveItems = rows.map(toLineItem);
  const { taxable, gst, grand } = calcTotals(liveItems);

  return (
    <div>
      <div className="overflow-x-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]">
        <table className="w-full text-sm">
          <thead>
            <tr className="border-b border-neutral-200">
              <th className="pb-2 text-left font-medium text-neutral-600 w-full">Item</th>
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">Qty</th>
              <th className="pb-2 text-left font-medium text-neutral-600 pl-3 whitespace-nowrap">Unit</th>
              <th className="pb-2 text-left font-medium text-neutral-600 pl-3 whitespace-nowrap">Size</th>
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">Unit Price</th>
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">GST%</th>
              {multiAccount && <th className="pb-2 text-left font-medium text-neutral-600 pl-4 whitespace-nowrap">Account</th>}
              <th className="pb-2 text-right font-medium text-neutral-600 pl-4 whitespace-nowrap">Total</th>
              <th className="pb-2 pl-4 w-8" />
            </tr>
          </thead>
          <tbody className="divide-y divide-neutral-100">
            {rows.map((row, i) => {
              const taxableAmt = (parseFloat(row.quantity) || 0) * (parseFloat(row.unitPrice) || 0);
              const gstR = row.gstRate !== "" && row.gstRate != null ? parseFloat(row.gstRate) : 0.18;
              return (
                <tr key={i}>
                  <td className="py-2 pr-4">
                    <NameCell
                      name={row.name}
                      description={row.description}
                      productId={row.productId}
                      onChange={(name, description, pid, price) => updateNameCell(i, name, description, pid, price)}
                    />
                  </td>
                  <td className="py-2 pl-4">
                    <input
                      type="number" min="0" step="any"
                      value={row.quantity}
                      onChange={(e) => update(i, "quantity", e.target.value)}
                      className="w-20 rounded border border-neutral-200 px-2 py-1.5 text-sm text-right focus:border-primary-500 focus:outline-none"
                    />
                  </td>
                  <td className="py-2 pl-3">
                    <select
                      value={row.unit}
                      onChange={(e) => update(i, "unit", e.target.value)}
                      className="w-32 rounded border border-neutral-200 px-2 py-1.5 text-sm focus:border-primary-500 focus:outline-none"
                    >
                      {UOM_OPTIONS.map((opt) => (
                        <option key={opt.value} value={opt.value}>{opt.label}</option>
                      ))}
                    </select>
                  </td>
                  <td className="py-2 pl-3">
                    <input
                      value={row.size}
                      onChange={(e) => update(i, "size", e.target.value)}
                      className="w-24 rounded border border-neutral-200 px-2 py-1.5 text-sm focus:border-primary-500 focus:outline-none"
                      placeholder="e.g. 10mm"
                    />
                  </td>
                  <td className="py-2 pl-4">
                    <input
                      type="number" min="0" step="any"
                      value={row.unitPrice}
                      onChange={(e) => update(i, "unitPrice", e.target.value)}
                      placeholder="0.00"
                      className="w-28 rounded border border-neutral-200 px-2 py-1.5 text-sm text-right focus:border-primary-500 focus:outline-none"
                    />
                  </td>
                  <td className="py-2 pl-4">
                    <select
                      value={row.gstRate}
                      onChange={(e) => update(i, "gstRate", e.target.value)}
                      className="w-20 rounded border border-neutral-200 px-2 py-1.5 text-sm focus:border-primary-500 focus:outline-none"
                    >
                      <option value="0">0%</option>
                      <option value="0.05">5%</option>
                      <option value="0.12">12%</option>
                      <option value="0.18">18%</option>
                      <option value="0.28">28%</option>
                    </select>
                  </td>
                  {multiAccount && (
                    <td className="py-2 pl-4 min-w-[200px]">
                      <SearchableSelect
                        name={`__account_row_${i}`}
                        value={row.accountId ?? defaultAccountId ?? ""}
                        onChange={(v) => update(i, "accountId", v)}
                        groups={accounts ?? []}
                        placeholder="Select code…"
                        size="compact"
                      />
                    </td>
                  )}
                  <td className="py-2 pl-4 text-right text-sm">
                    {formatCurrency(taxableAmt * (1 + gstR))}
                  </td>
                  <td className="py-2 pl-4">
                    <button
                      type="button"
                      aria-label="Remove line item"
                      onClick={() => remove(i)}
                      disabled={rows.length === 1}
                      className="text-neutral-400 hover:text-danger disabled:opacity-30 transition-colors"
                    >
                      <Trash2 className="h-4 w-4" />
                    </button>
                  </td>
                </tr>
              );
            })}
          </tbody>
          <tfoot>
            <tr className="border-t border-neutral-100">
              <td colSpan={multiAccount ? 7 : 6} className="pt-3 text-right text-sm text-neutral-500">Taxable subtotal</td>
              <td className="pt-3 pl-4 text-right text-sm text-neutral-700" colSpan={2}>{formatCurrency(taxable)}</td>
            </tr>
            <tr>
              <td colSpan={multiAccount ? 7 : 6} className="py-0.5 text-right text-sm text-neutral-500">GST</td>
              <td className="py-0.5 pl-4 text-right text-sm text-neutral-700" colSpan={2}>{formatCurrency(gst)}</td>
            </tr>
            <tr className="border-t border-neutral-200">
              <td colSpan={multiAccount ? 7 : 6} className="pt-2 text-right text-sm font-semibold text-neutral-900">Grand Total</td>
              <td className="pt-2 pl-4 text-right text-sm font-semibold text-neutral-900" colSpan={2}>{formatCurrency(grand)}</td>
            </tr>
          </tfoot>
        </table>
      </div>

      <button
        type="button"
        onClick={add}
        className="mt-3 flex items-center gap-1.5 text-sm text-primary-600 hover:text-primary-700 font-medium"
      >
        <Plus className="h-4 w-4" />
        Add line item
      </button>
    </div>
  );
}
