"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { useLocale, useTranslations } from "next-intl";
import { menuItemMatchesSearch } from "@/lib/menu-display";
import { QR_ALL_CATEGORY_ID } from "@/lib/qr-menu-constants";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { MenuItemLabels } from "@/components/menu/menu-item-labels";
import { formatCurrency } from "@/lib/format";
import { resolveMediaUrl } from "@/lib/api/client";
import { ApiClientError } from "@/lib/api/client";
import {
  callWaiter,
  fetchBranchPublicMenu,
  fetchPublicSecurityConfig,
  placeBranchGuestOrder,
  resolveQrCode,
  type PublicSecurityConfig,
  type QrCartLine,
  type QrPublicMenuItem,
  type QrResolve,
} from "@/lib/api/qr-public";
import {
  buildQrThemeCssVars,
  normalizeCafeTheme,
  normalizeMenuTexture,
  qrMenuTextureShellProps,
  resolveQrGuestColors,
  type CafeTheme,
} from "@/lib/cafe-theme";
import { QrFloatingCartBar, QrGuestMenuBody } from "@/components/qr/qr-guest-menu-body";
import { QrMenu3dSheet } from "@/components/qr/qr-menu-3d-sheet";
import { QrTurnstile } from "@/components/qr/qr-turnstile";
import { QrOrderTrack } from "@/components/qr/qr-order-track";
import {
  loadGuestOrders,
  ordersForTable,
  saveGuestOrder,
  type GuestOrderRef,
} from "@/lib/guest-order-storage";
import { cn } from "@/lib/utils";

type Screen = "loading" | "error" | "menu" | "cart" | "success" | "track" | "orders";

type QrGuestMenuProps = {
  code: string;
};

