"use client";

import { useCallback, useEffect, useMemo } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
import * as signalR from "@microsoft/signalr";
import { apiGet, apiPatch } from "@/lib/api/client";
import {
  branchTablesPath,
  fetchCafeTableBoard,
  setTableCleaning,
  type TableSectionDto,
} from "@/lib/api/branch-tables";
import type { Order, TableBoardItem } from "@/lib/api/types";
import { formatCurrency } from "@/lib/format";
import { Link } from "@/i18n/routing";
import { cn } from "@/lib/utils";

const statusStyles: Record<TableBoardItem["status"], string> = {
  Free: "bg-[#E1F5EE] text-[#0F6E56] border-[#0F6E56]/40 hover:border-[#0F6E56]",
  Busy: "bg-blue-50 text-[#0C447C] border-blue-300 hover:border-blue-500",
  Reserved: "bg-amber-50 text-[#BA7517] border-amber-300 hover:border-amber-500",
  Cleaning: "bg-slate-100 text-slate-600 border-slate-300 hover:border-slate-500",
};

const selectedTableStyles =
  "border-primary bg-primary/10 text-primary shadow-[0_0_0_2px_hsl(var(--primary)/0.35)] z-[1]";

type PosTableBoardProps = {
  cafeId: string;
  numberLocale: string;
  selectedTableId: string | null;
  selectedOrderId?: string | null;
  branchId: string | null;
  mode?: "order" | "pay";
  onSelectTable: (table: TableBoardItem, activeOrder: Order | null) => void;
};

function groupPosTables(
  tables: TableBoardItem[],
  sections: TableSectionDto[],
  noSectionLabel: string
): { key: string; label: string | null; tables: TableBoardItem[] }[] {
  const groups: { key: string; label: string | null; tables: TableBoardItem[] }[] = [];
  for (const sec of sections) {
    const items = tables.filter((t) => t.sectionId === sec.id);
    if (items.length > 0) {
      groups.push({ key: sec.id, label: sec.name, tables: items });
    }
  }
  const unassigned = tables.filter((t) => !t.sectionId);
  if (unassigned.length > 0) {
    groups.push({ key: "_none", label: noSectionLabel, tables: unassigned });
  }
  if (groups.length === 0 && tables.length > 0) {
    groups.push({ key: "_all", label: null, tables });
  }
  return groups;
}

