"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 =
  | "firstName"
  | "lastName"
  | "jobTitle"
  | "workEmail"
  | "firmName"
  | "firmType"
  | "regulator"
  | "activeClients"
  | "yearsInOperation"
  | "confirmRegistered"
  | "agreeContact";

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

const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

const REQUIRED_LABELS: Partial<Record<FieldName, string>> = {
  firstName: "First name",
  lastName: "Last name",
  jobTitle: "Job title",
  firmName: "Firm name",
};

function validateField(name: FieldName, value: string): string {
  const requiredLabel = REQUIRED_LABELS[name];
  if (requiredLabel) {
    return value.trim() ? "" : `${requiredLabel} is required.`;
  }

  switch (name) {
    case "workEmail":
      if (!value.trim()) return "Work email is required.";
      return EMAIL_RE.test(value.trim()) ? "" : "Enter a valid email address.";
    case "firmType":
      return value ? "" : "Select a firm type.";
    case "regulator":
      return value ? "" : "Select a regulator.";
    case "activeClients":
      if (!value.trim()) return "Number of active clients is required.";
      return Number(value) >= 0 && Number.isFinite(Number(value)) ? "" : "Enter a valid number.";
    case "yearsInOperation":
      if (!value.trim()) return "Years in operation is required.";
      return Number(value) >= 0 && Number.isFinite(Number(value)) ? "" : "Enter a valid number.";
    default:
      return "";
  }
}

function validateCheckbox(name: FieldName, checked: boolean): string {
  if (checked) return "";
  return name === "confirmRegistered"
    ? "Please confirm your firm's regulatory status."
    : "Please agree to be contacted to submit your application.";
}

