'use client';

/**
 * Create / edit a championship: name, room, venue-local date and time, the round plan and the
 * solo-merge preference. The plan travels to the server action as JSON in a hidden field; the
 * server re-validates everything (eventConfigSchema, visible packs, future time).
 */
import { useId, useMemo, useState } from 'react';
import type { RoundKind } from '@pintrush/engine';
import { Button } from '@/components/ui/Button';
import { Checkbox, Field, Input, Select } from '@/components/ui/Field';
import { ArrowRightIcon, XIcon } from '@/components/ui/icons';
import { cn } from '@/lib/cn';
import { fieldError, type ActionResult } from '../action-result';
import { FormMessage, SubmitButton, useActionForm } from '../client';
import { ROUND_KIND_LABELS, ROUND_KINDS } from '../format';
import { defaultLabel, defaultPackFor, estimatePlanMinutes, preferredPackKind, withSegments, type PackChoice, type PlanRowInput } from './plan';

interface Row extends PlanRowInput {
  uid: number;
}

export interface EventFormProps {
  mode: 'create' | 'edit';
  action: (prev: ActionResult, formData: FormData) => Promise<ActionResult>;
  rooms: { id: string; name: string }[];
  packs: PackChoice[];
  defaultPlan: PlanRowInput[];
  initial: { name: string; roomId: string; date: string; time: string; plan: PlanRowInput[]; mergeSolos: boolean };
  timeZoneLabel: string;
  eventId?: string;
  version?: number;
}

let nextUid = 1;
const toRows = (plan: PlanRowInput[]): Row[] => plan.map((p) => ({ ...p, uid: nextUid++ }));

