"use client";

import { useActionState, useState } from "react";
import { useFormStatus } from "react-dom";
import { motion } from "framer-motion";
import { CheckMark } from "../ui/CheckMark";
import { Spinner } from "../ui/Spinner";
import { sendContact, type ContactState } from "@/app/actions/contact";
import { CONTACT_CHANNELS } from "@/lib/site";
import { EASE_OUT_EXPO } from "@/lib/motion";

const initialState: ContactState = { status: "idle", message: "" };

function SubmitButton() {
  const { pending } = useFormStatus();
  return (
    <button
      type="submit"
      disabled={pending}
      className="sheen relative inline-flex items-center justify-center gap-2 overflow-hidden bg-accent px-8 py-3 font-display text-sm tracking-widest text-background transition duration-200 ease-out hover:-translate-y-0.5 hover:bg-foreground hover:shadow-[0_14px_30px_-14px_rgba(196,184,150,0.6)] active:scale-[0.97] disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:translate-y-0 disabled:hover:shadow-none"
    >
      {pending && <Spinner />}
      {pending ? "SENDING…" : "SEND MESSAGE"}
    </button>
  );
}

const inputBase =
  "w-full bg-surface border px-4 py-3 text-sm text-foreground placeholder:text-foreground-muted focus:outline-none transition-colors duration-200";

/** Field errors slide in under their input rather than appearing under it. */
function FieldError({ children, id }: { children: string; id: number }) {
  return (
    <motion.p
      key={id}
      initial={{ opacity: 0, y: -4 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.25, ease: EASE_OUT_EXPO }}
      className="mt-1.5 text-xs text-red-400"
    >
      {children}
    </motion.p>
  );
}

export function ContactForm() {
  const [state, formAction] = useActionState(sendContact, initialState);

  // A rejected submission has to be felt even when the message is identical to
  // the last one. React would keep the same paragraph mounted and replay
  // nothing, so every attempt gets a number and the number is the React key.
  //
  // Counted during render by comparing with the previous result rather than in
  // an effect: the action already returns a fresh object per submission, so
  // this needs no second render pass to stay in sync.
  const [seen, setSeen] = useState(state);
  const [attempt, setAttempt] = useState(0);
  if (seen !== state) {
    setSeen(state);
    setAttempt((count) => count + 1);
  }

  if (state.status === "success") {
    return (
      <motion.div
        initial={{ opacity: 0, scale: 0.96 }}
        animate={{ opacity: 1, scale: 1 }}
        transition={{ duration: 0.45, ease: EASE_OUT_EXPO }}
        className="rounded-2xl border border-accent/40 bg-surface p-10 text-center"
      >
        <CheckMark className="mx-auto mb-6 h-12 w-12" />
        <p className="mb-3 font-display text-xs tracking-[0.3em] text-accent">
          MESSAGE SENT
        </p>
        <p className="leading-relaxed text-foreground-muted">{state.message}</p>
      </motion.div>
    );
  }

  const err = state.fieldErrors ?? {};

  return (
    <form action={formAction} className="space-y-5">
      <input
        type="text"
        name="website"
        tabIndex={-1}
        autoComplete="off"
        className="hidden"
        aria-hidden
      />

      <div className="grid sm:grid-cols-2 gap-5">
        <div>
          <label
            htmlFor="contact-name"
            className="block font-display text-xs tracking-[0.3em] text-foreground-muted mb-2"
          >
            NAME
          </label>
          <input
            id="contact-name"
            name="name"
            type="text"
            required
            placeholder="Your name"
            className={`${inputBase} ${err.name ? "border-red-400" : "border-border focus:border-accent"}`}
          />
          {err.name && <FieldError id={attempt}>{err.name}</FieldError>}
        </div>
        <div>
          <label
            htmlFor="contact-email"
            className="block font-display text-xs tracking-[0.3em] text-foreground-muted mb-2"
          >
            EMAIL
          </label>
          <input
            id="contact-email"
            name="email"
            type="email"
            required
            placeholder="you@example.com"
            className={`${inputBase} ${err.email ? "border-red-400" : "border-border focus:border-accent"}`}
          />
          {err.email && <FieldError id={attempt}>{err.email}</FieldError>}
        </div>
      </div>

      <div className="grid gap-5 sm:grid-cols-2">
        {/* The desk the message is for. It replaces the three mailto cards as
            the default path: the visitor picks a reason instead of guessing
            which address to write to. */}
        <div>
          <label
            htmlFor="contact-topic"
            className="mb-2 block font-display text-xs tracking-[0.3em] text-foreground-muted"
          >
            REASON
          </label>
          <select
            id="contact-topic"
            name="topic"
            defaultValue={CONTACT_CHANNELS[0].label}
            className={`${inputBase} cursor-pointer border-border focus:border-accent`}
          >
            {CONTACT_CHANNELS.map((channel) => (
              <option key={channel.label} value={channel.label}>
                {channel.label.charAt(0) + channel.label.slice(1).toLowerCase()}
              </option>
            ))}
          </select>
        </div>

        <div>
          <label
            htmlFor="contact-subject"
            className="mb-2 block font-display text-xs tracking-[0.3em] text-foreground-muted"
          >
            SUBJECT
          </label>
          <input
            id="contact-subject"
            name="subject"
            type="text"
            required
            placeholder="What is this about?"
            className={`${inputBase} ${err.subject ? "border-red-400" : "border-border focus:border-accent"}`}
          />
          {err.subject && <FieldError id={attempt}>{err.subject}</FieldError>}
        </div>
      </div>

      <div>
        <label
          htmlFor="contact-message"
          className="block font-display text-xs tracking-[0.3em] text-foreground-muted mb-2"
        >
          MESSAGE
        </label>
        <textarea
          id="contact-message"
          name="message"
          rows={6}
          required
          placeholder="Your message…"
          className={`${inputBase} resize-y ${err.message ? "border-red-400" : "border-border focus:border-accent"}`}
        />
        {err.message && <FieldError id={attempt}>{err.message}</FieldError>}
      </div>

      <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 pt-2">
        <SubmitButton />
        {state.status === "error" && !Object.keys(err).length && (
          // Shakes once per attempt. The key remounts it, which is what makes
          // the CSS animation run again on an identical repeated error.
          <p key={attempt} className="animate-shake text-sm text-red-400">
            {state.message}
          </p>
        )}
      </div>
    </form>
  );
}
