"use client";

/**
 * The accept-gated RSVP form (FR-2.1 to FR-2.9).
 *
 * The form does not exist in the DOM until the guest taps Accept; it then reveals and
 * receives focus. Submission is idempotent server-side, but the button also disables on
 * the first tap so a double-tap on a slow connection does not fire two requests.
 */
import { useRef, useState } from "react";

import type { Dictionary } from "@/lib/i18n";
import type { PrefillView } from "@/lib/view-models";

export interface RsvpFormProps {
  token: string;
  maxGuests: number;
  prefill: PrefillView | null;
  dict: Dictionary;
  onSuccess: (result: { partySize: number; calendarUrl: string }) => void;
}

interface FieldErrors {
  name?: string;
  phone?: string;
  email?: string;
  form?: string;
}

export function RsvpForm({
  token,
  maxGuests,
  prefill,
  dict,
  onSuccess,
}: RsvpFormProps) {
  const [submitting, setSubmitting] = useState(false);
  const [errors, setErrors] = useState<FieldErrors>({});
  const formRef = useRef<HTMLFormElement>(null);

  async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (submitting) return;

    const data = new FormData(event.currentTarget);
    const name = String(data.get("name") ?? "").trim();
    const phone = String(data.get("phone") ?? "").trim();

    const nextErrors: FieldErrors = {};
    if (!name) nextErrors.name = dict.required;
    if (!phone) nextErrors.phone = dict.required;
    if (Object.keys(nextErrors).length > 0) {
      setErrors(nextErrors);
      return;
    }

    setSubmitting(true);
    setErrors({});

    try {
      const response = await fetch(`/api/rsvp/${encodeURIComponent(token)}/accept`, {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({
          name,
          phone,
          email: String(data.get("email") ?? "").trim() || null,
          party_size: Number(data.get("party_size") ?? 1),
          message_to_couple: String(data.get("message_to_couple") ?? "").trim() || null,
          dietary_notes: String(data.get("dietary_notes") ?? "").trim() || null,
        }),
      });

      if (!response.ok) {
        const body = await response.json().catch(() => null);
        // FastAPI returns field errors as a list of {loc, msg}.
        const detail = body?.detail;
        if (Array.isArray(detail)) {
          const mapped: FieldErrors = {};
          for (const item of detail as { loc?: unknown[]; msg?: string }[]) {
            const field = item?.loc?.at(-1);
            if (field === "phone" || field === "email" || field === "name") {
              mapped[field] = item.msg ?? dict.formError;
            }
          }
          setErrors(Object.keys(mapped).length ? mapped : { form: dict.formError });
        } else {
          setErrors({ form: typeof detail === "string" ? detail : dict.formError });
        }
        return;
      }

      const result = await response.json();
      onSuccess({
        partySize: result.party_size ?? 1,
        calendarUrl: result.calendar_url,
      });
    } catch {
      setErrors({ form: dict.formError });
    } finally {
      setSubmitting(false);
    }
  }

  const guestOptions = Array.from({ length: maxGuests }, (_, i) => i + 1);

  return (
    <form ref={formRef} onSubmit={handleSubmit} className="flex flex-col gap-4" noValidate>
      <label className="flex flex-col gap-1">
        <span className="text-sm font-medium">
          {dict.yourName} <span aria-hidden>*</span>
        </span>
        <input
          name="name"
          required
          defaultValue={prefill?.name ?? ""}
          autoComplete="name"
          aria-invalid={Boolean(errors.name)}
          className="min-h-11 rounded-lg border px-3 py-2 text-base"
        />
        {errors.name && (
          <span role="alert" className="text-sm text-red-600">
            {errors.name}
          </span>
        )}
      </label>

      <label className="flex flex-col gap-1">
        <span className="text-sm font-medium">
          {dict.phone} <span aria-hidden>*</span>
        </span>
        <input
          name="phone"
          required
          type="tel"
          inputMode="tel"
          defaultValue={prefill?.phone ?? ""}
          placeholder="01712345678"
          autoComplete="tel"
          aria-invalid={Boolean(errors.phone)}
          className="min-h-11 rounded-lg border px-3 py-2 text-base"
        />
        {errors.phone && (
          <span role="alert" className="text-sm text-red-600">
            {errors.phone}
          </span>
        )}
      </label>

      <label className="flex flex-col gap-1">
        <span className="text-sm font-medium">
          {dict.email}{" "}
          <span className="font-normal opacity-60">({dict.optional})</span>
        </span>
        <input
          name="email"
          type="email"
          defaultValue={prefill?.email ?? ""}
          autoComplete="email"
          aria-describedby="email-help"
          aria-invalid={Boolean(errors.email)}
          className="min-h-11 rounded-lg border px-3 py-2 text-base"
        />
        {/* v1 sends only email, so this field decides whether they hear from us at all. */}
        <span id="email-help" className="text-xs opacity-70">
          {dict.emailHelp}
        </span>
        {errors.email && (
          <span role="alert" className="text-sm text-red-600">
            {errors.email}
          </span>
        )}
      </label>

      <label className="flex flex-col gap-1">
        <span className="text-sm font-medium">{dict.guestsAttending}</span>
        <select
          name="party_size"
          defaultValue={1}
          className="min-h-11 rounded-lg border px-3 py-2 text-base"
        >
          {guestOptions.map((n) => (
            <option key={n} value={n}>
              {n}
            </option>
          ))}
        </select>
      </label>

      <label className="flex flex-col gap-1">
        <span className="text-sm font-medium">
          {dict.messageToCouple}{" "}
          <span className="font-normal opacity-60">({dict.optional})</span>
        </span>
        <textarea
          name="message_to_couple"
          maxLength={500}
          rows={3}
          className="rounded-lg border px-3 py-2 text-base"
        />
      </label>

      <label className="flex flex-col gap-1">
        <span className="text-sm font-medium">
          {dict.dietaryNotes}{" "}
          <span className="font-normal opacity-60">({dict.optional})</span>
        </span>
        <input
          name="dietary_notes"
          className="min-h-11 rounded-lg border px-3 py-2 text-base"
        />
      </label>

      {errors.form && (
        <p role="alert" className="text-sm text-red-600">
          {errors.form}
        </p>
      )}

      <button
        type="submit"
        disabled={submitting}
        className="min-h-12 rounded-full bg-black px-6 text-base font-medium text-white disabled:opacity-60"
      >
        {submitting ? dict.submitting : dict.confirm}
      </button>

      <p className="text-xs opacity-60">{dict.privacyNotice}</p>
    </form>
  );
}
