"use client";

import { useEffect, useMemo, useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
import * as signalR from "@microsoft/signalr";
import { apiGet, apiPatch, apiPost, ApiClientError } from "@/lib/api/client";
import { printErrorMessage, printReceipt } from "@/lib/api/print";
import { requestPosPayment, posDeviceErrorMessage } from "@/lib/api/pos-device";
import { PosSlipModal } from "@/components/pos/pos-slip-modal";
import type { Customer, Order, Table, TableBoardItem } from "@/lib/api/types";
import { formatCurrency, formatNumber } from "@/lib/format";
import { formatPosOrderLabel } from "@/lib/pos-order-label";
import { formatOrderNumber } from "@/lib/order-number";
import { PosTableBoard } from "@/components/pos/pos-table-board";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { LabeledField } from "@/components/ui/labeled-field";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { useCafeSettings } from "@/lib/hooks/use-cafe-settings";
import { confirmPayLabel } from "@/lib/pos-confirm-pay-label";
import { useConfirm } from "@/components/providers/confirm-provider";

type PaymentRow = {
  method: "Cash" | "Card" | "Credit";
  amount: string;
};

type PosPayPanelProps = {
  cafeId: string;
  numberLocale: string;
  branchId?: string | null;
};

export function PosPayPanel({ cafeId, numberLocale, branchId = null }: PosPayPanelProps) {
  const t = useTranslations("pos");
  const tPrint = useTranslations("print");
  const tDashboard = useTranslations("dashboard");
  const queryClient = useQueryClient();
  const confirmDialog = useConfirm();
  const { data: cafeSettings } = useCafeSettings(cafeId);
  const cafeName = cafeSettings?.name ?? tDashboard("cafeName");
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [selectedTableId, setSelectedTableId] = useState<string | null>(null);
  const [filterTableId, setFilterTableId] = useState<string | null>(null);
  const [search, setSearch] = useState("");
  const [debouncedSearch, setDebouncedSearch] = useState("");
  const [payMessage, setPayMessage] = useState<string | null>(null);
  const [receiptOrder, setReceiptOrder] = useState<Order | null>(null);
  const [lastPaidOrderId, setLastPaidOrderId] = useState<string | null>(null);
  const [paymentRows, setPaymentRows] = useState<PaymentRow[]>([
    { method: "Cash", amount: "" },
  ]);
  const [loyaltyRedeem, setLoyaltyRedeem] = useState(0);

  const apiBase = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:5080";

  useEffect(() => {
    const id = setTimeout(() => setDebouncedSearch(search.trim()), 300);
    return () => clearTimeout(id);
  }, [search]);

  const { data: openOrders = [], isLoading } = useQuery({
    queryKey: ["orders-open", cafeId, debouncedSearch],
    queryFn: () => {
      const qs = debouncedSearch
        ? `?search=${encodeURIComponent(debouncedSearch)}`
        : "";
      return apiGet<Order[]>(`/api/cafes/${cafeId}/orders/open${qs}`);
    },
    enabled: !!cafeId,
    refetchInterval: 15_000,
  });

  const { data: tables = [] } = useQuery({
    queryKey: ["tables", cafeId],
    queryFn: () => apiGet<Table[]>(`/api/cafes/${cafeId}/tables`),
    enabled: !!cafeId,
  });

  const displayedOrders = useMemo(() => {
    if (!filterTableId) return openOrders;
    return openOrders.filter((o) => o.tableId === filterTableId);
  }, [openOrders, filterTableId]);

  useEffect(() => {
    if (!cafeId) return;
    const token =
      typeof window !== "undefined" ? localStorage.getItem("meezi_access_token") : null;
    const connection = new signalR.HubConnectionBuilder()
      .withUrl(`${apiBase}/hubs/kds`, { accessTokenFactory: () => token ?? "" })
      .withAutomaticReconnect()
      .build();
    connection
      .start()
      .then(() => connection.invoke("JoinCafe", cafeId))
      .catch(() => undefined);
    const refresh = () => {
      queryClient.invalidateQueries({ queryKey: ["orders-open", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["tables-board", cafeId] });
    };
    connection.on("TableStatusChanged", refresh);
    connection.on("OrderStatusChanged", refresh);
    return () => {
      void connection.stop();
    };
  }, [cafeId, apiBase, queryClient]);

  const selectOrder = (order: Order, tableId?: string | null) => {
    setSelectedId(order.id);
    setSelectedTableId(tableId ?? order.tableId ?? null);
    setPayMessage(null);
  };

  const handleTableSelect = (table: TableBoardItem, activeOrder: Order | null) => {
    setFilterTableId(table.id);
    setSelectedTableId(table.id);
    if (activeOrder) {
      selectOrder(activeOrder, table.id);
      return;
    }
    setSelectedId(null);
    setPayMessage(t("noOrderOnTable"));
  };

  const selected = openOrders.find((o) => o.id === selectedId) ?? null;

  const remaining = useMemo(() => {
    if (!selected) return 0;
    return Math.max(0, selected.total - (selected.paidAmount ?? 0));
  }, [selected]);

  const { data: payCustomer } = useQuery({
    queryKey: ["customer", cafeId, selected?.customerId],
    queryFn: () =>
      apiGet<Customer>(`/api/cafes/${cafeId}/customers/${selected!.customerId}`),
    enabled: !!cafeId && !!selected?.customerId,
  });

  const maxLoyaltyRedeem = useMemo(() => {
    if (!payCustomer || !selected) return 0;
    const byDue = Math.floor(remaining / 100);
    return Math.min(payCustomer.loyaltyPoints, byDue);
  }, [payCustomer, selected, remaining]);

  const loyaltyDiscount = loyaltyRedeem * 100;
  const effectiveRemaining = Math.max(0, remaining - loyaltyDiscount);

  useEffect(() => {
    setLoyaltyRedeem(0);
  }, [selected?.id]);

  useEffect(() => {
    if (!selected) return;
    setPaymentRows([{ method: "Cash", amount: String(effectiveRemaining) }]);
  }, [selected?.id, selected?.total, selected?.paidAmount, effectiveRemaining]);

  const payOrder = useMutation({
    mutationFn: async (order: Order) => {
      const payments = paymentRows
        .map((row) => ({
          method: row.method,
          amount: parseFloat(row.amount.replace(/,/g, "")) || 0,
        }))
        .filter((p) => p.amount > 0);

      if (payments.length === 0) throw new Error("no payments");

      const cardTotal = payments
        .filter((p) => p.method === "Card")
        .reduce((s, p) => s + p.amount, 0);

      const payBranchId = order.branchId ?? branchId;
      if (cardTotal > 0 && payBranchId) {
        await requestPosPayment(cafeId, payBranchId, order.id, cardTotal);
      }

      return apiPost(`/api/cafes/${cafeId}/orders/${order.id}/payments`, {
        payments,
        loyaltyPointsToRedeem: loyaltyRedeem > 0 ? loyaltyRedeem : undefined,
      });
    },
    onSuccess: async (_data, order) => {
      setPayMessage(t("paySuccess"));
      setLastPaidOrderId(order.id);
      try {
        const paid = await apiGet<Order>(`/api/cafes/${cafeId}/orders/${order!.id}`);
        setReceiptOrder(paid);
      } catch {
        setReceiptOrder(order ?? null);
      }
      setSelectedId(null);
      setSelectedTableId(null);
      setFilterTableId(null);
      setSearch("");
      setPaymentRows([{ method: "Cash", amount: "" }]);
      setLoyaltyRedeem(0);
      queryClient.invalidateQueries({ queryKey: ["orders-open", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["orders-live", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["tables-board", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["reservations", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["customer", cafeId] });
    },
    onError: (err) => {
      if (err instanceof ApiClientError) {
        if (err.code.startsWith("POS_DEVICE")) {
          setPayMessage(posDeviceErrorMessage(err, t));
          return;
        }
        if (err.code === "NO_OPEN_SHIFT") {
          setPayMessage(t("payNeedsOpenShift"));
          return;
        }
        if (err.code === "LOYALTY_NO_CUSTOMER") {
          setPayMessage(t("loyaltyNoCustomer"));
          return;
        }
        if (err.code === "LOYALTY_INSUFFICIENT_POINTS") {
          setPayMessage(t("loyaltyInsufficient"));
          return;
        }
        setPayMessage(err.message || t("payError"));
        return;
      }
      setPayMessage(t("payError"));
    },
  });

  const cancelOrder = useMutation({
    mutationFn: (orderId: string) =>
      apiPatch(`/api/cafes/${cafeId}/orders/${orderId}/status`, {
        status: "Cancelled",
      }),
    onSuccess: () => {
      setPayMessage(t("cancelOrderSuccess"));
      setSelectedId(null);
      setSelectedTableId(null);
      setFilterTableId(null);
      setPaymentRows([{ method: "Cash", amount: "" }]);
      queryClient.invalidateQueries({ queryKey: ["orders-open", cafeId] });
      queryClient.invalidateQueries({ queryKey: ["tables-board", cafeId] });
    },
    onError: (err) => {
      setPayMessage(
        err instanceof ApiClientError ? err.message : t("cancelOrderError")
      );
    },
  });

  const paymentSum = paymentRows.reduce(
    (s, row) => s + (parseFloat(row.amount.replace(/,/g, "")) || 0),
    0
  );
  const canPay =
    selected && paymentSum > 0 && paymentSum <= effectiveRemaining + 0.01;

  const payButtonLabel = confirmPayLabel(paymentRows, t);

  const thermalPrint = useMutation({
    mutationFn: (orderId: string) => printReceipt(cafeId, orderId),
    onSuccess: () => setPayMessage(tPrint("success")),
    onError: (err) => setPayMessage(printErrorMessage(err, tPrint)),
  });

  return (
    <div className="flex h-full min-h-0 w-full gap-4 overflow-hidden">
      <Card className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
        <CardHeader className="shrink-0 space-y-3 pb-2">
          <CardTitle className="text-base">{t("openOrders")}</CardTitle>
          <p className="text-xs text-muted-foreground">{t("payOpenOrdersHint")}</p>

          <PosTableBoard
            cafeId={cafeId}
            numberLocale={numberLocale}
            branchId={branchId}
            mode="pay"
            selectedTableId={selectedTableId}
            selectedOrderId={selectedId}
            onSelectTable={handleTableSelect}
          />

          <LabeledField label={t("selectTable")} htmlFor="pay-table-filter">
            <select
              id="pay-table-filter"
              className="h-9 w-full rounded-md border border-input bg-background px-3 text-sm"
              value={filterTableId ?? ""}
              onChange={(e) => {
                const id = e.target.value || null;
                setFilterTableId(id);
                setSelectedTableId(id);
                if (!id) {
                  setSelectedId(null);
                  setPayMessage(null);
                  return;
                }
                void (async () => {
                  try {
                    const order = await apiGet<Order>(
                      `/api/cafes/${cafeId}/tables/${id}/active-order`
                    );
                    selectOrder(order, id);
                  } catch {
                    const match = openOrders.find((o) => o.tableId === id);
                    if (match) selectOrder(match, id);
                    else {
                      setSelectedId(null);
                      setPayMessage(t("noOrderOnTable"));
                    }
                  }
                })();
              }}
            >
              <option value="">{t("allTables")}</option>
              {tables?.map((tbl) => (
                <option key={tbl.id} value={tbl.id}>
                  {t("table")} {tbl.number}
                </option>
              ))}
            </select>
          </LabeledField>

          <div className="space-y-1">
            <p className="text-xs font-medium text-muted-foreground">
              {t("payPickByName")}
            </p>
            <Input
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder={t("searchOpenOrder")}
              className="h-9"
            />
          </div>
        </CardHeader>
        <CardContent className="min-h-0 flex-1 overflow-y-auto overscroll-contain p-4 pt-0">
          {payMessage && !selected ? (
            <p className="mb-2 text-center text-sm text-amber-700">{payMessage}</p>
          ) : null}
          {isLoading ? (
            <p className="text-sm text-muted-foreground">...</p>
          ) : displayedOrders.length === 0 ? (
            <p className="text-sm text-muted-foreground">
              {filterTableId ? t("noOpenOrdersOnTable") : t("noOpenOrders")}
            </p>
          ) : (
            <ul className="space-y-2">
              {displayedOrders.map((order) => {
                const label = formatPosOrderLabel(order, t("table"));
                const isSelected = selectedId === order.id;
                const guestLine =
                  order.guestName?.trim() ||
                  order.customerName?.trim() ||
                  order.guestPhone ||
                  order.customerPhone;
                return (
                  <li key={order.id}>
                    <button
                      type="button"
                      onClick={() => selectOrder(order)}
                      className={cn(
                        "flex w-full flex-col gap-1 rounded-lg border border-border bg-card px-4 py-3 text-start shadow-sm transition hover:border-primary",
                        isSelected && "border-primary ring-1 ring-primary/30"
                      )}
                    >
                      <div className="flex w-full items-center justify-between gap-3">
                        <div className="min-w-0">
                          <p className="truncate text-sm font-semibold">{label}</p>
                          {guestLine ? (
                            <p className="truncate text-xs text-[#0C447C]">
                              {guestLine}
                            </p>
                          ) : null}
                          <p className="text-xs text-muted-foreground">
                            {formatNumber(order.items.length, numberLocale)}{" "}
                            {t("itemsCount")} · {formatOrderNumber(order)}
                          </p>
                        </div>
                        <span className="shrink-0 text-sm font-bold text-primary">
                          {formatCurrency(order.total, numberLocale)}
                        </span>
                      </div>
                    </button>
                  </li>
                );
              })}
            </ul>
          )}
        </CardContent>
      </Card>

      <Card className="flex h-full min-h-0 w-[min(100%,20rem)] shrink-0 flex-col overflow-hidden sm:w-72 lg:w-80">
        <CardHeader className="shrink-0 space-y-2 pb-2">
          <CardTitle className="text-lg">{t("payOrder")}</CardTitle>
          {selected ? (
            <div className="rounded-lg border border-[#0F6E56]/30 bg-[#E1F5EE] px-3 py-2">
              <p className="text-xs text-muted-foreground">{t("payFor")}</p>
              <p className="text-base font-semibold text-[#0F6E56]">
                {formatPosOrderLabel(selected, t("table"))}
              </p>
            </div>
          ) : (
            <p className="text-sm text-muted-foreground">{t("selectOrderToPay")}</p>
          )}
        </CardHeader>
        <CardContent className="flex min-h-0 flex-1 flex-col gap-2 overflow-hidden pt-2">
          {selected ? (
            <>
              <div className="min-h-0 flex-1 space-y-1.5 overflow-y-auto overscroll-contain">
                {selected.items.map((line) => (
                  <div
                    key={line.id}
                    className="flex justify-between gap-2 rounded-md border border-border/60 px-2 py-1.5 text-sm"
                  >
                    <span className="min-w-0 truncate">
                      {line.menuItemName} × {formatNumber(line.quantity, numberLocale)}
                    </span>
                    <span className="shrink-0 tabular-nums">
                      {formatCurrency(line.unitPrice * line.quantity, numberLocale)}
                    </span>
                  </div>
                ))}
              </div>
              <div className="shrink-0 space-y-2 border-t border-border pt-2">
                <div className="flex justify-between text-sm">
                  <span>{t("subtotal")}</span>
                  <span>{formatCurrency(selected.subtotal, numberLocale)}</span>
                </div>
                {selected.discountAmount > 0 ? (
                  <div className="flex justify-between text-sm text-[#0F6E56]">
                    <span>{t("discount")}</span>
                    <span>-{formatCurrency(selected.discountAmount, numberLocale)}</span>
                  </div>
                ) : null}
                <div className="flex justify-between text-sm">
                  <span>{t("tax")}</span>
                  <span>{formatCurrency(selected.taxTotal, numberLocale)}</span>
                </div>
                <div className="flex justify-between text-base font-bold">
                  <span>{t("total")}</span>
                  <span>{formatCurrency(selected.total, numberLocale)}</span>
                </div>
                {(selected.paidAmount ?? 0) > 0 ? (
                  <div className="flex justify-between text-sm text-muted-foreground">
                    <span>{t("paidSoFar")}</span>
                    <span>{formatCurrency(selected.paidAmount, numberLocale)}</span>
                  </div>
                ) : null}
                <div className="flex justify-between text-sm font-semibold text-primary">
                  <span>{t("remaining")}</span>
                  <span>{formatCurrency(effectiveRemaining, numberLocale)}</span>
                </div>
                {loyaltyDiscount > 0 ? (
                  <div className="flex justify-between text-sm text-[#0F6E56]">
                    <span>{t("loyaltyRedeemApplied")}</span>
                    <span>-{formatCurrency(loyaltyDiscount, numberLocale)}</span>
                  </div>
                ) : null}

                {selected.customerId && payCustomer ? (
                  <div className="space-y-2 rounded-lg border border-[#0F6E56]/25 bg-[#E1F5EE]/50 p-2">
                    <p className="text-xs font-medium text-[#0F6E56]">
                      {t("loyaltyBalance", {
                        points: formatNumber(payCustomer.loyaltyPoints, numberLocale),
                      })}
                    </p>
                    <div className="flex flex-wrap items-center gap-2">
                      <Input
                        type="number"
                        min={0}
                        max={maxLoyaltyRedeem}
                        value={loyaltyRedeem || ""}
                        onChange={(e) => {
                          const n = Math.min(
                            maxLoyaltyRedeem,
                            Math.max(0, parseInt(e.target.value, 10) || 0)
                          );
                          setLoyaltyRedeem(n);
                        }}
                        className="h-8 w-24 tabular-nums"
                        disabled={maxLoyaltyRedeem === 0}
                      />
                      <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        className="h-8 text-xs"
                        disabled={maxLoyaltyRedeem === 0}
                        onClick={() => setLoyaltyRedeem(maxLoyaltyRedeem)}
                      >
                        {t("loyaltyUseMax")}
                      </Button>
                    </div>
                    <p className="text-[10px] text-muted-foreground">{t("loyaltyRedeemHint")}</p>
                  </div>
                ) : null}

                <div className="space-y-2 pt-1">
                  <p className="text-xs font-medium text-muted-foreground">
                    {t("splitPayments")}
                  </p>
                  {paymentRows.map((row, idx) => (
                    <div key={idx} className="flex gap-2">
                      <select
                        className="h-9 rounded-md border border-input bg-background px-2 text-sm"
                        value={row.method}
                        onChange={(e) => {
                          const method = e.target.value as PaymentRow["method"];
                          setPaymentRows((rows) =>
                            rows.map((r, i) => (i === idx ? { ...r, method } : r))
                          );
                        }}
                      >
                        <option value="Cash">{t("cash")}</option>
                        <option value="Card">{t("card")}</option>
                        <option value="Credit">{t("credit")}</option>
                      </select>
                      <Input
                        dir="ltr"
                        className="h-9 flex-1 text-end tabular-nums"
                        value={row.amount}
                        onChange={(e) => {
                          const amount = e.target.value;
                          setPaymentRows((rows) =>
                            rows.map((r, i) => (i === idx ? { ...r, amount } : r))
                          );
                        }}
                        placeholder="0"
                      />
                      {paymentRows.length > 1 ? (
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          onClick={() =>
                            setPaymentRows((rows) => rows.filter((_, i) => i !== idx))
                          }
                        >
                          ×
                        </Button>
                      ) : null}
                    </div>
                  ))}
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    className="w-full"
                    onClick={() =>
                      setPaymentRows((rows) => [
                        ...rows,
                        { method: "Card", amount: "" },
                      ])
                    }
                  >
                    {t("addPaymentRow")}
                  </Button>
                </div>

                {payMessage ? (
                  <p className="text-center text-sm text-primary">{payMessage}</p>
                ) : null}
                {lastPaidOrderId ? (
                  <Button
                    type="button"
                    variant="outline"
                    className="w-full"
                    disabled={thermalPrint.isPending}
                    onClick={() => thermalPrint.mutate(lastPaidOrderId)}
                  >
                    {thermalPrint.isPending ? "..." : tPrint("printReceipt")}
                  </Button>
                ) : null}
                <Button
                  type="button"
                  variant="outline"
                  className="w-full"
                  onClick={() => setReceiptOrder(selected)}
                >
                  {t("previewBill")}
                </Button>
                <Button
                  type="button"
                  variant="outline"
                  className="w-full border-[#A32D2D]/40 text-[#A32D2D] hover:bg-red-50"
                  disabled={cancelOrder.isPending}
                  onClick={async () => {
                    if (!selected) return;
                    const ok = await confirmDialog({
                      description: t("cancelOrderConfirm"),
                      variant: "destructive",
                      confirmLabel: t("cancelOrder"),
                    });
                    if (!ok) return;
                    cancelOrder.mutate(selected.id);
                  }}
                >
                  {cancelOrder.isPending ? "..." : t("cancelOrder")}
                </Button>
                <form
                  className="w-full"
                  onSubmit={(e) => {
                    e.preventDefault();
                    if (canPay && selected && !payOrder.isPending) {
                      payOrder.mutate(selected);
                    }
                  }}
                >
                  <Button
                    type="submit"
                    className="w-full"
                    disabled={!canPay || payOrder.isPending}
                  >
                    {payOrder.isPending ? "..." : payButtonLabel}
                  </Button>
                </form>
              </div>
            </>
          ) : null}
        </CardContent>
      </Card>

      {receiptOrder ? (
        <PosSlipModal
          variant="bill"
          order={receiptOrder}
          cafeName={cafeName}
          logoUrl={cafeSettings?.logoUrl}
          tagline={
            [cafeSettings?.address, cafeSettings?.phone]
              .filter(Boolean)
              .join(" • ") || undefined
          }
          onClose={() => setReceiptOrder(null)}
        />
      ) : null}
    </div>
  );
}
