"use client";

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

// ─── Internal rendered seat type (adds SVG coordinates) ──────────────────────

type SeatStatus = "AVAILABLE" | "SOLD" | "LOCKED";
type SeatType = "VIP" | "STD";

interface SeatData {
  id: number;
  x: number;
  y: number;
  row: number;
  number: number;
  sector: string;
  type: SeatType;
  status: SeatStatus;
  price: number;
}

// ─── Layout constants ─────────────────────────────────────────────────────────

const CX = 200;
const CY = 192;
const OCTAGON_R = 58;
const RING_MIN_R = 85;
const RING_MAX_R = 165;

// ─── Map API seats → SVG positions ───────────────────────────────────────────

/**
 * Groups seats by (sector, row) → each group becomes one concentric ring.
 * Rings are sorted VIP-first, then alphabetically by sector, then by row number.
 * Radii are distributed evenly between RING_MIN_R and RING_MAX_R.
 * Seats within a ring are placed at equal angles starting from the top (−π/2).
 */
function computeSeatPositions(apiSeats: SeatResponse[]): SeatData[] {
  // 1. Group by "sector::row"
  const ringsMap = new Map<string, SeatResponse[]>();
  for (const seat of apiSeats) {
    const key = `${seat.sector}::${seat.row}`;
    if (!ringsMap.has(key)) ringsMap.set(key, []);
    ringsMap.get(key)!.push(seat);
  }

  // 2. Sort rings: VIP innermost, then alpha by sector, then by row
  const sortedKeys = Array.from(ringsMap.keys()).sort((a, b) => {
    const [sA, rA] = a.split("::");
    const [sB, rB] = b.split("::");
    if (sA === "VIP" && sB !== "VIP") return -1;
    if (sB === "VIP" && sA !== "VIP") return 1;
    if (sA !== sB) return sA.localeCompare(sB);
    return Number(rA) - Number(rB);
  });

  const numRings = sortedKeys.length;
  const result: SeatData[] = [];

  sortedKeys.forEach((key, ringIdx) => {
    const ringSeats = [...ringsMap.get(key)!].sort((a, b) => a.number - b.number);
    const [sector] = key.split("::");
    const row = Number(key.split("::")[1]);

    // 3. Assign radius (lerp between min and max)
    const radius =
      numRings <= 1
        ? (RING_MIN_R + RING_MAX_R) / 2
        : RING_MIN_R + (ringIdx / (numRings - 1)) * (RING_MAX_R - RING_MIN_R);

    const total = ringSeats.length;

    // 4. Place seats at equal angles, starting from top
    ringSeats.forEach((seat, i) => {
      const angle = (i / total) * 2 * Math.PI - Math.PI / 2;
      result.push({
        id: seat.id,
        x: Math.round((CX + radius * Math.cos(angle)) * 10) / 10,
        y: Math.round((CY + radius * Math.sin(angle)) * 10) / 10,
        row,
        number: seat.number,
        sector,
        type: sector === "VIP" ? "VIP" : "STD",
        status: seat.is_available ? "AVAILABLE" : "SOLD",
        price: seat.price,
      });
    });
  });

  return result;
}

// ─── Octagon polygon points ───────────────────────────────────────────────────

function octagonPoints(cx: number, cy: number, r: number): string {
  return Array.from({ length: 8 }, (_, i) => {
    const a = (i / 8) * 2 * Math.PI + Math.PI / 8;
    return `${cx + r * Math.cos(a)},${cy + r * Math.sin(a)}`;
  }).join(" ");
}

// ─── Seat color helpers ───────────────────────────────────────────────────────

function seatFill(seat: SeatData, effectiveStatus: SeatStatus, isSelected: boolean): string {
  if (isSelected) return "#E32636";
  if (effectiveStatus === "SOLD") return "#2D3748";
  if (effectiveStatus === "LOCKED") return "#D97706";
  return seat.type === "VIP" ? "#8B5CF6" : "#0891B2";
}

function seatStroke(seat: SeatData, effectiveStatus: SeatStatus, isSelected: boolean): string {
  if (isSelected) return "#FF6B7A";
  if (effectiveStatus === "SOLD") return "#4B5563";
  if (effectiveStatus === "LOCKED") return "#F59E0B";
  return seat.type === "VIP" ? "#C084FC" : "#38BDF8";
}

// ─── Props ────────────────────────────────────────────────────────────────────

interface OctagonSeatMapProps {
  /**
   * Seats from the API.
   * `null`  → still loading (shows spinner)
   * `[]`    → no seats yet (shows empty state)
   * array   → renders the seat map
   */
  apiSeats: SeatResponse[] | null;
}

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

