"use client";

import { useState, type FormEvent } from "react";

/**
 * Every public form on the site.
 *
 * Server-validated. The browser adds inline error tips for immediacy, but the
 * server's verdict is the one that decides whether a lead is stored, and the
 * success message depends only on the API's 2xx — which itself depends only on
 * the database write. An email or Odoo outage may delay a notification; it may
 * never lose a lead, and it may never show an error for a lead that was saved.
 *
 * Three layouts, matching the Blade component:
 *
 *   home    — placeholder-only fields in rows, as the design's home band has it.
 *             aria-label carries the accessible name so removing the visible
 *             label costs a screen reader nothing.
 *   project — the interest drawer's field set, phone required.
 *   default — labelled blocks, the contact page's form.
 *
 * The honeypot is a real field named `company_website`, hidden from sight and
 * from assistive technology. Failing it looks like success to the bot so it does
 * not learn to adapt — the backend does that part; here it just has to exist and
 * stay empty.
 *
 * No CSRF token: there is no session to fix one to. The controls are the
 * per-IP throttle and the origin allowlist, both server-side.
 */

interface Props {
  form: string;
  layout?: "default" | "home" | "project";
  className?: string;
  sourceComponent?: string;
  submitLabel?: string;
  showProjectSelect?: boolean;
  projects?: Array<{ id: number; title: string }>;
  projectId?: number | null;
  /**
   * Resolved strings, not a translator.
   *
   * This is a Client Component and functions cannot cross the server/client
   * boundary in the App Router. The server parent resolves them from the
   * lang files the API ships and passes plain strings.
   */
  labels: Record<string, string>;
  locale: string;
}

type Errors = Record<string, string[]>;

