"use client";

import { useCallback, useEffect, useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
import * as signalR from "@microsoft/signalr";
import { Plus, QrCode, Pencil, Video, Trash2, Copy, ExternalLink } from "lucide-react";
import { notify } from "@/lib/notify";
import { MediaPairUpload } from "@/components/media/media-pair-upload";
import { PageHeader } from "@/components/layout/page-header";
import {
  apiGet,
  apiGetBlob,
  apiPatch,
  apiPost,
  ApiClientError,
  openBlobInNewTab,
  resolveMediaUrl,
} from "@/lib/api/client";
import {
  createBranchTable,
  deleteBranchTable,
  fetchCafeTableBoard,
  patchBranchTable,
  setTableCleaning,
} from "@/lib/api/branch-tables";
import { useBranchStore } from "@/lib/stores/branch.store";
import type { TableBoardItem } from "@/lib/api/types";
import { useAuthStore } from "@/lib/stores/auth.store";
import { formatCurrency, formatNumber } from "@/lib/format";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { LabeledField } from "@/components/ui/labeled-field";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";
import { useConfirm } from "@/components/providers/confirm-provider";
import { Alert } from "@/components/ui/alert";

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

export function TablesScreen() {
  const t = useTranslations("tables");
  const tCommon = useTranslations("common");
  const cafeId = useAuthStore((s) => s.user?.cafeId);
  const role = useAuthStore((s) => s.user?.role);
  const branchId = useBranchStore((s) => s.branchId);
  const queryClient = useQueryClient();
  const confirmDialog = useConfirm();
  const [actionMessage, setActionMessage] = useState<string | null>(null);
  const [showForm, setShowForm] = useState(false);
  const [number, setNumber] = useState("");
  const [capacity, setCapacity] = useState("4");
  const [floor, setFloor] = useState("");
  const [editingId, setEditingId] = useState<string | null>(null);
  const [editNumber, setEditNumber] = useState("");
  const [editCapacity, setEditCapacity] = useState("");
  const [editFloor, setEditFloor] = useState("");
  const [editImageUrl, setEditImageUrl] = useState("");
  const [editVideoUrl, setEditVideoUrl] = useState("");

  const apiBase = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:5080";
  const canManage = role === "Owner" || role === "Manager";

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

  const refresh = useCallback(() => {
    queryClient.invalidateQueries({ queryKey: ["tables-board", 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 createTable = useMutation({
    mutationFn: async () => {
      const cap = parseInt(capacity, 10);
      if (branchId) {
        await createBranchTable(cafeId!, branchId, {
          number,
          capacity: cap,
          floor: floor || null,
        });
        return;
      }
      await apiPost(`/api/cafes/${cafeId}/tables`, {
        number,
        capacity: cap,
        floor: floor || null,
      });
    },
    onSuccess: () => {
      setShowForm(false);
      setNumber("");
      setFloor("");
      setActionMessage(null);
      refresh();
    },
    onError: (err) => {
      setActionMessage(err instanceof ApiClientError ? err.message : t("createError"));
    },
  });

  const setCleaning = useMutation({
    mutationFn: ({
      table,
      isCleaning,
    }: {
      table: TableBoardItem;
      isCleaning: boolean;
    }) => setTableCleaning(cafeId!, table.id, isCleaning, branchId ?? table.branchId),
    onSuccess: () => {
      setActionMessage(null);
      refresh();
    },
    onError: (err) => {
      setActionMessage(err instanceof ApiClientError ? err.message : t("cleaningError"));
    },
  });

  const deleteTable = useMutation({
    mutationFn: (table: TableBoardItem) =>
      deleteBranchTable(cafeId!, table.branchId, table.id),
    onSuccess: () => {
      setActionMessage(null);
      refresh();
    },
    onError: (err) => {
      if (err instanceof ApiClientError && err.code === "TABLE_HAS_OPEN_ORDER") {
        setActionMessage(t("tableHasOpenOrder"));
        return;
      }
      setActionMessage(err instanceof ApiClientError ? err.message : t("deleteError"));
    },
  });

  const patchTable = useMutation({
    mutationFn: ({
      table,
      body,
    }: {
      table: TableBoardItem;
      body: {
        number?: string;
        capacity?: number;
        floor?: string | null;
        imageUrl?: string;
        videoUrl?: string;
        isActive?: boolean;
      };
    }) => {
      if (branchId) {
        return patchBranchTable(cafeId!, branchId, table.id, body);
      }
      return apiPatch(`/api/cafes/${cafeId}/tables/${table.id}`, body);
    },
    onSuccess: () => {
      setEditingId(null);
      setActionMessage(null);
      refresh();
    },
  });

  const startEdit = (table: TableBoardItem) => {
    setEditingId(table.id);
    setEditNumber(table.number);
    setEditCapacity(String(table.capacity));
    setEditFloor(table.floor ?? "");
    setEditImageUrl(table.imageUrl ?? "");
    setEditVideoUrl(table.videoUrl ?? "");
  };

  const mediaField = (url: string) => (url.trim() === "" ? "" : url);

  const openQr = async (tableId: string) => {
    try {
      const blob = await apiGetBlob(`/api/cafes/${cafeId}/tables/${tableId}/qr`);
      openBlobInNewTab(blob);
    } catch {
      /* ignore */
    }
  };

  const copyQrUrl = async (url: string) => {
    try {
      await navigator.clipboard.writeText(url);
      notify.success(t("qrUrlCopied"));
    } catch {
      notify.error(t("qrUrlCopyFailed"));
    }
  };

  if (!cafeId) return null;

  return (
    <div className="space-y-6 bg-[#f5f5f4] min-h-full -m-4 p-4 md:-m-6 md:p-6">
      <PageHeader
        title={t("title")}
        subtitle={t("floorPlan")}
        action={
          canManage ? (
            <Button
              className="bg-[#0F6E56] hover:bg-[#0d5e49]"
              onClick={() => setShowForm((v) => !v)}
            >
              <Plus className="ms-2 h-4 w-4" />
              {t("addTable")}
            </Button>
          ) : undefined
        }
      />

      {showForm && (
        <Card className="rounded-xl border border-border/80 bg-card">
          <CardContent className="grid gap-3 pt-6 sm:grid-cols-3">
            <LabeledField label={t("number")} htmlFor="table-number">
              <Input
                id="table-number"
                value={number}
                onChange={(e) => setNumber(e.target.value)}
              />
            </LabeledField>
            <LabeledField label={t("capacity")} htmlFor="table-capacity">
              <Input
                id="table-capacity"
                type="number"
                value={capacity}
                onChange={(e) => setCapacity(e.target.value)}
                dir="ltr"
                className="text-end"
              />
            </LabeledField>
            <LabeledField label={t("floor")} htmlFor="table-floor">
              <Input
                id="table-floor"
                value={floor}
                onChange={(e) => setFloor(e.target.value)}
              />
            </LabeledField>
            <div className="flex gap-2 sm:col-span-3">
              <Button
                disabled={!number.trim() || createTable.isPending}
                onClick={() => createTable.mutate()}
              >
                {tCommon("save")}
              </Button>
              <Button variant="outline" onClick={() => setShowForm(false)}>
                {tCommon("cancel")}
              </Button>
            </div>
          </CardContent>
        </Card>
      )}

      {editingId && (
        <Card className="rounded-xl border border-[#0F6E56]/30 bg-card">
          <CardContent className="grid gap-3 pt-6 sm:grid-cols-3">
            <p className="text-sm font-medium sm:col-span-3">{t("editTable")}</p>
            <LabeledField label={t("number")} htmlFor="edit-table-number">
              <Input
                id="edit-table-number"
                value={editNumber}
                onChange={(e) => setEditNumber(e.target.value)}
              />
            </LabeledField>
            <LabeledField label={t("capacity")} htmlFor="edit-table-capacity">
              <Input
                id="edit-table-capacity"
                type="number"
                value={editCapacity}
                onChange={(e) => setEditCapacity(e.target.value)}
                dir="ltr"
                className="text-end"
              />
            </LabeledField>
            <LabeledField label={t("floor")} htmlFor="edit-table-floor">
              <Input
                id="edit-table-floor"
                value={editFloor}
                onChange={(e) => setEditFloor(e.target.value)}
              />
            </LabeledField>
            <LabeledField label={t("media")} className="sm:col-span-3">
              <MediaPairUpload
                cafeId={cafeId}
                kind="table"
                imageUrl={editImageUrl}
                videoUrl={editVideoUrl}
                onImageChange={(url) => setEditImageUrl(url ?? "")}
                onVideoChange={(url) => setEditVideoUrl(url ?? "")}
              />
            </LabeledField>
            <div className="flex gap-2 sm:col-span-3">
              <Button
                disabled={!editNumber.trim() || patchTable.isPending}
                onClick={() => {
                  const editing = tables.find((tbl) => tbl.id === editingId);
                  if (!editing) return;
                  patchTable.mutate({
                    table: editing,
                    body: {
                      number: editNumber,
                      capacity: parseInt(editCapacity, 10),
                      floor: editFloor || null,
                      imageUrl: mediaField(editImageUrl),
                      videoUrl: mediaField(editVideoUrl),
                    },
                  });
                }}
              >
                {t("saveTable")}
              </Button>
              <Button variant="outline" onClick={() => setEditingId(null)}>
                {tCommon("cancel")}
              </Button>
            </div>
          </CardContent>
        </Card>
      )}

      {isLoading ? (
        <p className="text-sm text-muted-foreground">{tCommon("loading")}</p>
      ) : tables.length === 0 ? (
        <p className="text-sm text-muted-foreground">
          {branchId ? t("emptyBranch") : t("empty")}
        </p>
      ) : (
        <>
          {actionMessage ? (
            <Alert variant="info" onDismiss={() => setActionMessage(null)}>
              {actionMessage}
            </Alert>
          ) : null}
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
          {tables.map((table) => (
            <Card
              key={table.id}
              className={cn(
                "rounded-xl border border-border/80 bg-card transition-colors hover:border-[#0F6E56]"
              )}
            >
              <CardContent className="space-y-3 pt-6">
                {(table.imageUrl || table.videoUrl) && (
                  <div className="relative aspect-[16/9] overflow-hidden rounded-lg bg-muted">
                    {resolveMediaUrl(table.imageUrl) ? (
                      // eslint-disable-next-line @next/next/no-img-element
                      <img
                        src={resolveMediaUrl(table.imageUrl)!}
                        alt=""
                        className="h-full w-full object-cover"
                      />
                    ) : (
                      <div className="h-full min-h-[80px] bg-muted/50" />
                    )}
                    {table.videoUrl ? (
                      <span className="absolute bottom-2 start-2 flex items-center gap-1 rounded-md bg-black/60 px-2 py-0.5 text-[10px] text-white">
                        <Video className="h-3 w-3" />
                        Video
                      </span>
                    ) : null}
                  </div>
                )}
                <div className="flex items-start justify-between gap-2">
                  <div>
                    <p className="text-base font-medium">
                      {t("tableLabel", { number: table.number })}
                    </p>
                    <p className="text-[11px] text-muted-foreground">
                      {t("meta", {
                        capacity: formatNumber(table.capacity),
                        floor: table.floor ?? "—",
                      })}
                    </p>
                    {!table.isActive ? (
                      <Badge
                        variant="outline"
                        className="mt-1 text-[10px] text-muted-foreground"
                      >
                        {t("inactive")}
                      </Badge>
                    ) : null}
                  </div>
                  <Badge className={cn("border", statusStyles[table.status])}>
                    <span className="me-1 inline-block h-1.5 w-1.5 rounded-full bg-current" />
                    {t(`status.${table.status}`)}
                  </Badge>
                </div>

                {table.currentOrder && table.status === "Busy" && (
                  <p className="text-sm text-[#0F6E56]">
                    {table.currentOrder.guestLabel ?? t("activeOrder")} —{" "}
                    {formatCurrency(table.currentOrder.total)}
                  </p>
                )}
                {table.currentOrder && table.status === "Reserved" && (
                  <p className="text-sm text-[#BA7517]">
                    {table.currentOrder.guestLabel} — {t("reserved")}
                  </p>
                )}

                {table.qrCodeUrl ? (
                  <div className="rounded-lg border border-border/80 bg-muted/20 px-2.5 py-2">
                    <p className="text-[10px] font-medium uppercase tracking-[0.06em] text-muted-foreground">
                      {t("qrMenuUrl")}
                    </p>
                    <a
                      href={table.qrCodeUrl}
                      target="_blank"
                      rel="noopener noreferrer"
                      className="mt-1 block break-all text-xs font-medium text-[#0F6E56] hover:underline"
                      dir="ltr"
                    >
                      {table.qrCodeUrl}
                    </a>
                    <div className="mt-2 flex flex-wrap gap-1.5">
                      <Button size="sm" variant="outline" className="h-7 gap-1 px-2 text-xs" asChild>
                        <a href={table.qrCodeUrl} target="_blank" rel="noopener noreferrer">
                          <ExternalLink className="h-3 w-3" />
                          {t("openQrUrl")}
                        </a>
                      </Button>
                      <Button
                        size="sm"
                        variant="outline"
                        className="h-7 gap-1 px-2 text-xs"
                        type="button"
                        onClick={() => void copyQrUrl(table.qrCodeUrl)}
                      >
                        <Copy className="h-3 w-3" />
                        {t("copyQrUrl")}
                      </Button>
                    </div>
                  </div>
                ) : null}

                <div className="flex flex-wrap gap-2">
                  {canManage ? (
                    <Button size="sm" variant="outline" onClick={() => startEdit(table)}>
                      <Pencil className="ms-1 h-3.5 w-3.5" />
                      {t("edit")}
                    </Button>
                  ) : null}
                  <Button size="sm" variant="outline" onClick={() => openQr(table.id)}>
                    <QrCode className="ms-1 h-3.5 w-3.5" />
                    {t("printQr")}
                  </Button>
                  <Button
                    size="sm"
                    variant="outline"
                    onClick={() =>
                      setCleaning.mutate({
                        table,
                        isCleaning: !(table.isCleaning ?? table.status === "Cleaning"),
                      })
                    }
                  >
                    {(table.isCleaning ?? table.status === "Cleaning")
                      ? t("markReady")
                      : t("markCleaning")}
                  </Button>
                  {canManage ? (
                    <Button
                      size="sm"
                      variant="ghost"
                      className="text-[#A32D2D]"
                      disabled={deleteTable.isPending}
                      onClick={async () => {
                        const ok = await confirmDialog({
                          description: t("deleteTableConfirm"),
                          variant: "destructive",
                          confirmLabel: tCommon("delete"),
                        });
                        if (!ok) return;
                        deleteTable.mutate(table);
                      }}
                    >
                      <Trash2 className="ms-1 h-3.5 w-3.5" />
                      {t("deleteTable")}
                    </Button>
                  ) : null}
                  {canManage && table.isActive ? (
                    <Button
                      size="sm"
                      variant="ghost"
                      className="text-[#A32D2D]"
                      onClick={() =>
                        patchTable.mutate({ table, body: { isActive: false } })
                      }
                    >
                      {t("deactivate")}
                    </Button>
                  ) : canManage && !table.isActive ? (
                    <Button
                      size="sm"
                      variant="outline"
                      onClick={() =>
                        patchTable.mutate({ table, body: { isActive: true } })
                      }
                    >
                      {t("reactivate")}
                    </Button>
                  ) : null}
                </div>
                <p className="text-[11px] text-muted-foreground">{t("reprintHint")}</p>
              </CardContent>
            </Card>
          ))}
        </div>
        </>
      )}
    </div>
  );
}
