"use client";

import { useCallback, useMemo, useState } from "react";
import type { AxiosError } from "axios";
import { useCartStore } from "@/store/cartStore";
import { useAuthStore } from "@/store/authStore";
import { lockSeatApi, type Seat } from "@/api/client";

// ─── Grouping ─────────────────────────────────────────────────────────────────

/**
 * Groups seats into sector → row → sorted seats[].
 * Sectors are sorted VIP-first, then alphabetically.
 */
function groupSeats(seats: Seat[]): Map<string, Map<number, Seat[]>> {
  const result = new Map<string, Map<number, Seat[]>>();

  for (const seat of seats) {
    if (!result.has(seat.sector)) result.set(seat.sector, new Map());
    const rowMap = result.get(seat.sector)!;
    if (!rowMap.has(seat.row)) rowMap.set(seat.row, []);
    rowMap.get(seat.row)!.push(seat);
  }

  return new Map(
    Array.from(result.entries()).sort(([a], [b]) => {
      if (a === "VIP") return -1;
      if (b === "VIP") return 1;
      return a.localeCompare(b, "ru");
    })
  );
}

// ─── Component ────────────────────────────────────────────────────────────────

interface SeatMapProps {
  seats: Seat[];
}

export default function SeatMap({ seats }: SeatMapProps) {
  const { seats: cartSeats, addSeat, removeSeat } = useCartStore();

  const selectedIds = useMemo(
    () => new Set(cartSeats.map((s) => s.seatId)),
    [cartSeats]
  );

  // Seats marked unavailable locally after a 409 race-condition response
  const [localLocked, setLocalLocked] = useState<Set<number>>(new Set());

  // Prevents concurrent lock requests — only one seat at a time
  const [pendingId, setPendingId] = useState<number | null>(null);

  // Toast
  const [toastMsg, setToastMsg] = useState<string | null>(null);

  function showToast(msg: string) {
    setToastMsg(msg);
    setTimeout(() => setToastMsg(null), 3200);
  }

  const handleSeatClick = useCallback(
    async (seat: Seat) => {
      const isUnavailable = seat.status !== "AVAILABLE" || localLocked.has(seat.id);
      if (isUnavailable || pendingId !== null) return;

      // Deselect: remove from cart without an API call
      if (selectedIds.has(seat.id)) {
        removeSeat(seat.id);
        return;
      }

      const userId = useAuthStore.getState().user?.id ?? 1;
      setPendingId(seat.id);

      try {
        const { ticketId } = await lockSeatApi(seat.id, userId);
        addSeat({
          seatId: seat.id,
          ticketId,
          sector: seat.sector,
          row: seat.row,
          number: seat.number,
          price: seat.price,
        });
      } catch (err) {
        const axiosErr = err as AxiosError;
        setLocalLocked((prev) => {
          const next = new Set(prev);
          next.add(seat.id);
          return next;
        });
        showToast(
          axiosErr.response?.status === 409
            ? "Место только что заняли, выберите другое"
            : "Ошибка сети. Попробуйте ещё раз"
        );
      } finally {
        setPendingId(null);
      }
    },
    [localLocked, pendingId, selectedIds, addSeat, removeSeat]
  );

  const grouped = useMemo(() => groupSeats(seats), [seats]);

  // ── Empty state ──
  if (seats.length === 0) {
    return (
      <div className="flex flex-col items-center justify-center py-16 px-6 text-center gap-3">
        <div className="w-14 h-14 rounded-2xl bg-[#1C1C1E] flex items-center justify-center">
          <svg viewBox="0 0 24 24" fill="none" className="w-7 h-7 text-[#8E8E93]">
            <rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" strokeWidth="1.5" />
            <path d="M9 9h6M9 12h6M9 15h4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
          </svg>
        </div>
        <p className="text-[15px] font-semibold text-white">Схема зала пока не сформирована</p>
        <p className="text-[12px] text-[#8E8E93]">Администратор ещё не добавил места для этого события</p>
      </div>
    );
  }

  return (
    <div className="relative space-y-3 px-4 pb-2">

      {/* ── Toast notification ── */}
      <div
        aria-live="polite"
        aria-atomic="true"
        className={`fixed top-14 left-1/2 -translate-x-1/2 z-50 transition-all duration-300 pointer-events-none ${
          toastMsg ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-2"
        }`}
      >
        <div className="flex items-center gap-2 bg-[#1C1C1E] border border-[#E32636]/50 text-white text-[12px] font-medium px-4 py-2 rounded-full shadow-xl whitespace-nowrap">
          <span className="w-2 h-2 rounded-full bg-[#E32636] flex-shrink-0" />
          {toastMsg}
        </div>
      </div>

      {/* ── Sector blocks ── */}
      {Array.from(grouped.entries()).map(([sector, rowMap]) => {
        const sectorSeats = seats.filter((s) => s.sector === sector);
        const availableCount = sectorSeats.filter(
          (s) => s.status === "AVAILABLE" && !localLocked.has(s.id)
        ).length;
        const pricePerSeat = sectorSeats[0]?.price ?? 0;

        return (
          <div key={sector} className="bg-[#1C1C1E] rounded-2xl p-4">

            {/* Sector header */}
            <div className="flex items-center justify-between mb-3">
              <div className="flex items-center gap-2">
                <span className="text-[13px] font-bold text-white uppercase tracking-wider">
                  {sector}
                </span>
                <span className="text-[11px] font-semibold text-[#E32636]">
                  {pricePerSeat.toLocaleString("ru-RU")} ₽
                </span>
              </div>
              <span className="text-[11px] text-[#8E8E93]">
                {availableCount} свободно
              </span>
            </div>

            {/* Rows */}
            <div className="space-y-1.5">
              {Array.from(rowMap.entries())
                .sort(([a], [b]) => a - b)
                .map(([row, rowSeats]) => (
                  <div key={row} className="flex items-center gap-2">

                    {/* Row number label */}
                    <span className="text-[10px] text-[#4B5563] w-5 flex-shrink-0 text-right font-mono select-none">
                      {row}
                    </span>

                    {/* Seat buttons */}
                    <div className="flex gap-1 flex-wrap">
                      {rowSeats
                        .sort((a, b) => a.number - b.number)
                        .map((seat) => {
                          const isSelected  = selectedIds.has(seat.id);
                          const isPending   = pendingId === seat.id;
                          const isUnavailable =
                            seat.status !== "AVAILABLE" || localLocked.has(seat.id);

                          // Build class list
                          let cls =
                            "w-7 h-7 rounded-lg text-[10px] font-bold transition-all select-none ";

                          if (isPending) {
                            cls += "bg-[#4B5563] text-[#94A3B8] animate-pulse cursor-wait";
                          } else if (isSelected) {
                            cls += "bg-[#E32636] text-white scale-110 shadow-md shadow-red-900/40";
                          } else if (isUnavailable) {
                            cls += "bg-[#2C2C2E] text-[#4B5563] opacity-50 cursor-not-allowed";
                          } else {
                            cls +=
                              "bg-[#0891B2] hover:bg-[#0E7490] hover:scale-105 active:scale-95 text-white cursor-pointer";
                          }

                          return (
                            <button
                              key={seat.id}
                              onClick={() => { void handleSeatClick(seat); }}
                              disabled={isUnavailable || (pendingId !== null && !isPending)}
                              aria-label={
                                isUnavailable
                                  ? `Место ${seat.number} — недоступно`
                                  : `${seat.sector} Р${seat.row} М${seat.number} — ${seat.price.toLocaleString("ru-RU")} ₽`
                              }
                              aria-pressed={isSelected}
                              title={`${seat.sector} · Ряд ${seat.row} · Место ${seat.number}${
                                isUnavailable ? " (занято)" : ` — ${seat.price.toLocaleString("ru-RU")} ₽`
                              }`}
                              className={cls}
                            >
                              {seat.number}
                            </button>
                          );
                        })}
                    </div>
                  </div>
                ))}
            </div>
          </div>
        );
      })}

      {/* ── Legend ── */}
      <div className="flex gap-5 flex-wrap px-1 pt-1">
        {[
          { cls: "bg-[#0891B2]",  label: "Свободно" },
          { cls: "bg-[#E32636]",  label: "Выбрано"  },
          { cls: "bg-[#2C2C2E] opacity-50", label: "Занято" },
        ].map(({ cls, label }) => (
          <div key={label} className="flex items-center gap-1.5">
            <span className={`w-3 h-3 rounded ${cls}`} />
            <span className="text-[11px] text-[#8E8E93]">{label}</span>
          </div>
        ))}
      </div>

      {/* Transparent overlay blocking all clicks while a request is in flight */}
      {pendingId !== null && (
        <div className="absolute inset-0 z-10" style={{ cursor: "wait", pointerEvents: "all" }} />
      )}
    </div>
  );
}
