import { useEffect, useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { X, Users, Plus, Loader2, LogOut } from '../../lib/icons'
import { listGroups, createGroup, joinGroup, leaveGroup, setNewQueue, type SyncPlayGroup } from '../../lib/syncplay'
import { useSyncPlay } from '../../stores/syncplay-store'
import { toast } from '../../stores/toast-store'

interface Props {
  open: boolean
  onClose: () => void
  /** The item the host is currently playing - used to seed the group's
   *  queue when they create a party so joiners get pushed the right
   *  item via the server's PlayQueue update. */
  currentItemId: string | null
  currentPositionTicks: number
}

/**
 * Watch-party panel. Slides in from the right, shows the open SyncPlay
 * groups on the server, and lets the user create/join/leave one. Once
 * the user is in a group, PlayerPage starts mirroring pause/play/seek
 * across the group via the SyncPlay REST + WebSocket bridge.
 */
export default function SyncPlayPanel({ open, onClose, currentItemId, currentPositionTicks }: Props) {
  const active = useSyncPlay(s => s.active)
  const setActive = useSyncPlay(s => s.setActive)
  const [groups, setGroups] = useState<SyncPlayGroup[]>([])
  const [loading, setLoading] = useState(false)
  const [busy, setBusy] = useState<string | null>(null)
  const [newName, setNewName] = useState('')

  useEffect(() => {
    if (!open) return
    let cancelled = false
    setLoading(true)
    listGroups()
      .then(g => {
        if (!cancelled) setGroups(g)
      })
      .finally(() => {
        if (!cancelled) setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [open, active])

  async function onCreate() {
    if (!newName.trim() || busy) return
    setBusy('create')
    const name = newName.trim()
    try {
      const created = await createGroup(name)
      if (created) {
        setActive({ groupId: created.groupId, groupName: created.groupName, memberCount: created.participantCount })
        // Seed the group queue so joiners get pushed our item. If there's
        // no playback yet (creating a party from an empty player) the
        // seed is skipped - the host can set it later by starting any
        // item, and the server will broadcast a PlayQueue update.
        if (currentItemId) {
          setNewQueue(currentItemId, currentPositionTicks).catch(() => {})
        }
      }
      toast('Watch party created', 'success')
      setNewName('')
      setGroups(await listGroups())
    } catch {
      toast('Could not create watch party', 'error')
    } finally {
      setBusy(null)
    }
  }

  async function onJoin(g: SyncPlayGroup) {
    if (busy) return
    setBusy(g.groupId)
    try {
      await joinGroup(g.groupId)
      setActive({ groupId: g.groupId, groupName: g.groupName, memberCount: g.participantCount + 1 })
      toast(`Joined ${g.groupName}`, 'success')
    } catch {
      toast('Could not join that party', 'error')
    } finally {
      setBusy(null)
    }
  }

  async function onLeave() {
    setBusy('leave')
    try {
      await leaveGroup()
      setActive(null)
      toast('Left the watch party', 'info')
    } catch {
      toast('Could not leave', 'error')
    } finally {
      setBusy(null)
    }
  }

  return (
    <AnimatePresence>
      {open && (
        <>
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.18 }}
            onClick={onClose}
            className="absolute inset-0 z-30 bg-black/55 backdrop-blur-[2px]"
          />
          <motion.aside
            initial={{ x: '100%' }}
            animate={{ x: 0 }}
            exit={{ x: '100%' }}
            transition={{ duration: 0.32, ease: [0.16, 1, 0.3, 1] }}
            className="absolute right-0 top-0 bottom-0 z-40 w-[420px] max-w-[88vw] bg-[#0c0a08]/96 backdrop-blur-xl border-l border-white/10 flex flex-col shadow-[0_0_60px_rgba(0,0,0,0.6)]"
            role="dialog"
            aria-label="Watch party"
          >
            <header className="shrink-0 px-5 pt-5 pb-3 border-b border-white/8 flex items-center justify-between">
              <h2 className="text-[13px] font-semibold uppercase tracking-[0.14em] text-white/85 inline-flex items-center gap-2">
                <Users size={14} />
                Watch party
              </h2>
              <button
                onClick={onClose}
                className="w-8 h-8 grid place-items-center rounded-full text-white/70 hover:text-white hover:bg-white/10 transition-colors focus-ring"
                aria-label="Close"
              >
                <X size={16} />
              </button>
            </header>

            <div className="flex-1 overflow-y-auto content-scroll px-4 py-4 space-y-4">
              {active ? (
                <section className="rounded-lg bg-accent/8 border border-accent/25 p-3.5">
                  <p className="text-[11px] uppercase tracking-[0.16em] font-semibold text-accent mb-1">
                    In a party
                  </p>
                  <p className="text-[14px] font-semibold text-white tracking-tight">
                    {active.groupName}
                  </p>
                  <p className="text-[11.5px] text-white/65 mt-0.5">
                    {active.memberCount} {active.memberCount === 1 ? 'watcher' : 'watchers'}
                  </p>
                  <button
                    onClick={onLeave}
                    disabled={!!busy}
                    className="mt-3 inline-flex items-center gap-1.5 h-8 px-3 rounded-md text-[11.5px] font-medium bg-white/10 hover:bg-white/15 text-white border border-white/15 transition-colors focus-ring disabled:opacity-50"
                  >
                    <LogOut size={12} stroke={2} />
                    Leave
                  </button>
                </section>
              ) : (
                <section className="rounded-lg bg-elevated/30 border border-border p-3.5">
                  <p className="text-[11px] uppercase tracking-[0.16em] font-semibold text-text-3 mb-2">
                    Start a new party
                  </p>
                  <div className="flex items-center gap-2">
                    <input
                      type="text"
                      value={newName}
                      onChange={e => setNewName(e.target.value)}
                      onKeyDown={e => {
                        if (e.key === 'Enter') {
                          e.preventDefault()
                          onCreate()
                        }
                      }}
                      placeholder="Friday movie night"
                      className="flex-1 h-9 px-3 bg-void/55 rounded-md text-[12.5px] text-text-1 placeholder:text-text-4 border border-border focus:outline-none focus:border-accent/50 focus:ring-2 focus:ring-accent/20 transition-all"
                    />
                    <button
                      onClick={onCreate}
                      disabled={!newName.trim() || !!busy}
                      className="inline-flex items-center gap-1.5 h-9 px-3 rounded-md text-[12px] font-medium bg-accent hover:bg-accent-hover text-void disabled:opacity-40 disabled:cursor-not-allowed transition-colors focus-ring"
                    >
                      {busy === 'create' ? <Loader2 size={13} className="animate-spin" /> : <Plus size={13} stroke={2} />}
                      Create
                    </button>
                  </div>
                </section>
              )}

              <section>
                <p className="text-[11px] uppercase tracking-[0.16em] font-semibold text-text-3 mb-2.5">
                  Open parties
                </p>
                {loading && (
                  <div className="flex items-center gap-2 text-[12px] text-text-3 py-3 px-2">
                    <Loader2 size={13} className="animate-spin" />
                    Looking for parties...
                  </div>
                )}
                {!loading && groups.length === 0 && (
                  <p className="text-[12px] text-text-3 py-3 px-2 leading-snug">
                    No open watch parties. Start one above and tell a friend the group name.
                  </p>
                )}
                {!loading && groups.length > 0 && (
                  <ul className="space-y-1.5">
                    {groups.map(g => {
                      const isActive = active?.groupId === g.groupId
                      return (
                        <li key={g.groupId}>
                          <button
                            onClick={() => !isActive && onJoin(g)}
                            disabled={isActive || !!busy}
                            className={`w-full flex items-center gap-3 p-3 rounded-lg border transition-colors text-left focus-ring ${
                              isActive
                                ? 'bg-accent/10 border-accent/30 cursor-default'
                                : 'bg-elevated/30 border-border hover:border-border-strong hover:bg-elevated/60'
                            }`}
                          >
                            <span className="w-8 h-8 grid place-items-center rounded-md bg-void/55 shrink-0">
                              <Users size={13} className="text-text-3" />
                            </span>
                            <span className="flex-1 min-w-0">
                              <span className="block text-[13px] font-medium text-text-1 truncate tracking-tight">
                                {g.groupName}
                              </span>
                              <span className="block text-[11px] text-text-3 truncate">
                                {g.participantCount} {g.participantCount === 1 ? 'watcher' : 'watchers'}
                              </span>
                            </span>
                            {busy === g.groupId && <Loader2 size={13} className="text-text-3 animate-spin" />}
                          </button>
                        </li>
                      )
                    })}
                  </ul>
                )}
              </section>

              <p className="text-[10.5px] text-text-4 leading-relaxed">
                Pause, resume, and seek will mirror to everyone in the party. The host needs to keep their player open for state to flow.
              </p>
            </div>
          </motion.aside>
        </>
      )}
    </AnimatePresence>
  )
}
