import { useQuery } from '@tanstack/react-query'
import { motion, AnimatePresence } from 'framer-motion'
import { ShoppingBasket } from 'lucide-react'
import { useActiveHeapMembers } from '../../hooks/useActiveHeapMembersQuery'
import { useFilterStore } from '../../store/filterStore'
import { photos as photosApi, heaps as heapsApi } from '../../services/api'
import cardBg from '../../assets/card.png'

/** How many thumbnails fan out across the stack at once. The newest is
 *  drawn last (top), older ones fan back-left and back-right. */
const STACK_SIZE = 5

/**
 * Pinned card at the bottom of the LeftSidebar showing the currently
 * active heap. Renders nothing when no heap is active — the parent
 * layout collapses around it cleanly.
 *
 * The card is a fast nav shortcut + a satisfying landing spot for the P
 * pick action: every new pick optimistically updates the
 * ['heap-photo-ids', heapId] cache that the existing pick mutation
 * already maintains, so we just subscribe to the same query and let
 * framer-motion's AnimatePresence handle the entrance/exit animation
 * when ids appear or disappear.
 */
export function ActiveHeapCard() {
  const { activeHeap } = useActiveHeapMembers()
  const navigateToSection = useFilterStore((s) => s.navigateToSection)

  // Subscribes to the same cache key the pick mutation optimistically
  // updates. The data is already fetched (and kept fresh) by
  // useActiveHeapMembers above; this useQuery just gives us a render-
  // dependency on the array contents and stable insertion order.
  const { data: orderedIds = [] } = useQuery<string[]>({
    queryKey: ['heap-photo-ids', activeHeap?.id],
    queryFn: () => heapsApi.photoIds(activeHeap!.id),
    enabled: !!activeHeap,
    staleTime: 30_000,
  })

  if (!activeHeap) return null

  // Show the latest STACK_SIZE photos. The backend returns ids in
  // insertion order so the last one in the array is the most recently
  // picked — that's the one we want at the front of the stack.
  const visible = orderedIds.slice(-STACK_SIZE)
  // We render newest LAST so it draws on top via z-index. Reverse so
  // index 0 is the back card and index N-1 is the front.
  const stack = visible.map((id, i) => ({
    id,
    // Symmetric fan: front card has rotate=0, x=0; cards behind it
    // alternate left/right as you walk back through the stack.
    rotate: stackRotate(i, visible.length),
    x: stackOffsetX(i, visible.length),
    y: stackOffsetY(i, visible.length),
    z: i,
  }))

  return (
    <div className="m-1.5 rounded-md border border-border bg-surface-2 shadow-sm">
      {/* Header — clickable, navigates to the heap section. */}
      <button
        onClick={() =>
          navigateToSection(`heap-${activeHeap.id}`, { heapId: activeHeap.id })
        }
        className="flex w-full items-center gap-1.5 rounded-t-md px-2 py-1.5 text-left hover:bg-surface-offset"
        title={`Open "${activeHeap.name}"`}
      >
        <ShoppingBasket className="h-3.5 w-3.5 flex-shrink-0 text-pick" />
        <span className="min-w-0 flex-1 truncate text-[12px] font-semibold text-text">
          {activeHeap.name}
        </span>
        <span className="flex h-4 min-w-[20px] items-center justify-center rounded bg-surface px-1 text-[10px] font-medium text-text-muted">
          {orderedIds.length}
        </span>
      </button>

      {/* Stack row. Re-keyed on activeHeap.id so switching heaps tears
       *  the animation context down cleanly instead of trying to
       *  crossfade unrelated photos. The desert scene sits behind the
       *  fanned thumbnails — `cover` + `bottom` keeps the dunes anchored
       *  so the cacti frame the photos rather than the (transparent) sky. */}
      <div
        key={activeHeap.id}
        className="relative h-20 overflow-hidden rounded-b-md px-2 pb-2"
        style={{
          backgroundImage: `url(${cardBg})`,
          backgroundSize: 'cover',
          backgroundPosition: 'center bottom',
          backgroundRepeat: 'no-repeat',
          imageRendering: 'pixelated',
          opacity: 0.7,
        }}
      >
        {visible.length === 0 ? (
          <div className="flex h-full items-center justify-center px-2 text-center">
            <span className="rounded bg-black/70 px-2 py-1 text-[11px] font-medium text-white shadow-sm backdrop-blur-sm">
              Select photos with{' '}
              <kbd className="rounded bg-white/20 px-1 font-mono text-[10px] text-white">
                S
              </kbd>{' '}
              to fill the heap
            </span>
          </div>
        ) : (
          <div className="relative h-full">
            <AnimatePresence initial={false}>
              {stack.map((item) => (
                <motion.img
                  key={item.id}
                  src={photosApi.getThumbnailUrl(item.id, 'small')}
                  alt=""
                  initial={{ x: 80, y: 0, scale: 0.6, rotate: 0, opacity: 0 }}
                  animate={{
                    x: item.x,
                    y: item.y,
                    scale: 1,
                    rotate: item.rotate,
                    opacity: 1,
                  }}
                  exit={{ x: -60, scale: 0.6, opacity: 0 }}
                  transition={{ type: 'spring', stiffness: 360, damping: 28 }}
                  style={{
                    zIndex: item.z,
                    position: 'absolute',
                    left: '50%',
                    top: '50%',
                    marginLeft: -26, // half of w-13
                    marginTop: -26,  // half of h-13
                  }}
                  className="h-[52px] w-[52px] rounded object-cover shadow-[0_4px_10px_rgba(0,0,0,0.65),0_2px_4px_rgba(0,0,0,0.5)] ring-1 ring-black/60"
                />
              ))}
            </AnimatePresence>
          </div>
        )}
      </div>
    </div>
  )
}

// ── Stack geometry ───────────────────────────────────────────────────────
//
// `i` is the position in the visible array (0 = oldest, last = newest).
// We want the newest card at center (rotate 0, x 0) and earlier cards
// fanning symmetrically outward — so we score each card by how far it
// is from the front, alternating sign.

const X_STEP = 18  // pixels per fan step
const Y_STEP = 2   // tiny vertical lift so the back cards peek above
const ROTATE_STEP = 6  // degrees per fan step

function stackRotate(i: number, len: number): number {
  // Distance from the front (newest). Front card → 0, then alternating
  // -1, +1, -2, +2 ... to spread cards outward.
  const fromFront = len - 1 - i
  if (fromFront === 0) return 0
  const sign = fromFront % 2 === 1 ? -1 : 1
  const magnitude = Math.ceil(fromFront / 2)
  return sign * magnitude * ROTATE_STEP
}

function stackOffsetX(i: number, len: number): number {
  const fromFront = len - 1 - i
  if (fromFront === 0) return 0
  const sign = fromFront % 2 === 1 ? -1 : 1
  const magnitude = Math.ceil(fromFront / 2)
  return sign * magnitude * X_STEP
}

function stackOffsetY(i: number, len: number): number {
  // Back cards lift up a couple pixels so they're visible above the
  // front card's top edge — gives the stack its sense of depth.
  const fromFront = len - 1 - i
  return fromFront * -Y_STEP
}
