"use client";

import { useEffect, useMemo, useReducer, useRef, useState } from "react";
import Link from "next/link";
import { useMutation } from "@tanstack/react-query";
import type { CheckinSubmitPayload } from "@alqove/api-client";
import type { CheckinBrandingData } from "@alqove/api-client";
import { checkinApi, getOptionalAuthToken } from "@/lib/checkin/api";
import { isValidUsPhone } from "@/lib/checkin/phone";
import {
  getOrCreateIdempotencyKey,
  resetIdempotencyKey,
} from "@/lib/checkin/idempotency";
import { persistStatus, readPersistedStatus } from "@/lib/checkin/status-link";
import { StepPhone } from "@/components/checkin/StepPhone";
import { StepContainers } from "@/components/checkin/StepContainers";
import { StepReview } from "@/components/checkin/StepReview";
import { Turnstile } from "@/components/checkin/Turnstile";
import { Confirmation } from "@/components/checkin/Confirmation";
import {
  checkinDraftReducer,
  draftToPayload,
  initialDraft,
  type CheckinDraft,
} from "@/components/checkin/types";
import { DeadLinkNotice } from "./DeadLinkNotice";
import { StorePausedNotice } from "./StorePausedNotice";

const STEPS = ["phone", "containers", "review"] as const;
const STEP_TITLES = [
  "Your details",
  "What are you bringing?",
  "Review & check in",
] as const;

function stepIsValid(step: number, draft: CheckinDraft): boolean {
  switch (step) {
    case 0:
      return (
        draft.first_name.trim().length > 0 &&
        draft.last_name.trim().length > 0 &&
        isValidUsPhone(draft.phone)
      );
    default:
      // Containers (stepper-clamped) and review (opt-ins optional) are always valid.
      return true;
  }
}

function errorStatus(err: unknown): number | undefined {
  if (err && typeof err === "object" && "status" in err) {
    return (err as { status?: number }).status;
  }
  return undefined;
}

/** 409 — the customer already submitted; route them to the existing status. */
function AlreadySubmitted({ token }: { token: string }) {
  const existing = readPersistedStatus(token);
  return (
    <div className="mx-auto flex w-full max-w-md flex-col items-center gap-4 text-center">
      <h1 className="text-xl font-semibold text-slate-900">
        You&apos;re already checked in
      </h1>
      <p className="text-sm text-slate-600">
        It looks like this check-in was already submitted.
      </p>
      {existing ? (
        <Link
          href={existing.status_url}
          className="min-h-12 w-full rounded-lg bg-slate-900 px-4 py-3 text-base font-semibold text-white"
        >
          Track my check-in
        </Link>
      ) : null}
    </div>
  );
}

/**
 * Multi-step check-in wizard with Turnstile-gated submit. Local `useReducer`
 * holds the draft. Submit goes through a TanStack Query mutation that sends the
 * stable idempotency key (so a network retry safely replays) and the Turnstile
 * token. Response handling: 201/200 → confirmation; 409 → already-submitted;
 * 410/423 → dead/paused; other errors → retryable.
 *
 * `onSubmit` is an optional override used by unit tests to assert payload shape
 * without exercising the network mutation.
 */