export default function LeadForm({
  form,
  layout = "default",
  className = "",
  sourceComponent,
  submitLabel,
  showProjectSelect = false,
  projects = [],
  projectId = null,
  labels,
  locale,
}: Props) {
  const L = (key: string) => labels[key] ?? key;
  const [state, setState] = useState<"idle" | "sending" | "sent" | "error">("idle");
  const [errors, setErrors] = useState<Errors>({});

  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();

    const formElement = event.currentTarget;
    const body = new FormData(formElement);

    setState("sending");
    setErrors({});

    try {
      const response = await fetch(`/api/leads/${form}`, {
        method: "POST",
        headers: { Accept: "application/json" },
        body,
      });

      if (response.ok) {
        setState("sent");
        formElement.reset();
        return;
      }

      if (response.status === 422) {
        const payload = await response.json();
        setErrors(payload.errors ?? {});
        setState("error");
        return;
      }

      setState("error");
    } catch {
      // A network failure is the visitor's problem to retry, not a reason to
      // claim the lead was stored.
      setState("error");
    }
  }

  const fieldError = (name: string) => errors[name]?.[0];

  return (
    <form className={`demo-form ${className}`.trim()} method="POST" action={`/api/leads/${form}`} onSubmit={onSubmit}>
      {state === "sent" ? (
        <p className="form-response is-sent" role="status">
          {L("js.form.sent")}
        </p>
      ) : null}

      {state === "error" ? (
        <p className="form-response is-error" role="alert">
          {L("js.form.invalid")}
        </p>
      ) : null}

      <div className="field field--trap" aria-hidden="true">
        <label htmlFor={`${form}-company-website`}>Company website</label>
        <input
          type="text"
          id={`${form}-company-website`}
          name="company_website"
          tabIndex={-1}
          autoComplete="off"
        />
      </div>

      {layout === "home" ? (
        <>
          <p className="contact-form__row">
            <span className="contact-form__cell">
              <input
                type="text"
                name="name"
                placeholder={L("forms.name")}
                aria-label={L("forms.name")}
                autoComplete="name"
                required
              />
            </span>
            <span className="contact-form__cell">
              <input
                type="email"
                name="email"
                placeholder={L("forms.email")}
                aria-label={L("forms.email")}
                autoComplete="email"
                required
              />
            </span>
          </p>
          <p>
            <input
              type="tel"
              name="phone"
              placeholder={L("forms.phone")}
              aria-label={L("forms.phone")}
              autoComplete="tel"
            />
          </p>
          <p>
            <textarea
              name="message"
              rows={4}
              placeholder={L("forms.message")}
              aria-label={L("forms.message")}
            />
          </p>
          <p className="contact-form__actions">
            <button className="btn" type="submit" disabled={state === "sending"}>
              {submitLabel ?? L("forms.send")}
            </button>
          </p>
        </>
      ) : layout === "project" ? (
        <>
          <div className="field field--name">
            <input
              type="text"
              name="name"
              placeholder={L("forms.full_name")}
              aria-label={L("forms.full_name")}
              autoComplete="name"
              required
            />
          </div>
          <div className="field field--email">
            <input
              type="email"
              name="email"
              placeholder={L("forms.email")}
              aria-label={L("forms.email")}
              autoComplete="email"
              required
            />
          </div>
          <div className="field field--phone">
            <input
              type="tel"
              name="phone"
              placeholder={L("forms.mobile")}
              aria-label={L("forms.mobile")}
              autoComplete="tel"
              required
            />
          </div>
          <div className="field field--message">
            <textarea
              name="message"
              rows={4}
              placeholder={L("forms.message")}
              aria-label={L("forms.message")}
            />
          </div>
          <div className="field field--submit">
            <button className="btn" type="submit" disabled={state === "sending"}>
              {L("forms.send_message")}
            </button>
          </div>
        </>
      ) : (
        <>
          {([
            ["name", "text", "name"],
            ["email", "email", "email"],
            ["phone", "tel", "tel"],
          ] as const).map(([name, type, autocomplete]) => (
            <div className="field" key={name}>
              <label htmlFor={`${form}-${name}`}>{L(`forms.${name}`)}</label>
              <input
                type={type}
                id={`${form}-${name}`}
                name={name}
                autoComplete={autocomplete}
                aria-invalid={fieldError(name) ? true : undefined}
                aria-describedby={fieldError(name) ? `${form}-${name}-error` : undefined}
                required={name !== "phone" || form === "project_interest"}
              />
              {fieldError(name) ? (
                <span className="field-error" id={`${form}-${name}-error`}>
                  {fieldError(name)}
                </span>
              ) : null}
            </div>
          ))}
        </>
      )}

      {showProjectSelect ? (
        <div className="field field--full">
          <label htmlFor={`${form}-project`}>{L("forms.project")}</label>
          <select id={`${form}-project`} name="project_id" defaultValue="">
            <option value="">{L("forms.choose_project")}</option>
            {projects.map((project) => (
              <option key={project.id} value={project.id}>
                {project.title}
              </option>
            ))}
          </select>
        </div>
      ) : null}

      {layout === "default" ? (
        <div className="field field--full">
          <label htmlFor={`${form}-message`}>{L("forms.message")}</label>
          <textarea id={`${form}-message`} name="message" rows={4} />
          {fieldError("message") ? <span className="field-error">{fieldError("message")}</span> : null}
        </div>
      ) : null}

      {/*
        So an enquiry from a project page can be told apart from one off the
        contact page without guessing from the referrer. The backend also reads
        source_url to decide which language to answer in — it is what stops an
        English visitor's mistake being answered in Arabic.
      */}
      <SourceFields form={form} sourceComponent={sourceComponent} locale={locale} />

      {projectId ? <input type="hidden" name="project_id" value={projectId} /> : null}

      {layout === "default" ? (
        <button className="btn btn--fill" type="submit" disabled={state === "sending"}>
          {submitLabel ?? L("forms.send")}
        </button>
      ) : null}
    </form>
  );
}

/**
 * Provenance fields, filled from the live document.
 *
 * Rendered client-side because `location.href` and `document.title` are what
 * the Blade version's `url()->current()` and the resolved page title were —
 * properties of the page the visitor is actually on, not of the server render.
 */
function SourceFields({
  form,
  sourceComponent,
  locale,
}: {
  form: string;
  sourceComponent?: string;
  locale: string;
}) {
  const href = typeof window === "undefined" ? "" : window.location.href;
  const title = typeof document === "undefined" ? "" : document.title;
  const params = typeof window === "undefined" ? null : new URLSearchParams(window.location.search);

  return (
    <>
      <input type="hidden" name="source_url" value={href} />
      <input type="hidden" name="source_component" value={sourceComponent ?? form} />
      <input type="hidden" name="source_page_title" value={title} />
      <input type="hidden" name="locale" value={locale} />
      {["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"].map((utm) =>
        params?.get(utm) ? <input key={utm} type="hidden" name={utm} value={params.get(utm)!} /> : null,
      )}
    </>
  );
}
