"use client";

import { useState, type ChangeEvent, type FocusEvent, type FormEvent } from "react";
import { TurnstileWidget } from "./turnstile-widget";

type Status = "idle" | "submitting" | "ok" | "error";

type FieldName = "name" | "email" | "phone" | "company" | "message";

type FieldErrors = Partial<Record<FieldName, string>>;

const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// Matches the backend's expectation: optional leading +, then 7-15 digits once
// the usual separators are stripped.
const PHONE_RE = /^\+?[0-9]{7,15}$/;
const NAME_MIN = 2;
const MESSAGE_MIN = 10;

function validateField(name: FieldName, value: string): string {
  switch (name) {
    case "name":
      if (!value.trim()) return "Name is required.";
      return value.trim().length >= NAME_MIN ? "" : "Enter your full name.";
    case "email":
      if (!value.trim()) return "Email is required.";
      return EMAIL_RE.test(value.trim()) ? "" : "Enter a valid email address.";
    case "phone":
      if (!value.trim()) return "Phone is required.";
      return PHONE_RE.test(value.replace(/[\s().-]/g, "")) ? "" : "Enter a valid phone number.";
    case "message":
      if (!value.trim()) return "Message is required.";
      return value.trim().length >= MESSAGE_MIN
        ? ""
        : `Tell us a little more — at least ${MESSAGE_MIN} characters.`;
    default:
      return "";
  }
}

/**
 * Yii2 returns each field's errors as an array of strings; our own route
 * returns a plain string. Collapse both to the single string the UI renders.
 */
function normalizeServerErrors(raw: Record<string, unknown>): FieldErrors {
  const out: FieldErrors = {};
  for (const [key, value] of Object.entries(raw)) {
    const message = Array.isArray(value) ? value[0] : value;
    if (typeof message === "string" && message) out[key as FieldName] = message;
  }
  return out;
}

export function ContactForm() {
  const [status, setStatus] = useState<Status>("idle");
  const [errors, setErrors] = useState<FieldErrors>({});
  // Server-sent notices that are not per-field: rate limiting, challenge
  // failures. Without these a limited user just sees "something went wrong".
  const [notice, setNotice] = useState<string | null>(null);

  function handleFieldBlur(event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) {
    const { name, value } = event.currentTarget;
    const message = validateField(name as FieldName, value);
    setErrors((prev) => ({ ...prev, [name]: message || undefined }));
  }

  function handleFieldChange(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
    const { name } = event.currentTarget;
    if (errors[name as FieldName]) {
      const message = validateField(name as FieldName, event.currentTarget.value);
      setErrors((prev) => ({ ...prev, [name]: message || undefined }));
    }
  }

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

    const form = event.currentTarget;
    const data = new FormData(form);

    const fieldNames: FieldName[] = ["name", "email", "phone", "message"];
    const nextErrors: FieldErrors = {};
    for (const name of fieldNames) {
      const message = validateField(name, String(data.get(name) ?? ""));
      if (message) nextErrors[name] = message;
    }

    setErrors(nextErrors);

    const firstInvalid = Object.keys(nextErrors)[0];
    if (firstInvalid) {
      const el = form.elements.namedItem(firstInvalid) as HTMLElement | null;
      el?.focus();
      return;
    }

    setNotice(null);
    setStatus("submitting");
    const payload = Object.fromEntries(data.entries());

    try {
      const res = await fetch("/api/contact", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      });

      if (res.status === 422) {
        const body = await res.json().catch(() => null);
        if (body?.errors && typeof body.errors === "object") {
          setErrors(normalizeServerErrors(body.errors));
          const firstServerInvalid = Object.keys(body.errors)[0];
          const el = firstServerInvalid ? (form.elements.namedItem(firstServerInvalid) as HTMLElement | null) : null;
          el?.focus();
        }
        setStatus("error");
        return;
      }

      if (res.status === 429 || res.status === 403) {
        const body = await res.json().catch(() => null);
        setNotice(
          typeof body?.message === "string"
            ? body.message
            : "Too many submissions. Please try again later."
        );
        setStatus("error");
        return;
      }

      if (!res.ok) throw new Error("Request failed");
      setStatus("ok");
      form.reset();
      setErrors({});
    } catch {
      setStatus("error");
    }
  }

  return (
    <form className="contact-form" onSubmit={handleSubmit} noValidate>
      <div className="contact-form-row">
        <div className={`contact-field${errors.name ? " contact-field--invalid" : ""}`}>
          <label htmlFor="contact-name">Full name</label>
          <input
            id="contact-name"
            name="name"
            type="text"
            placeholder="Jane Doe"
            aria-invalid={!!errors.name}
            aria-describedby={errors.name ? "contact-name-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.name && (
            <p className="contact-field-error" id="contact-name-error">
              {errors.name}
            </p>
          )}
        </div>
        <div className={`contact-field${errors.email ? " contact-field--invalid" : ""}`}>
          <label htmlFor="contact-email">Work email</label>
          <input
            id="contact-email"
            name="email"
            type="email"
            placeholder="jane@company.com"
            aria-invalid={!!errors.email}
            aria-describedby={errors.email ? "contact-email-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.email && (
            <p className="contact-field-error" id="contact-email-error">
              {errors.email}
            </p>
          )}
        </div>
      </div>

      <div className="contact-form-row">
        <div className={`contact-field${errors.phone ? " contact-field--invalid" : ""}`}>
          <label htmlFor="contact-phone">Phone</label>
          <input
            id="contact-phone"
            name="phone"
            type="tel"
            autoComplete="tel"
            inputMode="tel"
            placeholder="+971 50 000 0000"
            aria-invalid={!!errors.phone}
            aria-describedby={errors.phone ? "contact-phone-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.phone && (
            <p className="contact-field-error" id="contact-phone-error">
              {errors.phone}
            </p>
          )}
        </div>
        <div className="contact-field">
          <label htmlFor="contact-company">Company</label>
          <input id="contact-company" name="company" type="text" placeholder="Company name" />
        </div>
      </div>

      <div className={`contact-field${errors.message ? " contact-field--invalid" : ""}`}>
        <label htmlFor="contact-message">Message</label>
        <textarea
          id="contact-message"
          name="message"
          placeholder="Tell us about your desk and what you're looking for."
          aria-invalid={!!errors.message}
          aria-describedby={errors.message ? "contact-message-error" : undefined}
          onBlur={handleFieldBlur}
          onChange={handleFieldChange}
        />
        {errors.message && (
          <p className="contact-field-error" id="contact-message-error">
            {errors.message}
          </p>
        )}
      </div>

      <TurnstileWidget />

      <button className="contact-submit" type="submit" disabled={status === "submitting"}>
        {status === "submitting" ? "Sending…" : "Send message"}
      </button>
      {status === "ok" && <p className="contact-status contact-status--ok">Thanks — we&apos;ll be in touch shortly.</p>}
      {status === "error" && (
        <p className="contact-status contact-status--error">
          {notice
            ? notice
            : Object.keys(errors).length > 0
              ? "Please check the highlighted fields and try again."
              : "Something went wrong. Please email hello@oxyfinz.com instead."}
        </p>
      )}
    </form>
  );
}