export function EventForm({ mode, action, rooms, packs, defaultPlan, initial, timeZoneLabel, eventId, version }: EventFormProps) {
  const { result, pending, onSubmit } = useActionForm(action);
  const [rows, setRows] = useState<Row[]>(() => toRows(initial.plan));
  const planHeadingId = useId();
  const planJson = useMemo(() => JSON.stringify(rows.map(({ kind, packKey, label }) => ({ kind, packKey, label }))), [rows]);
  const segments = useMemo(() => withSegments(rows), [rows]);
  const minutes = useMemo(() => estimatePlanMinutes(rows), [rows]);
  const packKeys = new Set(packs.map((p) => p.key));

  const update = (uid: number, patch: Partial<PlanRowInput>) =>
    setRows((current) =>
      current.map((row) => {
        if (row.uid !== uid) return row;
        const next = { ...row, ...patch };
        if (patch.kind && patch.kind !== row.kind) {
          // Follow the new kind's defaults unless the host customised them.
          if (row.label === defaultLabel(row.kind)) next.label = defaultLabel(patch.kind);
          const currentPack = packs.find((p) => p.key === row.packKey);
          if (!currentPack || currentPack.kind !== preferredPackKind(patch.kind)) next.packKey = defaultPackFor(patch.kind, packs);
        }
        return next;
      }),
    );
  const move = (index: number, delta: -1 | 1) =>
    setRows((current) => {
      const target = index + delta;
      if (target < 0 || target >= current.length) return current;
      const copy = [...current];
      [copy[index], copy[target]] = [copy[target]!, copy[index]!];
      return copy;
    });
  const add = () =>
    setRows((current) => (current.length >= 30 ? current : [...current, { uid: nextUid++, kind: 'RUSH', packKey: defaultPackFor('RUSH', packs), label: defaultLabel('RUSH') }]));

  return (
    <form onSubmit={onSubmit} className="flex flex-col gap-8">
      {eventId && <input type="hidden" name="eventId" value={eventId} />}
      {version !== undefined && <input type="hidden" name="expectedVersion" value={version} />}
      <input type="hidden" name="plan" value={planJson} />

      <FormMessage result={result} />

      <div className="grid gap-5 md:grid-cols-2">
        <Field label="Show name" required error={fieldError(result, 'name')} className="md:col-span-2">
          <Input name="name" defaultValue={initial.name} placeholder="Friday Night Championship" maxLength={80} required />
        </Field>
        <Field
          label="Room"
          required
          error={fieldError(result, 'roomId')}
          hint={mode === 'edit' ? 'The room can’t be changed after scheduling. Cancel and re-create the show to move it.' : undefined}
        >
          <Select name="roomId" defaultValue={initial.roomId} disabled={mode === 'edit'} required>
            {rooms.map((r) => (
              <option key={r.id} value={r.id}>
                {r.name}
              </option>
            ))}
          </Select>
        </Field>
        <div className="grid grid-cols-2 gap-3">
          <Field label="Date" required error={fieldError(result, 'date')}>
            <Input name="date" type="date" defaultValue={initial.date} required />
          </Field>
          <Field label="Start time" required error={fieldError(result, 'time')} hint={timeZoneLabel}>
            <Input name="time" type="time" defaultValue={initial.time} step={300} required />
          </Field>
        </div>
      </div>

      <section aria-labelledby={planHeadingId} className="flex flex-col gap-4">
        <div className="flex flex-wrap items-end justify-between gap-3">
          <div>
            <h2 id={planHeadingId} className="font-display text-lg font-semibold">
              Round plan
            </h2>
            <p className="mt-1 text-sm text-muted">
              {rows.length} round{rows.length === 1 ? '' : 's'} · about {minutes} minutes of play, plus the lobby (opens 15 minutes before the start). Rounds
              with the same label form one segment.
            </p>
          </div>
          <Button variant="ghost" size="sm" onClick={() => setRows(toRows(defaultPlan))}>
            Reset to the default 50-minute plan
          </Button>
        </div>
        {fieldError(result, 'plan') && (
          <p role="alert" className="text-sm font-medium text-danger-soft">
            {fieldError(result, 'plan')}
          </p>
        )}
        <ol className="flex flex-col gap-3">
          {rows.map((row, i) => {
            const segment = segments[i]?.segment ?? 0;
            const newSegment = i === 0 || segment !== segments[i - 1]?.segment;
            const packMissing = !packKeys.has(row.packKey);
            return (
              <li
                key={row.uid}
                className={cn(
                  'grid gap-3 rounded-2xl border bg-night/40 p-4 md:grid-cols-[2.5rem_1fr_1.4fr_1.2fr_auto] md:items-end',
                  newSegment ? 'border-line-strong/80' : 'border-line/70',
                )}
              >
                <div className="flex items-center gap-2 md:flex-col md:items-start md:gap-0">
                  <span className="num font-display text-lg font-bold text-violet-soft" aria-hidden="true">
                    {i + 1}
                  </span>
                  <span className="text-xs text-subtle md:mt-1">Seg {segment + 1}</span>
                </div>
                <Field label={<span>Round {i + 1} type</span>}>
                  <Select value={row.kind} onChange={(e) => update(row.uid, { kind: e.target.value as RoundKind })}>
                    {ROUND_KINDS.map((k) => (
                      <option key={k} value={k}>
                        {ROUND_KIND_LABELS[k]}
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label={<span>Round {i + 1} pack</span>} error={packMissing ? 'This pack is no longer available' : undefined}>
                  <Select value={row.packKey} onChange={(e) => update(row.uid, { packKey: e.target.value })}>
                    {packMissing && <option value={row.packKey}>{row.packKey} (unavailable)</option>}
                    {packs.map((p) => (
                      <option key={p.key} value={p.key}>
                        {p.name} · {p.kind === 'MUSIC' ? 'music' : 'general'} · {p.questionCount} questions
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label={<span>Round {i + 1} label on TV</span>}>
                  <Input value={row.label} maxLength={40} onChange={(e) => update(row.uid, { label: e.target.value })} required />
                </Field>
                <div className="flex gap-1">
                  <Button variant="ghost" size="sm" onClick={() => move(i, -1)} disabled={i === 0} aria-label={`Move round ${i + 1} up`} className="px-3">
                    <ArrowRightIcon className="-rotate-90" />
                  </Button>
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => move(i, 1)}
                    disabled={i === rows.length - 1}
                    aria-label={`Move round ${i + 1} down`}
                    className="px-3"
                  >
                    <ArrowRightIcon className="rotate-90" />
                  </Button>
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => setRows((current) => current.filter((r) => r.uid !== row.uid))}
                    disabled={rows.length === 1}
                    aria-label={`Remove round ${i + 1}`}
                    className="px-3 hover:text-danger-soft"
                  >
                    <XIcon />
                  </Button>
                </div>
              </li>
            );
          })}
        </ol>
        <div>
          <Button variant="secondary" size="sm" onClick={add} disabled={rows.length >= 30}>
            Add a round
          </Button>
        </div>
        <p className="text-xs text-subtle">
          Final Rush: the top 5 play five questions while everyone else predicts the winner — put it last. Table Wars needs teams to shine.
        </p>
      </section>

      <Checkbox
        name="mergeSolos"
        defaultChecked={initial.mergeSolos}
        label="Rank solo players together with teams"
        description="Off: players without a team (and teams of one) get their own Solo leaderboard and sit out table challenges."
      />

      <div className="flex flex-wrap gap-3 border-t border-line/70 pt-6">
        <SubmitButton size="lg" pending={pending} pendingLabel={mode === 'create' ? 'Scheduling…' : 'Saving…'}>
          {mode === 'create' ? 'Schedule championship' : 'Save changes'}
        </SubmitButton>
      </div>
    </form>
  );
}