function ArrowIcon() {
  return (
    <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden>
      <path d="M5 12h14M12 5l7 7-7 7" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

/**
 * 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 SmeInitiativeForm() {
  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 | HTMLSelectElement>) {
    const { name, value } = event.currentTarget;
    const message = validateField(name as FieldName, value);
    setErrors((prev) => ({ ...prev, [name]: message || undefined }));
  }

  function handleCheckboxChange(event: ChangeEvent<HTMLInputElement>) {
    const { name, checked } = event.currentTarget;
    const message = validateCheckbox(name as FieldName, checked);
    setErrors((prev) => ({ ...prev, [name]: message || undefined }));
  }

  function handleFieldChange(event: ChangeEvent<HTMLInputElement | HTMLSelectElement>) {
    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[] = [
      "firstName",
      "lastName",
      "jobTitle",
      "workEmail",
      "firmName",
      "firmType",
      "regulator",
      "activeClients",
      "yearsInOperation",
    ];
    const checkboxNames: FieldName[] = ["confirmRegistered", "agreeContact"];

    const nextErrors: FieldErrors = {};
    for (const name of fieldNames) {
      const message = validateField(name, String(data.get(name) ?? ""));
      if (message) nextErrors[name] = message;
    }
    for (const name of checkboxNames) {
      const message = validateCheckbox(name, data.get(name) === "on");
      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/sme-initiative", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload),
      });

      // Surface per-field rejections (ours or the backend's) next to the field
      // rather than collapsing them into one generic failure message.
      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="sme-form" onSubmit={handleSubmit} noValidate>
      <div className="sme-form-row">
        <div className={`sme-field${errors.firstName ? " sme-field--invalid" : ""}`}>
          <label htmlFor="sme-first-name">First Name</label>
          <input
            id="sme-first-name"
            name="firstName"
            type="text"
            placeholder="First name"
            aria-invalid={!!errors.firstName}
            aria-describedby={errors.firstName ? "sme-first-name-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.firstName && (
            <p className="sme-field-error" id="sme-first-name-error">
              {errors.firstName}
            </p>
          )}
        </div>
        <div className={`sme-field${errors.lastName ? " sme-field--invalid" : ""}`}>
          <label htmlFor="sme-last-name">Last Name</label>
          <input
            id="sme-last-name"
            name="lastName"
            type="text"
            placeholder="Last name"
            aria-invalid={!!errors.lastName}
            aria-describedby={errors.lastName ? "sme-last-name-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.lastName && (
            <p className="sme-field-error" id="sme-last-name-error">
              {errors.lastName}
            </p>
          )}
        </div>
      </div>

      <div className="sme-form-row">
        <div className={`sme-field${errors.jobTitle ? " sme-field--invalid" : ""}`}>
          <label htmlFor="sme-job-title">Job Title</label>
          <input
            id="sme-job-title"
            name="jobTitle"
            type="text"
            placeholder="Job title"
            aria-invalid={!!errors.jobTitle}
            aria-describedby={errors.jobTitle ? "sme-job-title-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.jobTitle && (
            <p className="sme-field-error" id="sme-job-title-error">
              {errors.jobTitle}
            </p>
          )}
        </div>
        <div className={`sme-field${errors.workEmail ? " sme-field--invalid" : ""}`}>
          <label htmlFor="sme-work-email">Work Email</label>
          <input
            id="sme-work-email"
            name="workEmail"
            type="email"
            placeholder="you@firm.com"
            aria-invalid={!!errors.workEmail}
            aria-describedby={errors.workEmail ? "sme-work-email-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.workEmail && (
            <p className="sme-field-error" id="sme-work-email-error">
              {errors.workEmail}
            </p>
          )}
        </div>
      </div>

      <div className={`sme-field${errors.firmName ? " sme-field--invalid" : ""}`}>
        <label htmlFor="sme-firm-name">Firm Name</label>
        <input
          id="sme-firm-name"
          name="firmName"
          type="text"
          placeholder="Firm name"
          aria-invalid={!!errors.firmName}
          aria-describedby={errors.firmName ? "sme-firm-name-error" : undefined}
          onBlur={handleFieldBlur}
          onChange={handleFieldChange}
        />
        {errors.firmName && (
          <p className="sme-field-error" id="sme-firm-name-error">
            {errors.firmName}
          </p>
        )}
      </div>

      <div className="sme-form-row">
        <div className={`sme-field${errors.firmType ? " sme-field--invalid" : ""}`}>
          <label htmlFor="sme-firm-type">Firm Type</label>
          <select
            id="sme-firm-type"
            name="firmType"
            defaultValue=""
            aria-invalid={!!errors.firmType}
            aria-describedby={errors.firmType ? "sme-firm-type-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          >
            <option value="" disabled>
              Select firm type
            </option>
            <option value="Wealth management firm">Wealth management firm</option>
            <option value="Asset management firm">Asset management firm</option>
            <option value="Multi-family office">Multi-family office</option>
            <option value="Capital advisory firm">Capital advisory firm</option>
            <option value="External asset manager">External asset manager</option>
          </select>
          {errors.firmType && (
            <p className="sme-field-error" id="sme-firm-type-error">
              {errors.firmType}
            </p>
          )}
        </div>
        <div className={`sme-field${errors.regulator ? " sme-field--invalid" : ""}`}>
          <label htmlFor="sme-regulator">Regulator (DIFC / DFSA / ADGM)</label>
          <select
            id="sme-regulator"
            name="regulator"
            defaultValue=""
            aria-invalid={!!errors.regulator}
            aria-describedby={errors.regulator ? "sme-regulator-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          >
            <option value="" disabled>
              Select regulator
            </option>
            <option value="DIFC">DIFC</option>
            <option value="DFSA">DFSA</option>
            <option value="ADGM">ADGM</option>
          </select>
          {errors.regulator && (
            <p className="sme-field-error" id="sme-regulator-error">
              {errors.regulator}
            </p>
          )}
        </div>
      </div>

      <div className="sme-form-row">
        <div className={`sme-field${errors.activeClients ? " sme-field--invalid" : ""}`}>
          <label htmlFor="sme-active-clients">Number of Active Clients</label>
          <input
            id="sme-active-clients"
            name="activeClients"
            type="number"
            min={0}
            placeholder="e.g. 12"
            aria-invalid={!!errors.activeClients}
            aria-describedby={errors.activeClients ? "sme-active-clients-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.activeClients && (
            <p className="sme-field-error" id="sme-active-clients-error">
              {errors.activeClients}
            </p>
          )}
        </div>
        <div className={`sme-field${errors.yearsInOperation ? " sme-field--invalid" : ""}`}>
          <label htmlFor="sme-years-operation">Years in Operation</label>
          <input
            id="sme-years-operation"
            name="yearsInOperation"
            type="number"
            min={0}
            placeholder="e.g. 3"
            aria-invalid={!!errors.yearsInOperation}
            aria-describedby={errors.yearsInOperation ? "sme-years-operation-error" : undefined}
            onBlur={handleFieldBlur}
            onChange={handleFieldChange}
          />
          {errors.yearsInOperation && (
            <p className="sme-field-error" id="sme-years-operation-error">
              {errors.yearsInOperation}
            </p>
          )}
        </div>
      </div>

      <div className="sme-field">
        <label htmlFor="sme-challenges">
          Current Operational Challenges <span style={{ textTransform: "none", letterSpacing: 0, color: "var(--text-4)" }}>(optional)</span>
        </label>
        <textarea id="sme-challenges" name="challenges" placeholder="Leave blank if not applicable" />
      </div>

      <div className="sme-declarations">
        <p className="sme-declarations-label">Declarations</p>
        <label className={`sme-check-row${errors.confirmRegistered ? " sme-check-row--invalid" : ""}`}>
          <input type="checkbox" name="confirmRegistered" onChange={handleCheckboxChange} />
          <span>I confirm that my firm is registered with DIFC, DFSA, or ADGM and is operating in compliance with all applicable regulations.</span>
        </label>
        {errors.confirmRegistered && <p className="sme-field-error">{errors.confirmRegistered}</p>}
        <label className={`sme-check-row${errors.agreeContact ? " sme-check-row--invalid" : ""}`}>
          <input type="checkbox" name="agreeContact" onChange={handleCheckboxChange} />
          <span>I agree to be contacted by the Oxyfinz team regarding this initiative and understand that my details will be used solely for the purpose of processing this application.</span>
        </label>
        {errors.agreeContact && <p className="sme-field-error">{errors.agreeContact}</p>}
      </div>

      <TurnstileWidget />

      <button className="sme-submit" type="submit" disabled={status === "submitting"}>
        {status === "submitting" ? "Submitting…" : "Submit application"}
        <ArrowIcon />
      </button>

      {status === "ok" && <p className="sme-status sme-status--ok">Thanks — a member of our team will be in touch within two business days.</p>}
      {status === "error" && (
        <p className="sme-status sme-status--error">
          {notice ?? "Something went wrong. Please email hello@oxyfinz.com instead."}
        </p>
      )}
    </form>
  );
}
