'use client';

/**
 * Venue settings: always-on on/off, weekly opening hours (several windows per day allowed; a close
 * time at or before the open time runs past midnight), the always-on question pack and the
 * solo-merge preference. Saved with an optimistic version check.
 */
import { useId, useMemo, useState } from 'react';
import { Button } from '@/components/ui/Button';
import { Checkbox, Field, Select } from '@/components/ui/Field';
import { XIcon } from '@/components/ui/icons';
import { cn } from '@/lib/cn';
import { fieldError, type ActionResult } from '../action-result';
import { FormMessage, SubmitButton, useActionForm } from '../client';
import { WEEKDAYS } from '../format';

export interface Slot {
  day: number;
  open: string;
  close: string;
}

interface Window {
  uid: number;
  open: string;
  close: string;
}

/** Monday first: how bars think about their week. Values stay 0 = Sunday … 6 = Saturday. */
const DISPLAY_ORDER = [1, 2, 3, 4, 5, 6, 0];
let nextUid = 1;

/** <input type="time"> can't show 24:00; 00:00 as a closing time means the same thing (past midnight). */
const toInput = (t: string) => (t === '24:00' ? '00:00' : t);

function toMinutes(t: string): number {
  const [h, m] = t.split(':');
  return Number(h) * 60 + Number(m);
}

