'use client';

import type { ReactNode } from 'react';
import type { PrivateState, PublicState } from '@pintrush/engine';
import { LogoMark } from '@/components/brand/Logo';
import { AlertIcon, CheckIcon, HourglassIcon, InfoIcon, MenuIcon, TrophyIcon, WifiIcon, XIcon } from '@/components/ui/icons';
import { cn } from '@/lib/cn';
import type { ConnectionStatus } from '@/lib/game';
import { formatPoints, ordinal } from '@/lib/play/format';
import { useBump } from '@/lib/play/hooks';
import type { ChampionshipStage } from '@/lib/play/screen';
import type { Notice } from './usePlayController';

/** Scrollable middle of a screen. */
export function ScreenBody({ children, className, center = false }: { children: ReactNode; className?: string; center?: boolean }) {
  return (
    <div
      className={cn(
        'min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 pt-4 pb-6',
        // Children never shrink when the column overflows a short phone (badges and truncating pills
        // would squash into ovals); the column scrolls instead.
        center && 'flex flex-col items-center justify-center text-center [&>*]:shrink-0',
        className,
      )}
    >
      {children}
    </div>
  );
}

/** Bottom-anchored action area in the thumb zone; clears the iPhone home indicator. */
export function ActionDock({ children, className }: { children: ReactNode; className?: string }) {
  return (
    <div
      className={cn(
        'relative z-10 shrink-0 border-t border-line/70 bg-night/90 px-4 pt-3 pb-[max(0.875rem,env(safe-area-inset-bottom))] backdrop-blur-md',
        className,
      )}
    >
      {children}
    </div>
  );
}

/** Small uppercase label used above headings on every screen. */
export function Eyebrow({
  children,
  tone = 'cyan',
  className,
}: {
  children: ReactNode;
  tone?: 'cyan' | 'amber' | 'lime' | 'violet' | 'muted';
  className?: string;
}) {
  const color = { cyan: 'text-cyan-soft', amber: 'text-amber-soft', lime: 'text-lime-soft', violet: 'text-violet-soft', muted: 'text-subtle' }[tone];
  return <p className={cn('text-xs font-bold tracking-[0.18em] uppercase', color, className)}>{children}</p>;
}

export function roundContext(pub: PublicState | null, fallback: string): string {
  const round = pub?.round;
  if (!round) return pub?.status === 'WAITING' ? 'Championship lobby' : fallback;
  const q = pub.question;
  if (q) return `${round.label} · Q${q.index + 1}/${round.questionCount}`;
  if (round.phase === 'INTRO') return `${round.label} · Get ready`;
  if (round.phase === 'ROUND_OVER') return `${round.label} · Results`;
  return round.label;
}

export function TopBar({
  pub,
  me,
  fallback,
  onMenu,
  menuDisabled,
}: {
  pub: PublicState | null;
  me: PrivateState | null;
  /** Shown when there is no round (venue or event name). */
  fallback: string;
  onMenu: () => void;
  menuDisabled?: boolean;
}) {
  const points = me?.totals.points ?? null;
  const rank = me?.totals.rank ?? null;
  const bump = useBump(points);
  return (
    <header className="glass relative z-20 flex h-14 shrink-0 items-center gap-2.5 border-b border-line/60 pr-1.5 pl-3">
      <LogoMark className="size-8 shrink-0" />
      <div className="min-w-0 flex-1 leading-tight">
        <p className="truncate text-[0.6875rem] font-bold tracking-[0.14em] text-cyan-soft uppercase">{roundContext(pub, fallback)}</p>
        <p className="truncate text-sm font-semibold">
          {me ? me.nickname : fallback}
          {me?.teamName && <span className="font-normal text-muted"> · {me.teamName}</span>}
        </p>
      </div>
      {me?.isFinalist && (
        <span className="inline-flex shrink-0 items-center gap-1 rounded-full bg-amber px-2 py-0.5 text-[0.6875rem] font-extrabold tracking-[0.08em] text-on-bright uppercase">
          <TrophyIcon className="size-3.5" /> Finalist
        </span>
      )}
      {points !== null && (
        <p className="shrink-0 text-right leading-none">
          <span className="sr-only">Score </span>
          <span
            key={bump}
            className={cn(
              'num inline-block rounded-full border border-line-strong/60 bg-raised px-3 py-1.5 font-display text-base font-bold',
              bump > 0 && 'motion-safe:animate-score-bump',
            )}
          >
            {formatPoints(points)}
          </span>
          {rank !== null && <span className="sr-only">{` points, ranked ${ordinal(rank)}`}</span>}
        </p>
      )}
      <button
        type="button"
        onClick={onMenu}
        disabled={menuDisabled}
        aria-haspopup="dialog"
        aria-label="Open game menu: leaderboard, teams, your board, power-ups and scoring"
        className="grid size-12 shrink-0 place-items-center rounded-xl text-fg hover:bg-white/[0.06] disabled:opacity-40"
      >
        <MenuIcon className="size-6" />
      </button>
    </header>
  );
}