export function PosTableBoard({
  cafeId,
  numberLocale,
  selectedTableId,
  selectedOrderId = null,
  branchId,
  mode = "order",
  onSelectTable,
}: PosTableBoardProps) {
  const t = useTranslations("pos");
  const tQr = useTranslations("qrMenu");
  const tTables = useTranslations("tables");
  const queryClient = useQueryClient();
  const apiBase = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:5080";

  const {
    data: tables = [],
    isLoading,
    isError,
    refetch,
  } = useQuery({
    queryKey: ["tables-board", cafeId, branchId, "pos"],
    queryFn: () => fetchCafeTableBoard(cafeId, branchId),
    enabled: !!cafeId,
  });

  const { data: sections = [] } = useQuery({
    queryKey: ["table-sections", cafeId, branchId],
    queryFn: () =>
      apiGet<TableSectionDto[]>(
        `${branchTablesPath(cafeId, branchId!)}/sections`
      ),
    enabled: !!cafeId && !!branchId,
    retry: false,
  });

  const grouped = useMemo(
    () => groupPosTables(tables, sections, tTables("noSection")),
    [tables, sections, tTables]
  );

  const refresh = useCallback(() => {
    queryClient.invalidateQueries({ queryKey: ["tables-board", cafeId] });
    queryClient.invalidateQueries({ queryKey: ["orders-open", cafeId] });
  }, [queryClient, cafeId]);

  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);
    connection.on("TableStatusChanged", refresh);
    connection.on("OrderCreated", refresh);
    connection.on("OrderStatusChanged", refresh);
    return () => {
      void connection.stop();
    };
  }, [cafeId, apiBase, refresh]);

  const setCleaning = useMutation({
    mutationFn: ({
      tableId,
      isCleaning,
      tableBranchId,
    }: {
      tableId: string;
      isCleaning: boolean;
      tableBranchId: string;
    }) => setTableCleaning(cafeId, tableId, isCleaning, branchId ?? tableBranchId),
    onSuccess: () => refresh(),
  });

  const handleClick = async (table: TableBoardItem) => {
    if (table.isCleaning ?? table.status === "Cleaning") return;
    if (mode === "pay" && table.status !== "Busy") return;

    let activeOrder: Order | null = null;
    if (table.status === "Busy" && table.currentOrder?.orderId) {
      try {
        activeOrder = await apiGet<Order>(
          `/api/cafes/${cafeId}/orders/${table.currentOrder.orderId}`
        );
      } catch {
        try {
          activeOrder = await apiGet<Order>(
            `/api/cafes/${cafeId}/tables/${table.id}/active-order`
          );
        } catch {
          activeOrder = null;
        }
      }
    }
    onSelectTable(table, activeOrder);
  };

  const statusLabel = (status: TableBoardItem["status"]) => {
    switch (status) {
      case "Free":
        return tTables("status.free");
      case "Busy":
        return tTables("status.occupied");
      case "Reserved":
        return tTables("status.reserved");
      case "Cleaning":
        return tTables("status.cleaning");
    }
  };

  const title =
    mode === "pay" ? t("paySelectTable") : t("selectTableBoard");

  const renderTableButton = (table: TableBoardItem) => {
    const cleaning = table.isCleaning ?? table.status === "Cleaning";
    const isSelected =
      selectedTableId === table.id ||
      (selectedOrderId != null &&
        table.currentOrder?.orderId === selectedOrderId);
    const payDisabled =
      mode === "pay" &&
      (table.status === "Cleaning" || table.status !== "Busy");
    return (
      <div key={table.id} className="flex shrink-0 flex-col gap-1">
        <button
          type="button"
          disabled={cleaning || payDisabled}
          onClick={() => void handleClick(table)}
          className={cn(
            "flex min-w-[4.5rem] flex-col items-center rounded-lg border-2 px-3 py-2 text-center transition",
            isSelected ? selectedTableStyles : statusStyles[table.status],
            (cleaning || payDisabled) &&
              "cursor-not-allowed opacity-60"
          )}
        >
          <span className="text-lg font-bold">{table.number}</span>
          <span className="text-[10px]">{statusLabel(table.status)}</span>
          {table.currentOrder && table.status === "Busy" ? (
            <span className="mt-0.5 max-w-[4rem] truncate text-[10px] tabular-nums">
              {formatCurrency(table.currentOrder.total, numberLocale)}
            </span>
          ) : null}
          {table.currentOrder?.guestLabel && table.status === "Busy" ? (
            <span className="mt-0.5 max-w-[4.5rem] truncate text-[9px] opacity-90">
              {table.currentOrder.guestLabel}
            </span>
          ) : null}
          {table.currentOrder?.source === "GuestQr" && table.status === "Busy" ? (
            <span className="mt-0.5 rounded-full bg-amber-100 px-1.5 py-0.5 text-[9px] font-semibold text-amber-900">
              {tQr("guestQrBadge")}
            </span>
          ) : null}
        </button>
        {mode === "order" ? (
          <button
            type="button"
            className="text-[10px] text-muted-foreground underline-offset-2 hover:underline"
            onClick={(e) => {
              e.stopPropagation();
              setCleaning.mutate({
                tableId: table.id,
                tableBranchId: table.branchId,
                isCleaning: !cleaning,
              });
            }}
          >
            {cleaning
              ? tTables("markReady")
              : tTables("markCleaning")}
          </button>
        ) : null}
      </div>
    );
  };

  return (
    <div className="shrink-0 space-y-2 rounded-lg border border-border/80 bg-muted/20 p-3">
      <p className="text-xs font-medium text-muted-foreground">{title}</p>

      {isLoading ? (
        <p className="text-sm text-muted-foreground">{t("loadingTables")}</p>
      ) : null}

      {isError ? (
        <div className="space-y-2">
          <p className="text-sm text-[#A32D2D]">{t("tablesLoadError")}</p>
          <button
            type="button"
            className="text-xs text-[#0F6E56] underline-offset-2 hover:underline"
            onClick={() => void refetch()}
          >
            {t("retryTables")}
          </button>
        </div>
      ) : null}

      {!isLoading && !isError && tables.length === 0 ? (
        <div className="space-y-2 rounded-md border border-dashed border-[#BA7517]/50 bg-amber-50/50 px-3 py-3">
          <p className="text-sm text-[#BA7517]">{t("noTablesOnBoard")}</p>
          <Link
            href="/tables"
            className="text-xs font-medium text-[#0F6E56] underline-offset-2 hover:underline"
          >
            {t("manageTablesLink")}
          </Link>
        </div>
      ) : null}

      {!isLoading && !isError && tables.length > 0
        ? grouped.map((group) => (
            <div key={group.key} className="space-y-1.5">
              {group.label ? (
                <p className="text-[10px] font-medium uppercase tracking-[0.06em] text-muted-foreground">
                  {group.label}
                </p>
              ) : null}
              <div className="-mx-0.5 flex gap-2 overflow-x-auto px-1 py-1">
                {group.tables.map(renderTableButton)}
              </div>
            </div>
          ))
        : null}
    </div>
  );
}
