import { useState } from 'react';
import { useNavigate } from '@tanstack/react-router';
import { useLiveQuery } from 'dexie-react-hooks';
import { Check, Lock, RadioTower, X } from 'lucide-react';
import { useSessionStore, type SeatRequest } from '@/stores/sessionStore';
import { hostSession, stopSession, grantSeat } from '@/lib/sync/wsSync';
import { charactersRepo } from '@/lib/db/repositories';
import { cloudUsername } from '@/lib/cloud/client';
import { useActiveCampaign } from '@/features/campaigns/hooks';
import { Button } from '@/components/ui/Button';

/** Header control: GM hosts a live session, shares the code, and approves seats. */
export function SessionControl() {
  const navigate = useNavigate();
  const campaign = useActiveCampaign();
  const role = useSessionStore((s) => s.role);
  const status = useSessionStore((s) => s.status);
  const joinCode = useSessionStore((s) => s.joinCode);
  const seatRequests = useSessionStore((s) => s.seatRequests);
  const [copied, setCopied] = useState(false);
  const [showSeats, setShowSeats] = useState(false);

  if (role === 'player') return null; // players don't host

  if (role === 'off') {
    if (!campaign) return null;
    // Hosting a shared session requires the GM to be signed in to an account.
    if (!cloudUsername()) {
      return (
        <Button size="sm" variant="ghost" title="Sign in to host a shared session" onClick={() => void navigate({ to: '/settings' })}>
          <Lock size={14} aria-hidden /> Sign in to host
        </Button>
      );
    }
    return (
      <Button size="sm" variant="ghost" title="Host a live session for players"
        onClick={() => {
          const pw = window.prompt('Optional player password (leave blank for none):')?.trim();
          hostSession(campaign.id, pw || undefined);
        }}
      ><RadioTower size={14} aria-hidden /> Host</Button>
    );
  }

  const link = joinCode ? `${location.origin}/play?room=${joinCode}` : '';
  return (
    <div className="relative flex items-center gap-1.5 rounded-lg border border-accent/50 bg-accent-glow px-2 py-1 text-xs">
      <RadioTower size={14} className="text-accent-deep" aria-hidden />
      <span className="smallcaps text-[9px] text-muted">{status === 'connected' ? 'Live' : status}</span>
      <button
        data-testid="join-code"
        className="font-mono font-semibold tracking-wider text-accent-deep"
        title="Copy player link"
        onClick={() => { if (link) void navigator.clipboard?.writeText(link).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1200); }); }}
      >{joinCode}{copied ? <><Check size={11} aria-hidden /></> : ''}</button>

      {seatRequests.length > 0 && (
        <button data-testid="seat-requests" className="ml-0.5 grid h-5 min-w-5 place-items-center rounded-full bg-danger px-1 font-mono text-[10px] font-bold text-white"
          title="Pending seat requests" onClick={() => setShowSeats((v) => !v)}>{seatRequests.length}</button>
      )}

      <Button size="sm" variant="ghost" className="h-6 w-6 px-0 text-danger" onClick={() => stopSession()} title="Stop session" aria-label="Stop session"><X size={14} aria-hidden /></Button>

      {showSeats && seatRequests.length > 0 && (
        <div className="paper-grain absolute right-0 top-full z-50 mt-1.5 w-72 rounded-xl border border-line-strong bg-panel p-2 shadow-lg">
          <div className="smallcaps mb-1.5 px-1 text-muted">Seat requests</div>
          <ul className="space-y-2">
            {seatRequests.map((r) => <SeatRequestRow key={r.playerId} req={r} />)}
          </ul>
        </div>
      )}
    </div>
  );
}

function SeatRequestRow({ req }: { req: SeatRequest }) {
  const campaign = useActiveCampaign();
  const character = useLiveQuery(() => charactersRepo.get(req.characterId), [req.characterId]);
  const removeSeatRequest = useSessionStore((s) => s.removeSeatRequest);
  const name = character?.name ?? req.offlineSnapshot?.name ?? 'Unknown character';

  const grant = async (applyOffline: boolean) => {
    let current = await charactersRepo.get(req.characterId);
    if (!current && req.offlineSnapshot && campaign) {
      // A character the player made and pushed — add it to this campaign, then seat them.
      await charactersRepo.insert({ ...req.offlineSnapshot, campaignId: campaign.id });
      current = await charactersRepo.get(req.characterId);
    } else if (applyOffline && req.offlineSnapshot && current) {
      const { id: _id, campaignId: _c, createdAt: _cr, updatedAt: _u, ...rest } = req.offlineSnapshot;
      await charactersRepo.update(req.characterId, rest);
      current = await charactersRepo.get(req.characterId);
    }
    if (current) grantSeat(req.playerId, current);
    else removeSeatRequest(req.playerId);
  };

  return (
    <li className="rounded-lg border border-line bg-surface-2 p-2 text-sm">
      <div className="mb-1.5 text-ink">Player wants <span className="font-display font-semibold text-ink">{name}</span></div>
      <div className="flex flex-wrap gap-1">
        <Button size="sm" variant="primary" onClick={() => void grant(false)}>Grant</Button>
        {req.offlineSnapshot && <Button size="sm" variant="secondary" onClick={() => void grant(true)}>Apply offline & grant</Button>}
        <Button size="sm" variant="ghost" onClick={() => removeSeatRequest(req.playerId)}>Deny</Button>
      </div>
    </li>
  );
}