/** Non-blocking strip for flaky Wi-Fi; the game keeps rendering the last known state underneath. */
export function ConnectionBanner({ status, onRetry }: { status: ConnectionStatus; onRetry: () => void }) {
  if (status !== 'reconnecting' && status !== 'offline') return null;
  const offline = status === 'offline';
  return (
    <div
      role="status"
      className={cn(
        'relative z-20 flex min-h-11 shrink-0 items-center gap-2.5 px-4 py-1.5 text-sm font-semibold',
        offline ? 'bg-danger/20 text-danger-soft' : 'bg-amber/15 text-amber-soft',
      )}
    >
      <WifiIcon className={cn('size-5 shrink-0', !offline && 'motion-safe:animate-glow-pulse')} />
      <span className="flex-1">{offline ? 'Connection lost.' : 'Reconnecting… your answers are safe.'}</span>
      {offline && (
        <button
          type="button"
          onClick={onRetry}
          className="min-h-12 min-w-12 shrink-0 rounded-lg border border-danger/50 px-3 font-bold text-fg hover:bg-danger/20"
        >
          Retry
        </button>
      )}
    </div>
  );
}

/**
 * "Lobby open: <name>" / "<name> is live" strip while this phone finishes its always-on round. Only
 * the name truncates, so the words that explain the Join button always stay visible on narrow phones.
 */
export function ChampionshipBanner({
  name,
  stage,
  joining,
  onJoin,
}: {
  name: string | null;
  stage: ChampionshipStage;
  joining: boolean;
  onJoin: () => void;
}) {
  const title = name ?? 'The Championship';
  return (
    <div className="relative z-20 flex shrink-0 items-center gap-3 border-b border-amber/40 bg-[linear-gradient(90deg,rgb(255_176_32/0.22),rgb(182_242_58/0.12))] px-4 py-2">
      <TrophyIcon className="size-6 shrink-0 text-amber" />
      <p className="min-w-0 flex-1 text-sm leading-tight">
        <span className="flex min-w-0 font-bold text-amber-soft">
          {stage === 'lobby' ? (
            <>
              <span className="shrink-0">Lobby open:&nbsp;</span>
              <span className="truncate">{title}</span>
            </>
          ) : (
            <>
              <span className="truncate">{title}</span>
              <span className="shrink-0">&nbsp;is live</span>
            </>
          )}
        </span>
        <span className="block text-xs text-muted">
          {stage === 'lobby' ? 'Join now, or after this round.' : 'Finish your round or jump in now.'}
        </span>
      </p>
      <button
        type="button"
        onClick={onJoin}
        disabled={joining}
        className="min-h-12 shrink-0 rounded-xl bg-amber px-4 font-display text-sm font-bold text-on-bright shadow-glow-amber disabled:opacity-60"
      >
        {joining ? 'Joining…' : 'Join'}
      </button>
    </div>
  );
}

export function PausedOverlay() {
  return (
    // Announced by the LiveAnnouncer ("Game paused…"), so no live role here to avoid a double read.
    <div className="glass absolute inset-0 z-30 flex flex-col items-center justify-center gap-4 px-8 text-center">
      <span className="grid size-20 shrink-0 place-items-center rounded-3xl border border-cyan/50 bg-cyan/10 text-cyan shadow-glow-cyan">
        <HourglassIcon className="size-10" />
      </span>
      <h2 className="font-display text-3xl font-bold">Game paused</h2>
      <p className="max-w-xs text-muted">Hang tight — the host will resume shortly. Your score and board are safe.</p>
    </div>
  );
}