export function QrGuestMenu({ code }: QrGuestMenuProps) {
  const t = useTranslations("qrMenu");
  const locale = useLocale();
  const [screen, setScreen] = useState<Screen>("loading");
  const [error, setError] = useState<string>("");
  const [branch, setBranch] = useState<QrResolve | null>(null);
  const [categories, setCategories] = useState<
    Awaited<ReturnType<typeof fetchBranchPublicMenu>>["categories"]
  >([]);
  const [activeCategory, setActiveCategory] = useState("");
  const [cart, setCart] = useState<QrCartLine[]>([]);
  const [guestName, setGuestName] = useState("");
  const [guestPhone, setGuestPhone] = useState("");
  const [orderNumber, setOrderNumber] = useState("");
  const [activeTrack, setActiveTrack] = useState<{ orderId: string; token: string } | null>(null);
  const [tableOrders, setTableOrders] = useState<GuestOrderRef[]>([]);
  const [submitting, setSubmitting] = useState(false);
  const [menuTheme, setMenuTheme] = useState<CafeTheme | null>(null);
  const [searchQuery, setSearchQuery] = useState("");
  const [view3dItem, setView3dItem] = useState<QrPublicMenuItem | null>(null);
  const [security, setSecurity] = useState<PublicSecurityConfig | null>(null);
  const [captchaToken, setCaptchaToken] = useState<string | null>(null);
  const [callWaiterState, setCallWaiterState] = useState<"idle" | "sending" | "sent" | "cooldown">("idle");

  const themeColors = useMemo(
    () => resolveQrGuestColors(menuTheme, branch?.primaryColor),
    [menuTheme, branch?.primaryColor]
  );
  const primary = themeColors.primary;
  const menuStyle = menuTheme?.menuStyle ?? "cards";

  useEffect(() => {
    let cancelled = false;
    fetchPublicSecurityConfig()
      .then((cfg) => {
        if (!cancelled) setSecurity(cfg);
      })
      .catch(() => {
        /* optional — orders still work when captcha is off */
      });
    return () => {
      cancelled = true;
    };
  }, []);

  useEffect(() => {
    if (!code) return;
    let cancelled = false;

    (async () => {
      try {
        const resolved = await resolveQrCode(code);
        if (cancelled) return;
        if (resolved.isCleaning) {
          setError(t("tableCleaning"));
          setScreen("error");
          return;
        }
        setBranch(resolved);
        const menu = await fetchBranchPublicMenu(resolved.cafeId, resolved.branchId);
        if (cancelled) return;
        const cats = menu.categories ?? [];
        setCategories(cats);
        setMenuTheme(normalizeCafeTheme(menu.theme ?? undefined));
        setActiveCategory(QR_ALL_CATEGORY_ID);
        if (cats.length === 0) {
          setError(t("emptyMenu"));
          setScreen("error");
          return;
        }
        setScreen("menu");
        setError("");
        setTableOrders(ordersForTable(loadGuestOrders(), resolved.cafeId, resolved.tableId));
      } catch (err) {
        if (cancelled) return;
        const message =
          err instanceof ApiClientError
            ? err.code === "NOT_FOUND"
              ? t("tableNotFound")
              : `${t("loadError")} (${err.message})`
            : t("loadError");
        setError(message);
        setScreen("error");
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [code, t]);

  const totalItems = cart.reduce((s, c) => s + c.qty, 0);
  const totalPrice = cart.reduce(
    (s, c) => s + effectiveLinePrice(c.item) * c.qty,
    0
  );

  const allItems = useMemo(
    () => categories.flatMap((c) => c.items ?? []),
    [categories]
  );

  const searchTrimmed = searchQuery.trim();
  const isSearching = searchTrimmed.length > 0;
  const showAllGrouped =
    !isSearching && activeCategory === QR_ALL_CATEGORY_ID;

  const activeItems = useMemo(() => {
    const pool = isSearching
      ? allItems
      : activeCategory === QR_ALL_CATEGORY_ID
        ? allItems
        : categories.find((c) => c.id === activeCategory)?.items ?? [];

    if (!isSearching) return pool;
    return pool.filter((item) => menuItemMatchesSearch(item, searchTrimmed, locale));
  }, [allItems, categories, activeCategory, isSearching, searchTrimmed, locale]);

  const categoryNameById = useMemo(() => {
    const map = new Map<string, string>();
    for (const c of categories) map.set(c.id, c.name);
    return map;
  }, [categories]);

  const addToCart = useCallback((item: QrPublicMenuItem) => {
    setCart((prev) => {
      const idx = prev.findIndex((c) => c.item.id === item.id);
      if (idx >= 0) {
        const next = [...prev];
        next[idx] = { ...next[idx]!, qty: next[idx]!.qty + 1 };
        return next;
      }
      return [...prev, { item, qty: 1 }];
    });
  }, []);

  const removeFromCart = useCallback((itemId: string) => {
    setCart((prev) => {
      const idx = prev.findIndex((c) => c.item.id === itemId);
      if (idx < 0) return prev;
      const next = [...prev];
      if (next[idx]!.qty > 1) {
        next[idx] = { ...next[idx]!, qty: next[idx]!.qty - 1 };
        return next;
      }
      next.splice(idx, 1);
      return next;
    });
  }, []);

  const refreshTableOrders = useCallback(() => {
    if (!branch) return;
    setTableOrders(
      ordersForTable(loadGuestOrders(), branch.cafeId, branch.tableId)
    );
  }, [branch]);

  useEffect(() => {
    if (screen === "orders") refreshTableOrders();
  }, [screen, refreshTableOrders]);

  const handleCallWaiter = useCallback(async () => {
    if (!branch || callWaiterState !== "idle") return;
    setCallWaiterState("sending");
    try {
      await callWaiter(branch.cafeId, branch.tableId);
      setCallWaiterState("sent");
      setTimeout(() => setCallWaiterState("cooldown"), 2500);
      setTimeout(() => setCallWaiterState("idle"), 62_000);
    } catch (err) {
      const code = err instanceof ApiClientError ? err.code : null;
      setCallWaiterState(code === "RATE_LIMITED" ? "cooldown" : "idle");
      if (code !== "RATE_LIMITED") setTimeout(() => setCallWaiterState("idle"), 3000);
    }
  }, [branch, callWaiterState]);

  const captchaRequired =
    !!security?.captchaRequired && !!security.turnstileSiteKey;

  const submitOrder = async () => {
    if (!branch || cart.length === 0) return;
    if (captchaRequired && !captchaToken) {
      setError(t("captchaRequired"));
      return;
    }
    setSubmitting(true);
    setError("");
    try {
      const result = await placeBranchGuestOrder(branch.cafeId, branch.branchId, {
        tableId: branch.tableId,
        guestName: guestName.trim() || null,
        guestPhone: guestPhone.trim() || null,
        captchaToken: captchaToken ?? undefined,
        items: cart.map((c) => ({
          menuItemId: c.item.id,
          quantity: c.qty,
          notes: c.note ?? null,
        })),
      });
      setOrderNumber(result.orderNumber);
      const orderRef: GuestOrderRef = {
        orderId: result.orderId,
        trackingToken: result.trackingToken,
        orderNumber: result.orderNumber,
        createdAt: new Date().toISOString(),
        cafeId: branch.cafeId,
        branchId: branch.branchId,
        tableId: branch.tableId,
      };
      const saved = saveGuestOrder(orderRef);
      setCart([]);
      setCaptchaToken(null);
      if (saved) {
        refreshTableOrders();
      } else {
        setTableOrders((prev) => {
          const filtered = prev.filter((o) => o.orderId !== orderRef.orderId);
          return [orderRef, ...filtered];
        });
      }
      setActiveTrack({ orderId: result.orderId, token: result.trackingToken });
      setScreen("track");
    } catch (err) {
      if (err instanceof ApiClientError) {
        if (err.code === "RATE_LIMITED") setError(t("rateLimited"));
        else if (err.code?.startsWith("CAPTCHA")) setError(t("captchaRequired"));
        else if (err.code === "CAFE_SUSPENDED") setError(t("cafeUnavailable"));
        else setError(err.message || t("orderError"));
      } else {
        setError(t("orderError"));
      }
      setScreen("cart");
    } finally {
      setSubmitting(false);
    }
  };

  if (screen === "loading") {
    return (
      <div
        className="flex min-h-svh flex-col items-center justify-center gap-3 p-6"
        data-qr-guest-menu
        style={buildQrThemeCssVars(themeColors)}
      >
        <div
          className="size-10 animate-spin rounded-full border-[3px] border-t-transparent"
          style={{ borderColor: primary, borderTopColor: "transparent" }}
        />
        <p className="text-sm qr-muted">{t("loading")}</p>
      </div>
    );
  }

  if (screen === "error") {
    return (
      <main
        className="flex min-h-svh flex-col items-center justify-center p-6 text-center"
        data-qr-guest-menu
        style={buildQrThemeCssVars(themeColors)}
      >
        <p className="text-4xl">😕</p>
        <p className="mt-4 font-medium qr-text">{error}</p>
        <p className="mt-2 text-sm qr-muted">{t("scanAgain")}</p>
      </main>
    );
  }

  if (screen === "track" && activeTrack) {
    return (
      <main
        className="mx-auto min-h-svh max-w-md"
        dir="rtl"
        data-qr-guest-menu
        style={buildQrThemeCssVars(themeColors)}
      >
        <QrOrderTrack
          orderId={activeTrack.orderId}
          trackingToken={activeTrack.token}
          primary={primary}
          onBack={() => setScreen("menu")}
        />
        <QrBottomNav
          screen={screen}
          primary={primary}
          onMenu={() => setScreen("menu")}
          onOrders={() => {
            refreshTableOrders();
            setScreen("orders");
          }}
          callWaiterState={callWaiterState}
          onCallWaiter={() => void handleCallWaiter()}
        />
      </main>
    );
  }

  if (screen === "orders" && branch) {
    return (
      <main
        className="mx-auto flex min-h-svh max-w-md flex-col"
        dir="rtl"
        data-qr-guest-menu
        style={buildQrThemeCssVars(themeColors)}
      >
        <div className="flex-1 overflow-auto p-4">
          <h2 className="mb-3 text-lg font-semibold qr-text">{t("myOrders")}</h2>
          {tableOrders.length === 0 ? (
            <p className="text-sm qr-muted">{t("noOrders")}</p>
          ) : (
            <div className="space-y-2">
              {tableOrders.map((o) => (
                <button
                  key={o.orderId}
                  type="button"
                  className="w-full rounded-xl border qr-border qr-surface p-4 text-start transition"
                  style={{ borderColor: `color-mix(in srgb, ${primary} 35%, transparent)` }}
                  onClick={() => {
                    setActiveTrack({ orderId: o.orderId, token: o.trackingToken });
                    setScreen("track");
                  }}
                >
                  <p className="font-medium qr-text">{o.orderNumber}</p>
                  <p className="text-xs qr-muted">
                    {new Date(o.createdAt).toLocaleString("fa-IR")}
                  </p>
                </button>
              ))}
            </div>
          )}
        </div>
        <QrBottomNav
          screen={screen}
          primary={primary}
          onMenu={() => setScreen("menu")}
          onOrders={() => setScreen("orders")}
          callWaiterState={callWaiterState}
          onCallWaiter={() => void handleCallWaiter()}
        />
      </main>
    );
  }

  if (screen === "cart") {
    return (
      <div
        className="mx-auto min-h-svh max-w-md p-4"
        dir="rtl"
        data-qr-guest-menu
        style={buildQrThemeCssVars(themeColors)}
      >
        <header className="mb-4 flex items-center gap-2">
          <Button variant="ghost" size="sm" onClick={() => setScreen("menu")}>
            ←
          </Button>
          <h2 className="text-lg font-semibold qr-text">{t("cartTitle")}</h2>
        </header>
        <div className="rounded-xl border qr-border qr-surface">
          {cart.map((c) => (
            <div
              key={c.item.id}
              className="flex items-center justify-between gap-3 border-b px-3 py-3 last:border-0"
            >
              <div className="min-w-0 flex-1">
                <MenuItemLabels item={c.item} lines={1} primaryClassName="text-sm" />
                <p className="text-sm font-medium" style={{ color: primary }}>
                  {formatCurrency(effectiveLinePrice(c.item), "fa-IR")}
                </p>
              </div>
              <div className="flex items-center gap-2">
                <QtyButton
                  label="−"
                  onClick={() => removeFromCart(c.item.id)}
                  variant="outline"
                  color={primary}
                />
                <span className="min-w-6 text-center font-semibold">{c.qty}</span>
                <QtyButton
                  label="+"
                  onClick={() => addToCart(c.item)}
                  variant="filled"
                  color={primary}
                />
              </div>
            </div>
          ))}
        </div>
        <div className="mt-4 space-y-2">
          <Input
            value={guestName}
            onChange={(e) => setGuestName(e.target.value)}
            placeholder={t("guestName")}
            className="text-end"
          />
          <Input
            value={guestPhone}
            onChange={(e) => setGuestPhone(e.target.value)}
            placeholder={t("guestPhone")}
            inputMode="tel"
            className="text-end"
          />
        </div>
        {captchaRequired && security?.turnstileSiteKey ? (
          <div className="mt-4">
            <QrTurnstile
              siteKey={security.turnstileSiteKey}
              onToken={(token) => {
                setCaptchaToken(token);
                if (error === t("captchaRequired")) setError("");
              }}
              onExpire={() => setCaptchaToken(null)}
            />
          </div>
        ) : null}
        {error ? (
          <p className="mt-3 text-sm text-destructive">{error}</p>
        ) : null}
        <div className="mt-4 rounded-xl border qr-border qr-surface p-4">
          <div className="mb-3 flex justify-between font-semibold">
            <span>{t("subtotal")}</span>
            <span style={{ color: primary }}>
              {formatCurrency(totalPrice, "fa-IR")}
            </span>
          </div>
          <Button
            className="w-full"
            disabled={submitting}
            style={{ backgroundColor: primary }}
            onClick={() => void submitOrder()}
          >
            {submitting ? t("loading") : t("placeOrder")}
          </Button>
        </div>
      </div>
    );
  }

  const menuTexture = normalizeMenuTexture(menuTheme?.menuTexture);
  const textureShell = qrMenuTextureShellProps(menuTexture, themeColors.background);

  return (
    <div
      className="mx-auto flex min-h-svh max-w-md flex-col"
      dir="rtl"
      data-qr-guest-menu
      data-qr-texture={textureShell["data-qr-texture"]}
      style={{
        ...textureShell.style,
        ...buildQrThemeCssVars(themeColors),
      }}
    >
      <header
        className="border-b qr-border px-4 py-5 text-center qr-surface"
      >
        {branch?.logoUrl ? (
          <img
            src={resolveMediaUrl(branch.logoUrl)}
            alt={branch.cafeName}
            className="mx-auto mb-2 size-14 rounded-full object-cover"
          />
        ) : null}
        <h1 className="text-lg font-bold qr-text">{branch?.cafeName}</h1>
        <p className="text-sm qr-muted">{branch?.branchName}</p>
        <p className="mt-1 text-xs qr-muted">
          {branch?.welcomeText} — {t("tableLabel")} {branch?.tableNumber}
        </p>
      </header>

      <div
        className={cn(
          "min-h-0 flex-1 overflow-auto",
          totalItems > 0 ? "pb-[8.5rem]" : "pb-20"
        )}
      >
        <QrGuestMenuBody
          showCartBar={false}
          menuStyle={menuStyle}
          colors={themeColors}
          categories={categories}
          activeCategory={activeCategory}
          onCategoryChange={setActiveCategory}
          activeItems={activeItems}
          showAllGrouped={showAllGrouped}
          searchQuery={searchQuery}
          onSearchChange={setSearchQuery}
          isSearching={isSearching}
          categoryNameById={categoryNameById}
          cart={cart}
          onAdd={addToCart}
          onRemove={removeFromCart}
          onView3d={setView3dItem}
          totalItems={totalItems}
          totalPrice={totalPrice}
          onOpenCart={() => setScreen("cart")}
          labels={{
            emptyCategory: isSearching ? t("searchNoResults") : t("emptyCategory"),
            addToCart: t("addToCart"),
            checkout: t("placeOrder"),
            searchPlaceholder: t("searchPlaceholder"),
            allCategories: t("allCategories"),
            clearSearch: t("clearSearch"),
            view3d: t("view3d"),
          }}
        />
      </div>
      {totalItems > 0 ? (
        <div className="pointer-events-none fixed inset-x-0 bottom-[3.25rem] z-40 mx-auto max-w-md px-3 pb-1">
          <div
            className="pointer-events-auto rounded-2xl p-1 shadow-lg backdrop-blur-sm qr-surface"
            style={{ backgroundColor: `color-mix(in srgb, ${themeColors.surface} 95%, transparent)` }}
          >
            <QrFloatingCartBar
              totalItems={totalItems}
              totalPrice={totalPrice}
              colors={themeColors}
              onOpenCart={() => setScreen("cart")}
              labels={{
                emptyCategory: "",
                addToCart: t("addToCart"),
                checkout: t("placeOrder"),
                searchPlaceholder: "",
                allCategories: "",
                clearSearch: "",
                view3d: "",
              }}
            />
          </div>
        </div>
      ) : null}
      {view3dItem ? (
        <QrMenu3dSheet
          item={view3dItem}
          primary={primary}
          onClose={() => setView3dItem(null)}
          onAdd={() => addToCart(view3dItem)}
          addLabel={t("addToCart")}
        />
      ) : null}
      <QrBottomNav
        screen={screen}
        primary={primary}
        onMenu={() => setScreen("menu")}
        onOrders={() => {
          refreshTableOrders();
          setScreen("orders");
        }}
        callWaiterState={callWaiterState}
        onCallWaiter={() => void handleCallWaiter()}
      />
    </div>
  );
}

function QrBottomNav({
  screen,
  primary,
  onMenu,
  onOrders,
  callWaiterState,
  onCallWaiter,
}: {
  screen: Screen;
  primary: string;
  onMenu: () => void;
  onOrders: () => void;
  callWaiterState: "idle" | "sending" | "sent" | "cooldown";
  onCallWaiter: () => void;
}) {
  const t = useTranslations("qrMenu");

  const callLabel =
    callWaiterState === "sending"
      ? "..."
      : callWaiterState === "sent"
      ? t("callWaiterSent")
      : callWaiterState === "cooldown"
      ? t("callWaiterCooldown")
      : t("callWaiter");

  return (
    <nav className="fixed inset-x-0 bottom-0 z-30 mx-auto flex max-w-md items-stretch border-t qr-border qr-surface">
      <button
        type="button"
        className={cn(
          "flex-1 py-3 text-sm font-medium",
          screen === "menu" || screen === "cart" ? "qr-text" : "qr-muted"
        )}
        style={screen === "menu" || screen === "cart" ? { color: primary } : undefined}
        onClick={onMenu}
      >
        {t("tabMenu")}
      </button>

      {/* Call waiter — centre prominent button */}
      <div className="flex items-center justify-center px-2 py-1.5">
        <button
          type="button"
          onClick={onCallWaiter}
          disabled={callWaiterState !== "idle"}
          className={cn(
            "flex items-center gap-1.5 rounded-full px-4 py-2 text-xs font-semibold transition-all duration-200 shadow-md active:scale-95",
            callWaiterState === "sent"
              ? "bg-emerald-500 text-white"
              : callWaiterState === "cooldown"
              ? "bg-gray-200 text-gray-400 cursor-not-allowed"
              : callWaiterState === "sending"
              ? "opacity-70 cursor-wait text-white"
              : "text-white"
          )}
          style={
            callWaiterState === "idle" || callWaiterState === "sending"
              ? { backgroundColor: primary }
              : undefined
          }
        >
          <span
            className={cn(
              "inline-block transition-transform",
              callWaiterState === "sent" && "animate-bounce"
            )}
          >
            🔔
          </span>
          <span className="max-w-[7rem] truncate">{callLabel}</span>
        </button>
      </div>

      <button
        type="button"
        className={cn(
          "flex-1 py-3 text-sm font-medium",
          screen === "orders" || screen === "track" ? "qr-text" : "qr-muted"
        )}
        style={screen === "orders" || screen === "track" ? { color: primary } : undefined}
        onClick={onOrders}
      >
        {t("tabOrders")}
      </button>
    </nav>
  );
}

function effectiveLinePrice(item: QrPublicMenuItem): number {
  const discount = item.discountPercent > 0 ? item.discountPercent : 0;
  return Math.round(item.price * (1 - discount / 100));
}

function QtyButton({
  label,
  onClick,
  variant,
  color,
}: {
  label: string;
  onClick: () => void;
  variant: "outline" | "filled";
  color: string;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={`flex size-8 items-center justify-center rounded-full text-lg leading-none ${
        variant === "filled" ? "text-white" : ""
      }`}
      style={
        variant === "filled"
          ? { backgroundColor: color }
          : { border: `1.5px solid ${color}`, color }
      }
    >
      {label}
    </button>
  );
}