export function SettingsForm({
  action,
  version,
  canEdit,
  initial,
  packs,
}: {
  action: (prev: ActionResult, formData: FormData) => Promise<ActionResult>;
  version: number;
  canEdit: boolean;
  initial: { enabled: boolean; packKey: string; mergeSolos: boolean; schedule: Slot[] };
  packs: { key: string; name: string; kind: 'GENERAL' | 'MUSIC'; questionCount: number }[];
}) {
  const { result, pending, onSubmit } = useActionForm(action);
  const [enabled, setEnabled] = useState(initial.enabled);
  const [days, setDays] = useState<Record<number, Window[]>>(() => {
    const map: Record<number, Window[]> = { 0: [], 1: [], 2: [], 3: [], 4: [], 5: [], 6: [] };
    for (const s of initial.schedule) map[s.day]?.push({ uid: nextUid++, open: toInput(s.open), close: toInput(s.close) });
    return map;
  });
  const scheduleJson = useMemo(
    () => JSON.stringify(DISPLAY_ORDER.flatMap((day) => (days[day] ?? []).map((w) => ({ day, open: w.open, close: w.close })))),
    [days],
  );
  const hoursId = useId();
  const packMissing = !packs.some((p) => p.key === initial.packKey);

  const setDay = (day: number, fn: (windows: Window[]) => Window[]) => setDays((d) => ({ ...d, [day]: fn(d[day] ?? []) }));
  const copyToAll = (from: number) =>
    setDays((d) => {
      const source = d[from] ?? [];
      const next: Record<number, Window[]> = {};
      for (const day of DISPLAY_ORDER) next[day] = source.map((w) => ({ ...w, uid: nextUid++ }));
      return next;
    });

  return (
    <form onSubmit={onSubmit} className="flex flex-col gap-8">
      <input type="hidden" name="expectedVersion" value={version} />
      <input type="hidden" name="schedule" value={scheduleJson} />
      <FormMessage result={result} />

      <fieldset disabled={!canEdit} className="flex flex-col gap-8 disabled:opacity-70">
        <div className="flex flex-col gap-3">
          <Checkbox
            name="enabled"
            checked={enabled}
            onChange={(e) => setEnabled(e.target.checked)}
            label="Always-on games"
            description="Back-to-back 3–5 minute rounds run by themselves during opening hours, with a 60-second break and a nightly leaderboard. No host needed."
          />
          <div className="grid gap-5 md:grid-cols-2">
            <Field label="Always-on question pack" error={fieldError(result, 'packKey')} hint="Changes apply from tonight’s next always-on night.">
              <Select name="packKey" defaultValue={initial.packKey}>
                {packMissing && <option value={initial.packKey}>{initial.packKey} (unavailable)</option>}
                {packs.map((p) => (
                  <option key={p.key} value={p.key}>
                    {p.name} · {p.questionCount} questions
                  </option>
                ))}
              </Select>
            </Field>
          </div>
        </div>

        <section aria-labelledby={hoursId} className={cn('flex flex-col gap-4', !enabled && 'opacity-70')}>
          <div>
            <h2 id={hoursId} className="font-display text-lg font-semibold">
              Opening hours
            </h2>
            <p className="mt-1 text-sm text-muted">
              Always-on runs inside these windows (venue time). A closing time at or before the opening time runs past midnight — e.g. 11:00 AM to 2:00 AM.
            </p>
          </div>
          {fieldError(result, 'schedule') && (
            <p role="alert" className="text-sm font-medium text-danger-soft">
              {fieldError(result, 'schedule')}
            </p>
          )}
          <ul className="flex flex-col divide-y divide-line/60 rounded-2xl border border-line">
            {DISPLAY_ORDER.map((day) => {
              const windows = days[day] ?? [];
              const name = WEEKDAYS[day]!;
              return (
                <li key={day} className="flex flex-col gap-3 p-4 md:flex-row md:items-start">
                  <div className="flex w-32 shrink-0 items-center justify-between md:min-h-12">
                    <span className="font-semibold">{name}</span>
                    {windows.length === 0 && <span className="text-sm text-subtle md:hidden">Closed</span>}
                  </div>
                  <div className="flex flex-1 flex-col gap-2">
                    {windows.length === 0 && <span className="hidden min-h-12 items-center text-sm text-subtle md:flex">Closed</span>}
                    {windows.map((w, i) => {
                      const overnight = toMinutes(w.close) <= toMinutes(w.open);
                      return (
                        <div key={w.uid} className="flex flex-wrap items-center gap-2">
                          <label className="sr-only" htmlFor={`open-${w.uid}`}>
                            {name} window {i + 1} opens
                          </label>
                          <input
                            id={`open-${w.uid}`}
                            type="time"
                            value={w.open}
                            required
                            onChange={(e) => setDay(day, (ws) => ws.map((x) => (x.uid === w.uid ? { ...x, open: e.target.value } : x)))}
                            className="min-h-12 rounded-xl border border-line-strong bg-night/70 px-3 text-base text-fg focus-visible:border-cyan"
                          />
                          <span className="text-sm text-subtle">to</span>
                          <label className="sr-only" htmlFor={`close-${w.uid}`}>
                            {name} window {i + 1} closes
                          </label>
                          <input
                            id={`close-${w.uid}`}
                            type="time"
                            value={w.close}
                            required
                            onChange={(e) => setDay(day, (ws) => ws.map((x) => (x.uid === w.uid ? { ...x, close: e.target.value } : x)))}
                            className="min-h-12 rounded-xl border border-line-strong bg-night/70 px-3 text-base text-fg focus-visible:border-cyan"
                          />
                          {overnight && (
                            <span className="text-xs font-semibold text-amber-soft">{w.open === w.close ? '24 hours' : 'closes next day'}</span>
                          )}
                          <Button
                            variant="ghost"
                            size="sm"
                            className="px-3 hover:text-danger-soft"
                            aria-label={`Remove ${name} window ${i + 1}`}
                            onClick={() => setDay(day, (ws) => ws.filter((x) => x.uid !== w.uid))}
                          >
                            <XIcon />
                          </Button>
                        </div>
                      );
                    })}
                  </div>
                  <div className="flex flex-wrap gap-1 md:justify-end">
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => setDay(day, (ws) => [...ws, { uid: nextUid++, open: ws.length ? '18:00' : '11:00', close: ws.length ? '23:00' : '02:00' }])}
                      disabled={windows.length >= 4}
                    >
                      Add hours<span className="sr-only"> on {name}</span>
                    </Button>
                    {windows.length > 0 && (
                      <Button variant="ghost" size="sm" onClick={() => copyToAll(day)}>
                        Copy to all days<span className="sr-only"> from {name}</span>
                      </Button>
                    )}
                  </div>
                </li>
              );
            })}
          </ul>
        </section>

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

      {canEdit && (
        <div className="border-t border-line/70 pt-6">
          <SubmitButton size="lg" pending={pending} pendingLabel="Saving…">
            Save settings
          </SubmitButton>
        </div>
      )}
    </form>
  );
}