/**
 * Transient message (errors, confirmations), pinned to the top of the game area so it never covers
 * the answer buttons in the thumb zone. Announced via its role.
 */
export function NoticeToast({ notice, onDismiss }: { notice: Notice | null; onDismiss: () => void }) {
  if (!notice) return null;
  const Icon = notice.tone === 'error' ? AlertIcon : notice.tone === 'success' ? CheckIcon : InfoIcon;
  return (
    <div className="pointer-events-none absolute inset-x-3 top-3 z-40 flex justify-center">
      <div
        key={notice.id}
        role={notice.tone === 'error' ? 'alert' : 'status'}
        className={cn(
          'pointer-events-auto flex w-full max-w-md items-start gap-2.5 rounded-2xl border px-4 py-3 text-sm font-semibold shadow-lift motion-safe:animate-rise',
          notice.tone === 'error' && 'border-danger/60 bg-[#2a0f1f] text-danger-soft',
          notice.tone === 'success' && 'border-lime/50 bg-[#17240c] text-lime-soft',
          notice.tone === 'info' && 'border-cyan/50 bg-[#0b2232] text-cyan-soft',
        )}
      >
        <Icon className="mt-0.5 size-4 shrink-0" />
        <span className="flex-1 text-fg">{notice.text}</span>
        <button
          type="button"
          onClick={onDismiss}
          aria-label="Dismiss"
          className="-m-3 grid size-12 shrink-0 place-items-center rounded-lg text-muted hover:text-fg"
        >
          <XIcon className="size-4" />
        </button>
      </div>
    </div>
  );
}

/**
 * One-tap "Was that round fair?" strip, docked under the screen after a round (never over it, never
 * blocking the game). After a vote it says thanks; the parent removes it.
 */
export function FairnessPrompt({
  thanked,
  onVote,
  onDismiss,
}: {
  thanked: boolean;
  onVote: (fair: boolean) => void;
  onDismiss: () => void;
}) {
  return (
    <section
      aria-label="Round feedback"
      className="relative z-10 shrink-0 border-t border-line/70 bg-night/90 px-4 pt-2 pb-[max(0.5rem,env(safe-area-inset-bottom))] backdrop-blur-md motion-safe:animate-rise"
    >
      {thanked ? (
        <p role="status" className="flex min-h-12 items-center justify-center gap-2 text-sm font-semibold text-lime-soft">
          <CheckIcon className="size-4 shrink-0" /> Thanks for the feedback!
        </p>
      ) : (
        <div className="flex items-center gap-2">
          <p className="min-w-0 flex-1 text-sm leading-tight font-semibold">Was that round fair?</p>
          <div role="group" aria-label="Was that round fair?" className="flex shrink-0 gap-2">
            <button
              type="button"
              onClick={() => onVote(true)}
              className="min-h-12 min-w-14 rounded-xl border-2 border-lime/60 bg-lime/10 px-3 font-semibold text-lime-soft hover:bg-lime/20"
            >
              Yes
            </button>
            <button
              type="button"
              onClick={() => onVote(false)}
              className="min-h-12 min-w-14 rounded-xl border-2 border-line-strong bg-surface/80 px-3 font-semibold text-fg hover:bg-white/[0.06]"
            >
              No
            </button>
          </div>
          <button
            type="button"
            onClick={onDismiss}
            aria-label="Dismiss the fairness question"
            className="-mr-2 grid size-12 shrink-0 place-items-center rounded-lg text-muted hover:text-fg"
          >
            <XIcon className="size-4" />
          </button>
        </div>
      )}
    </section>
  );
}

/** Polite screen-reader announcements for phase changes and results. */
export function LiveAnnouncer({ message }: { message: string }) {
  return (
    <p className="sr-only" aria-live="polite" aria-atomic="true">
      {message}
    </p>
  );
}