export default function OctagonSeatMap({ apiSeats }: OctagonSeatMapProps) {
  const { seats: cartSeats, addSeat, removeSeat } = useCartStore();
  const selectedIds = useMemo(() => new Set(cartSeats.map((s) => s.seatId)), [cartSeats]);

  // Compute SVG positions from API data (memoised, recomputes only when apiSeats changes)
  const seats: SeatData[] = useMemo(
    () => (apiSeats ? computeSeatPositions(apiSeats) : []),
    [apiSeats]
  );

  // Local status overrides: applied after a 409 response to immediately mark a seat LOCKED
  const [localStatuses, setLocalStatuses] = useState<Record<number, SeatStatus>>({});

  // ID of seat currently awaiting API response — prevents multiple concurrent requests
  const [pendingId, setPendingId] = useState<number | null>(null);

  // Toast notification
  const [toastMessage, setToastMessage] = useState("");
  const [toastVisible, setToastVisible] = useState(false);

  const showToast = useCallback((message: string) => {
    setToastMessage(message);
    setToastVisible(true);
    setTimeout(() => setToastVisible(false), 3500);
  }, []);

  const handleSeatClick = useCallback(
    async (seat: SeatData) => {
      const effectiveStatus = localStatuses[seat.id] ?? seat.status;
      if (effectiveStatus !== "AVAILABLE") return;
      if (pendingId !== null) return;

      // Deselect: remove from cart without API call (lock expires via Redis TTL)
      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;

        // Mark seat LOCKED locally so it becomes visually unavailable immediately
        setLocalStatuses((prev) => ({ ...prev, [seat.id]: "LOCKED" }));

        if (axiosErr.response?.status === 409) {
          showToast("Извините, это место только что заняли");
        } else {
          showToast("Ошибка сети. Попробуйте ещё раз");
        }
      } finally {
        setPendingId(null);
      }
    },
    [localStatuses, pendingId, selectedIds, addSeat, removeSeat, showToast]
  );

  // ── Loading state ──
  if (apiSeats === null) {
    return (
      <div className="flex items-center justify-center w-full py-16">
        <div className="flex flex-col items-center gap-3">
          <svg
            className="w-8 h-8 animate-spin text-[#0891B2]"
            viewBox="0 0 24 24"
            fill="none"
          >
            <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
            <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4l3-3-3-3v4a8 8 0 00-8 8h4z" />
          </svg>
          <p className="text-[13px] text-[#8E8E93]">Загрузка схемы зала…</p>
        </div>
      </div>
    );
  }

  // ── Empty state ──
  if (apiSeats.length === 0) {
    return (
      <div className="flex items-center justify-center w-full py-16 px-6">
        <div className="flex flex-col items-center gap-3 text-center">
          <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>
      </div>
    );
  }

  // ── Full seat map ──
  return (
    <div className="relative w-full px-2">
      {/* ── Toast notification ── */}
      <div
        className={`absolute top-1 left-0 right-0 z-10 flex justify-center pointer-events-none transition-all duration-300 ${
          toastVisible ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-1"
        }`}
        aria-live="polite"
        aria-atomic="true"
      >
        <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">
          <span className="w-2 h-2 rounded-full bg-[#E32636] flex-shrink-0" />
          {toastMessage}
        </div>
      </div>

      <svg
        viewBox="0 0 400 384"
        className="w-full"
        aria-label="Схема зала"
        role="img"
        style={{ cursor: pendingId !== null ? "wait" : undefined }}
      >
        <defs>
          <radialGradient id="arena-bg" cx="50%" cy="50%" r="50%">
            <stop offset="0%"   stopColor="#131328" />
            <stop offset="100%" stopColor="#080812" />
          </radialGradient>

          <filter id="glow-red" x="-80%" y="-80%" width="260%" height="260%">
            <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur" />
            <feMerge>
              <feMergeNode in="blur" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>

          <filter id="glow-soft" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur in="SourceGraphic" stdDeviation="1.5" result="blur" />
            <feMerge>
              <feMergeNode in="blur" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>

          <filter id="glow-cage" x="-20%" y="-20%" width="140%" height="140%">
            <feGaussianBlur in="SourceGraphic" stdDeviation="2.5" result="blur" />
            <feMerge>
              <feMergeNode in="blur" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>
        </defs>

        {/* ── Outer arena ellipse ── */}
        <ellipse cx={CX} cy={CY} rx={186} ry={168} fill="url(#arena-bg)" stroke="#1E3A5F" strokeWidth="2" />
        <ellipse cx={CX} cy={CY} rx={186} ry={168} fill="none" stroke="#2DD4BF" strokeWidth="1" opacity="0.35" />

        {/* ── Inner floor area ── */}
        <ellipse cx={CX} cy={CY} rx={146} ry={128} fill="#0B0B1E" stroke="#1E293B" strokeWidth="1" />

        {/* ── Sector divider lines ── */}
        {[0, 90, 180, 270].map((deg) => {
          const rad = (deg * Math.PI) / 180;
          return (
            <line
              key={deg}
              x1={CX + 148 * Math.cos(rad)} y1={CY + 130 * Math.sin(rad)}
              x2={CX + 182 * Math.cos(rad)} y2={CY + 165 * Math.sin(rad)}
              stroke="#1E293B"
              strokeWidth="1"
            />
          );
        })}

        {/* ── Octagon cage ── */}
        <polygon points={octagonPoints(CX, CY, OCTAGON_R)} fill="none" stroke="#38BDF8" strokeWidth="4" opacity="0.25" filter="url(#glow-cage)" />
        <polygon points={octagonPoints(CX, CY, OCTAGON_R)} fill="#05050F" stroke="#38BDF8" strokeWidth="1.5" />

        {/* Cage cross-lines */}
        {[0, 1, 2, 3].map((i) => {
          const a1 = (i / 8) * 2 * Math.PI + Math.PI / 8;
          const a2 = ((i + 4) / 8) * 2 * Math.PI + Math.PI / 8;
          return (
            <line
              key={i}
              x1={CX + (OCTAGON_R - 6) * Math.cos(a1)} y1={CY + (OCTAGON_R - 6) * Math.sin(a1)}
              x2={CX + (OCTAGON_R - 6) * Math.cos(a2)} y2={CY + (OCTAGON_R - 6) * Math.sin(a2)}
              stroke="#1E3A5F" strokeWidth="0.8" opacity="0.5"
            />
          );
        })}

        {/* Stage label */}
        <text x={CX} y={CY + 5} textAnchor="middle" dominantBaseline="middle" fill="#64748B" fontSize="13" fontWeight="600" letterSpacing="1">
          Stage
        </text>

        {/* ── Seat dots ── */}
        {seats.map((seat) => {
          const effectiveStatus = localStatuses[seat.id] ?? seat.status;
          const isSelected = selectedIds.has(seat.id);
          const isPending = pendingId === seat.id;
          const isClickable = effectiveStatus === "AVAILABLE" && !isSelected && pendingId === null;
          const r = seat.type === "VIP" ? 5 : 4.2;

          return (
            <circle
              key={seat.id}
              cx={seat.x}
              cy={seat.y}
              r={r}
              fill={isPending ? "#94A3B8" : seatFill(seat, effectiveStatus, isSelected)}
              stroke={isPending ? "#CBD5E1" : seatStroke(seat, effectiveStatus, isSelected)}
              strokeWidth={isSelected ? 1.5 : isPending ? 1.2 : 0.8}
              opacity={effectiveStatus === "SOLD" ? 0.45 : isPending ? 0.7 : 1}
              cursor={isPending ? "wait" : isClickable || isSelected ? "pointer" : "not-allowed"}
              className={isPending ? "animate-pulse" : undefined}
              filter={
                isSelected
                  ? "url(#glow-red)"
                  : effectiveStatus === "AVAILABLE" && !isPending
                  ? "url(#glow-soft)"
                  : undefined
              }
              onClick={() => { void handleSeatClick(seat); }}
              role={isClickable || isSelected ? "button" : undefined}
              aria-label={
                isClickable
                  ? `${seat.sector} Ряд ${seat.row} Место ${seat.number} — ${seat.price.toLocaleString("ru-RU")} ₽`
                  : undefined
              }
            >
              <title>
                {seat.sector} • Ряд {seat.row} • Место {seat.number}
                {isPending
                  ? " (обработка…)"
                  : effectiveStatus === "SOLD"
                  ? " (Занято)"
                  : effectiveStatus === "LOCKED"
                  ? " (Удержано)"
                  : ` — ${seat.price.toLocaleString("ru-RU")} ₽`}
              </title>
            </circle>
          );
        })}

        {/* Transparent overlay blocking all SVG clicks while a request is in flight */}
        {pendingId !== null && (
          <rect x={0} y={0} width={400} height={384} fill="transparent" cursor="wait" style={{ pointerEvents: "all" }} />
        )}
      </svg>
    </div>
  );
}
