import { useState } from 'react';
import { useLiveQuery } from 'dexie-react-hooks';
import { useSessionStore } from '@/stores/sessionStore';
import { usePlayerSessionStore } from '@/stores/playerSessionStore';
import { useUiStore } from '@/stores/uiStore';
import { sendChat, sendPrivateHandout, sendSetName } from '@/lib/sync/wsSync';
import { sessionLogRepo } from '@/lib/db/repositories';
import type { SessionLogEntry } from '@/lib/schemas';
import type { RosterEntry } from '@/lib/sync/messages';
import { fileToDataUrl, resizeToMax } from '@/lib/img/resize';
import { Dice5, Mail, MessageSquare } from 'lucide-react';
import { Input, Textarea } from '@/components/ui/Input';
import { Button } from '@/components/ui/Button';
import { Modal } from '@/components/ui/Modal';
import { cn } from '@/lib/cn';

/**
 * Global session panel (docked on desktop, drawer on phones). Everyone sees the
 * session, who's here, the live roll feed, and chat. The GM can whisper specific
 * players and (for them) review the persisted recap (rolls + chat saved to the
 * campaign).
 */
export function SessionSidebar({ open, onClose }: { open: boolean; onClose: () => void }) {
  const role = useSessionStore((s) => s.role);
  const status = useSessionStore((s) => s.status);
  const joinCode = useSessionStore((s) => s.joinCode);
  const intent = useSessionStore((s) => s.joinIntent);
  const roster = useSessionStore((s) => s.roster);
  const guestName = useSessionStore((s) => s.guestName);
  const setGuestName = useSessionStore((s) => s.setGuestName);
  const rolls = usePlayerSessionStore((s) => s.rolls);
  const chat = usePlayerSessionStore((s) => s.chat);
  const activeCampaignId = useUiStore((s) => s.activeCampaignId);

  const isGm = role === 'gm';
  const code = isGm ? joinCode : intent?.joinCode;
  const inSession = role !== 'off' || !!intent;

  const [tab, setTab] = useState<'chat' | 'rolls' | 'recap'>('chat');
  const [nameDraft, setNameDraft] = useState(guestName);
  const commitName = () => { const n = nameDraft.trim(); setGuestName(n); sendSetName(n); };
  const [draft, setDraft] = useState('');
  const [whisperTo, setWhisperTo] = useState(''); // GM: playerId; player: 'gm' to whisper the GM
  const targets = roster.filter((p) => p.playerId !== 'gm');
  const nameOf = (pid: string) => (pid === 'gm' ? 'GM' : roster.find((p) => p.playerId === pid)?.name ?? 'player');

  const recap = useLiveQuery(
    () => (isGm && activeCampaignId ? sessionLogRepo.recent(activeCampaignId, 200) : Promise.resolve([] as SessionLogEntry[])),
    [isGm, activeCampaignId],
    [] as SessionLogEntry[],
  );

  const submit = () => {
    if (!draft.trim()) return;
    sendChat(draft, whisperTo || undefined);
    setDraft('');
  };

  // GM: targeted private share (handout/note/image) to one player
  const [shareTarget, setShareTarget] = useState<RosterEntry | null>(null);
  const [shareTitle, setShareTitle] = useState('');
  const [shareBody, setShareBody] = useState('');
  const [shareImage, setShareImage] = useState<string | undefined>(undefined);
  const openShare = (p: RosterEntry) => { setShareTarget(p); setShareTitle(''); setShareBody(''); setShareImage(undefined); };
  const onShareImage = async (file: File) => setShareImage(await resizeToMax(await fileToDataUrl(file), 1280));
  const sendShare = () => {
    if (!shareTarget) return;
    sendPrivateHandout(shareTarget.playerId, { title: shareTitle.trim() || 'A note', body: shareBody.trim(), ...(shareImage ? { image: shareImage } : {}) });
    setShareTarget(null);
  };

  if (!open) return null;

  return (
    <>
      <div className="fixed inset-0 z-40 bg-black/40 md:hidden print:hidden" onClick={onClose} aria-hidden />
      <aside
        className="fixed right-0 top-0 z-50 flex h-full w-80 max-w-[88vw] flex-col border-l border-line bg-panel shadow-2xl print:hidden md:static md:z-auto md:h-auto md:w-80 md:max-w-none md:shrink-0 md:self-stretch md:shadow-none"
        aria-label="Session panel"
      >
        <div className="flex items-center justify-between border-b border-line p-3">
          <div className="min-w-0">
            <h2 className="font-display font-semibold text-ink">Session</h2>
            {inSession && code && (
              <div className="text-xs text-muted">
                {isGm ? 'Hosting' : 'Joined'} <span className="font-mono text-accent">{code}</span> · <span className={status === 'connected' ? 'text-success' : ''}>{status === 'connected' ? 'live' : status}</span>
              </div>
            )}
          </div>
          <button onClick={onClose} aria-label="Close session panel" className="text-muted hover:text-ink">✕</button>
        </div>

        {!inSession && (
          <p className="p-3 text-sm text-muted">You're not in a live session. Host one (GM) or open a join link to play together.</p>
        )}

        {inSession && !isGm && (
          <div className="border-b border-line p-3">
            <label className="text-xs font-semibold uppercase tracking-wide text-muted">Your name</label>
            <Input value={nameDraft} onChange={(e) => setNameDraft(e.target.value)} onBlur={commitName} onKeyDown={(e) => { if (e.key === 'Enter') commitName(); }} placeholder="What should we call you?" aria-label="Your display name" className="mt-1" />
          </div>
        )}

        {inSession && (
          <div className="border-b border-line p-3">
            <h3 className="mb-1 text-xs font-semibold uppercase tracking-wide text-muted">Who's here ({roster.length})</h3>
            <ul className="flex flex-wrap gap-1">
              {roster.map((p) => (
                <li key={p.playerId} className={cn('flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs', p.playerId === 'gm' ? 'border-accent/50 text-accent' : 'border-line text-ink')}>
                  <span className="h-1.5 w-1.5 rounded-full bg-success" aria-hidden />
                  {p.name}{p.character ? <span className="text-muted"> · {p.character}</span> : null}
                  {isGm && p.playerId !== 'gm' && (
                    <button onClick={() => openShare(p)} title={`Share privately with ${p.name}`} aria-label={`Share with ${p.name}`} className="ml-0.5 text-muted hover:text-info"><Mail size={12} aria-hidden /></button>
                  )}
                </li>
              ))}
            </ul>
          </div>
        )}

        <div className="flex border-b border-line text-sm">
          {(['chat', 'rolls', ...(isGm ? ['recap'] as const : [])] as const).map((t) => (
            <button key={t} onClick={() => setTab(t)} className={cn('flex-1 px-2 py-2 capitalize', tab === t ? 'border-b-2 border-accent text-ink' : 'text-muted hover:text-ink')}>
              {t === 'recap' ? 'Recap' : t}
            </button>
          ))}
        </div>

        <div className="flex-1 overflow-y-auto p-3">
          {tab === 'chat' && (
            chat.length === 0 ? <p className="text-xs text-muted">No messages yet.</p> : (
              <ul className="space-y-1">
                {chat.map((c) => (
                  <li key={c.id} className={cn('text-sm', c.scope === 'whisper' && 'rounded bg-elevated/60 px-1.5 py-0.5 italic')}>
                    <span className="font-semibold text-accent">{c.mine ? (c.to ? `You → ${nameOf(c.to)}` : 'You') : c.from}{c.scope === 'whisper' && !c.mine ? ' (whisper)' : ''}:</span>{' '}
                    <span className="text-ink">{c.body}</span>
                  </li>
                ))}
              </ul>
            )
          )}

          {tab === 'rolls' && (
            rolls.length === 0 ? <p className="text-xs text-muted">No rolls yet.</p> : (
              <ul className="space-y-1">
                {rolls.map((r) => (
                  <li key={r.id} className="flex items-baseline gap-2 rounded-md border border-line bg-surface px-2 py-1 text-xs">
                    <span className="font-semibold text-accent">{r.playerName}</span>
                    <span className="min-w-0 flex-1 truncate text-ink">{r.label || r.expression}</span>
                    <span className="font-display text-sm font-bold text-ink">{r.total}</span>
                  </li>
                ))}
              </ul>
            )
          )}

          {tab === 'recap' && isGm && (
            (recap ?? []).length === 0 ? <p className="text-xs text-muted">No saved session activity yet.</p> : (
              <ul className="space-y-0.5 text-xs">
                {(recap ?? []).map((e) => (
                  <li key={e.id} className="flex gap-2">
                    <span className={e.kind === 'roll' ? 'text-accent' : 'text-muted'} aria-hidden>{e.kind === 'roll' ? <Dice5 size={12} /> : <MessageSquare size={12} />}</span>
                    <span className="text-muted">{e.from}:</span>
                    <span className="min-w-0 flex-1 text-ink">{e.text}</span>
                  </li>
                ))}
              </ul>
            )
          )}
        </div>

        {inSession && tab !== 'recap' && (
          <div className="border-t border-line p-2">
            {isGm ? (
              <select value={whisperTo} onChange={(e) => setWhisperTo(e.target.value)} className="mb-1 w-full rounded-md border border-line bg-surface px-2 py-1 text-xs text-ink" aria-label="Chat recipient">
                <option value="">Everyone (table)</option>
                {targets.map((p) => <option key={p.playerId} value={p.playerId}>Whisper {p.name}</option>)}
              </select>
            ) : (
              <label className="mb-1 flex items-center gap-1 text-xs text-muted">
                <input type="checkbox" checked={whisperTo === 'gm'} onChange={(e) => setWhisperTo(e.target.checked ? 'gm' : '')} /> Whisper the GM
              </label>
            )}
            <div className="flex gap-1">
              <Input value={draft} onChange={(e) => setDraft(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') submit(); }} placeholder={whisperTo ? 'Whisper…' : 'Message the table…'} aria-label="Chat message" className="flex-1" />
              <Button size="sm" variant="primary" onClick={submit} disabled={!draft.trim()}>Send</Button>
            </div>
          </div>
        )}
      </aside>

      {shareTarget && (
        <Modal open onClose={() => setShareTarget(null)} title={`Share privately with ${shareTarget.name}`}
          footer={<>
            <Button variant="ghost" onClick={() => setShareTarget(null)}>Cancel</Button>
            <Button variant="primary" onClick={sendShare}>Send to {shareTarget.name}</Button>
          </>}>
          <div className="space-y-3">
            <Input value={shareTitle} onChange={(e) => setShareTitle(e.target.value)} placeholder="Title (e.g. A scrawled map)" aria-label="Share title" />
            <Textarea value={shareBody} onChange={(e) => setShareBody(e.target.value)} placeholder="Text only this player sees…" rows={4} aria-label="Share text" />
            <div className="flex items-center gap-2">
              {shareImage && <img src={shareImage} alt="" className="h-16 w-16 rounded border border-line object-cover" />}
              <label className="cursor-pointer rounded-md border border-line px-2 py-1 text-xs text-ink hover:border-accent">Image…<input type="file" accept="image/*" className="hidden" aria-label="Share image" onChange={(e) => { const f = e.target.files?.[0]; if (f) void onShareImage(f); e.target.value = ''; }} /></label>
              {shareImage && <Button size="sm" variant="ghost" onClick={() => setShareImage(undefined)}>Remove</Button>}
            </div>
            <p className="text-xs text-muted">Only <span className="text-ink">{shareTarget.name}</span> receives this — a secret map, note, or image (e.g. for a scout who went ahead).</p>
          </div>
        </Modal>
      )}
    </>
  );
}
