'use client';

/**
 * Roster from HostState.players with moderation: inline rename and remove (kick, with confirmation).
 * The game server re-validates nicknames (length, characters, profanity) and de-duplicates them.
 */
import { useId, useMemo, useState } from 'react';
import type { HostState } from '@pintrush/engine';
import { Badge } from '@/components/ui/Badge';
import { Button } from '@/components/ui/Button';
import { ConfirmDialog } from '../client';
import { formatNumber } from '../format';
import { Notice, StatusBadge, TableWrap, td, th } from '../ui';

type Player = HostState['players'][number];

export type ModerateFn = (player: Player, action: 'rename' | 'kick', nickname?: string) => Promise<{ ok: true; nickname: string } | { ok: false; message: string }>;

export function PlayersTable({ players, onModerate, disabled }: { players: readonly Player[]; onModerate: ModerateFn; disabled: boolean }) {
  const [query, setQuery] = useState('');
  const [showRemoved, setShowRemoved] = useState(false);
  const [editing, setEditing] = useState<string | null>(null);
  const [draft, setDraft] = useState('');
  const [busy, setBusy] = useState<string | null>(null);
  const [kickTarget, setKickTarget] = useState<Player | null>(null);
  const [feedback, setFeedback] = useState<{ tone: 'success' | 'error'; text: string } | null>(null);
  const searchId = useId();

  const visible = useMemo(() => {
    const q = query.trim().toLowerCase();
    return [...players]
      .filter((p) => showRemoved || p.status === 'ACTIVE')
      .filter((p) => !q || p.nickname.toLowerCase().includes(q) || (p.teamName ?? '').toLowerCase().includes(q))
      .sort((a, b) => b.points - a.points || a.nickname.localeCompare(b.nickname));
  }, [players, query, showRemoved]);
  const removedCount = players.filter((p) => p.status !== 'ACTIVE').length;

  async function saveRename(player: Player) {
    const nickname = draft.trim();
    if (!nickname || nickname === player.nickname) {
      setEditing(null);
      return;
    }
    setBusy(player.playerId);
    const res = await onModerate(player, 'rename', nickname);
    setBusy(null);
    if (res.ok) {
      setEditing(null);
      setFeedback({ tone: 'success', text: `Renamed “${player.nickname}” to “${res.nickname}”.` });
    } else setFeedback({ tone: 'error', text: res.message });
  }

  async function confirmKick() {
    if (!kickTarget) return;
    const target = kickTarget;
    setBusy(target.playerId);
    const res = await onModerate(target, 'kick');
    setBusy(null);
    setKickTarget(null);
    setFeedback(res.ok ? { tone: 'success', text: `Removed “${target.nickname}” from the game.` } : { tone: 'error', text: res.message });
  }

  return (
    <div className="flex flex-col gap-4">
      <div className="flex flex-wrap items-center gap-3">
        <label htmlFor={searchId} className="sr-only">
          Search players or teams
        </label>
        <input
          id={searchId}
          type="search"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Search players or teams"
          className="min-h-11 w-full max-w-xs rounded-xl border border-line-strong bg-night/70 px-4 text-sm text-fg placeholder:text-subtle focus-visible:border-cyan"
        />
        {removedCount > 0 && (
          <label className="inline-flex min-h-11 cursor-pointer items-center gap-2 text-sm text-muted">
            <input type="checkbox" checked={showRemoved} onChange={(e) => setShowRemoved(e.target.checked)} className="size-4 accent-violet" />
            Show removed ({removedCount})
          </label>
        )}
      </div>
      <div aria-live="polite">{feedback && <Notice tone={feedback.tone}>{feedback.text}</Notice>}</div>
      {visible.length === 0 ? (
        <p className="text-sm text-muted">{players.length === 0 ? 'No one has joined yet. Point guests at the QR code on the TV.' : 'No players match.'}</p>
      ) : (
        <TableWrap label="Players">
          <thead>
            <tr>
              <th scope="col" className={th}>
                Player
              </th>
              <th scope="col" className={th}>
                Team
              </th>
              <th scope="col" className={`${th} text-right`}>
                Points
              </th>
              <th scope="col" className={`${th} text-right`}>
                Correct / answered
              </th>
              <th scope="col" className={th}>
                Status
              </th>
              <th scope="col" className={th}>
                <span className="sr-only">Moderation</span>
              </th>
            </tr>
          </thead>
          <tbody>
            {visible.map((p) => {
              const isEditing = editing === p.playerId;
              const isBusy = busy === p.playerId;
              return (
                <tr key={p.playerId}>
                  <td className={td}>
                    {isEditing ? (
                      <form
                        className="flex flex-wrap items-center gap-2"
                        onSubmit={(e) => {
                          e.preventDefault();
                          void saveRename(p);
                        }}
                      >
                        <label className="sr-only" htmlFor={`rename-${p.playerId}`}>
                          New nickname for {p.nickname}
                        </label>
                        <input
                          id={`rename-${p.playerId}`}
                          value={draft}
                          onChange={(e) => setDraft(e.target.value)}
                          onKeyDown={(e) => {
                            if (e.key === 'Escape') setEditing(null);
                          }}
                          maxLength={32}
                          autoFocus
                          autoComplete="off"
                          className="min-h-11 w-40 rounded-lg border border-cyan bg-night px-3 text-sm text-fg"
                        />
                        <Button type="submit" size="sm" disabled={isBusy}>
                          {isBusy ? 'Saving…' : 'Save'}
                        </Button>
                        <Button size="sm" variant="ghost" onClick={() => setEditing(null)} disabled={isBusy}>
                          Cancel
                        </Button>
                      </form>
                    ) : (
                      <span className="inline-flex items-center gap-2">
                        <span className="font-semibold">{p.nickname}</span>
                        {p.isBot && <Badge tone="neutral">bot</Badge>}
                      </span>
                    )}
                  </td>
                  <td className={`${td} text-muted`}>{p.teamName ?? '—'}</td>
                  <td className={`${td} num text-right font-semibold`}>{formatNumber(p.points)}</td>
                  <td className={`${td} num text-right text-muted`}>
                    {p.correct} / {p.answered}
                  </td>
                  <td className={td}>
                    <StatusBadge status={p.status === 'ACTIVE' ? 'RUNNING' : p.status} label={p.status === 'ACTIVE' ? 'playing' : p.status === 'KICKED' ? 'removed' : 'left'} />
                  </td>
                  <td className={`${td} text-right whitespace-nowrap`}>
                    {p.status === 'ACTIVE' && !isEditing && (
                      <span className="inline-flex gap-1">
                        <Button
                          size="sm"
                          variant="ghost"
                          disabled={disabled || isBusy}
                          onClick={() => {
                            setEditing(p.playerId);
                            setDraft(p.nickname);
                            setFeedback(null);
                          }}
                        >
                          Rename<span className="sr-only"> {p.nickname}</span>
                        </Button>
                        <Button size="sm" variant="ghost" className="hover:text-danger-soft" disabled={disabled || isBusy} onClick={() => setKickTarget(p)}>
                          Remove<span className="sr-only"> {p.nickname}</span>
                        </Button>
                      </span>
                    )}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </TableWrap>
      )}
      <ConfirmDialog
        open={kickTarget !== null}
        onClose={() => setKickTarget(null)}
        title={kickTarget ? `Remove “${kickTarget.nickname}”?` : 'Remove player?'}
        description="Their phone is disconnected from this game and they drop off the leaderboard. Use this for offensive names or players who are disrupting the show."
        confirmLabel="Remove player"
        busy={kickTarget !== null && busy === kickTarget.playerId}
        onConfirm={() => void confirmKick()}
      />
    </div>
  );
}