export function CheckinForm({
  token,
  branding,
  onSubmit,
}: {
  token: string;
  branding: CheckinBrandingData;
  onSubmit?: (payload: CheckinSubmitPayload) => void;
}) {
  const [draft, dispatch] = useReducer(checkinDraftReducer, initialDraft);
  const [step, setStep] = useState(0);
  const [turnstileToken, setTurnstileToken] = useState<string | null>(null);
  const [submittedPayload, setSubmittedPayload] =
    useState<CheckinSubmitPayload | null>(null);

  // Move focus to the step heading on change so screen-reader + keyboard users
  // land on the new content rather than at the top of the document.
  const headingRef = useRef<HTMLHeadingElement>(null);
  const mounted = useRef(false);
  useEffect(() => {
    if (mounted.current) headingRef.current?.focus();
    else mounted.current = true;
  }, [step]);

  const mutation = useMutation({
    mutationFn: (payload: CheckinSubmitPayload) =>
      checkinApi.submit(token, payload, {
        idempotencyKey: getOrCreateIdempotencyKey(token),
        turnstileToken: turnstileToken ?? "",
        authToken: getOptionalAuthToken() ?? undefined,
      }),
    onSuccess: (res) => {
      persistStatus(token, res.data);
      // Only mint a fresh key once the submission has truly landed.
      resetIdempotencyKey(token);
    },
  });

  const isLastStep = step === STEPS.length - 1;
  const canAdvance = stepIsValid(step, draft);
  const showLoginLink = useMemo(() => getOptionalAuthToken() === null, []);
  const loginHref = `/login?redirect=/c/${token}`;

  // ----- result states -----
  if (mutation.isSuccess) {
    return (
      <Confirmation
        token={token}
        accepted={mutation.data.data}
        storeName={branding.name}
      />
    );
  }
  if (mutation.isError) {
    const status = errorStatus(mutation.error);
    if (status === 409) return <AlreadySubmitted token={token} />;
    if (status === 410) return <DeadLinkNotice />;
    if (status === 423) return <StorePausedNotice branding={branding} />;
    return (
      <div
        role="alert"
        className="mx-auto flex w-full max-w-md flex-col items-center gap-4 text-center"
      >
        <h1 className="text-xl font-semibold text-slate-900">
          We couldn&apos;t submit your check-in
        </h1>
        <p className="text-sm text-slate-600">
          Something went wrong. Your details are safe — try again.
        </p>
        <button
          type="button"
          className="min-h-12 w-full rounded-lg bg-slate-900 px-4 py-3 text-base font-semibold text-white"
          onClick={() => submittedPayload && mutation.mutate(submittedPayload)}
        >
          Try again
        </button>
      </div>
    );
  }

  // ----- wizard -----
  const submitBlocked = isLastStep && !onSubmit && !turnstileToken;

  function handlePrimary() {
    if (!canAdvance) return;
    if (!isLastStep) {
      setStep((s) => Math.min(STEPS.length - 1, s + 1));
      return;
    }
    const payload = draftToPayload(draft);
    if (onSubmit) {
      onSubmit(payload);
      return;
    }
    if (!turnstileToken) return;
    setSubmittedPayload(payload);
    mutation.mutate(payload);
  }

  return (
    <div className="mx-auto flex w-full max-w-md flex-col gap-6">
      <ol className="flex gap-2" aria-label="Progress">
        {STEPS.map((name, i) => (
          <li
            key={name}
            aria-current={i === step ? "step" : undefined}
            className={`h-1.5 flex-1 rounded-full ${
              i <= step ? "bg-slate-900" : "bg-slate-200"
            }`}
          />
        ))}
      </ol>

      <h2
        ref={headingRef}
        tabIndex={-1}
        className="text-lg font-semibold text-slate-900 focus:outline-none"
      >
        <span className="sr-only">
          Step {step + 1} of {STEPS.length}:{" "}
        </span>
        {STEP_TITLES[step]}
      </h2>

      {step === 0 ? <StepPhone draft={draft} dispatch={dispatch} /> : null}
      {step === 1 ? <StepContainers draft={draft} dispatch={dispatch} /> : null}
      {step === 2 ? (
        <StepReview
          draft={draft}
          dispatch={dispatch}
          storeName={branding.name}
          showLoginLink={showLoginLink}
          loginHref={loginHref}
        />
      ) : null}

      {/* Invisible-first bot check; acquires a token in the background. */}
      <Turnstile onToken={setTurnstileToken} />

      <div className="flex items-center gap-3">
        {step > 0 ? (
          <button
            type="button"
            className="min-h-12 flex-1 rounded-lg border border-slate-300 px-4 py-3 text-base font-medium text-slate-700"
            onClick={() => setStep((s) => Math.max(0, s - 1))}
          >
            Back
          </button>
        ) : null}
        <button
          type="button"
          className="min-h-12 flex-1 rounded-lg bg-slate-900 px-4 py-3 text-base font-semibold text-white disabled:opacity-40"
          disabled={!canAdvance || submitBlocked || mutation.isPending}
          onClick={handlePrimary}
        >
          {isLastStep ? "Check in" : "Next"}
        </button>
      </div>
    </div>
  );
}
