import { useEffect, useRef, useState, type FormEvent } from "react";
import { Link } from "react-router-dom";
import { ApiError, api, newIdempotencyKey } from "../api";
import { FeedbackBanner, LoadingState } from "../components/Feedback";
import { usePollingResource } from "../hooks/usePollingResource";
import type { CreateTicketPayload, CreateTicketResponse } from "../types";

type VisitorTicketFormState = Omit<CreateTicketPayload, "party_size"> & { party_size: number | "" };

const initialTicket: VisitorTicketFormState = { phone: "", last_name: "", honorific: "", party_size: 1 };

interface WriteIntent {
  fingerprint: string;
  idempotencyKey: string;
}

function isPhoneInputValid(value: string): boolean {
  const digits = value.replace(/\D/g, "");
  return /^[+\d\s\-()]+$/.test(value) && digits.length >= 7 && digits.length <= 15;
}

function keyForIntent(ref: { current: WriteIntent | null }, fingerprint: string): string {
  if (!ref.current || ref.current.fingerprint !== fingerprint) {
    ref.current = { fingerprint, idempotencyKey: newIdempotencyKey() };
  }
  return ref.current.idempotencyKey;
}

function releaseIntentAfterDefinitiveError(ref: { current: WriteIntent | null }, error: unknown) {
  if (error instanceof ApiError && error.status >= 400 && error.status < 500 && error.status !== 429) ref.current = null;
}

function ticketStatusPath(response: CreateTicketResponse): string | null {
  if (response.public_url) return response.public_url;
  if (response.public_token) return `/visitor/${response.public_token}`;
  return null;
}

export function VisitorTakeTicketForm() {
  const projectsResource = usePollingResource((signal) => api.publicProjects(signal), {
    intervalMs: 60_000,
    resourceKey: "visitor-public-projects",
  });
  const projects = projectsResource.data?.projects ?? [];
  const [selectedProjectId, setSelectedProjectId] = useState("");
  const [ticketForm, setTicketForm] = useState<VisitorTicketFormState>(initialTicket);
  const [phoneError, setPhoneError] = useState<string | null>(null);
  const [formError, setFormError] = useState<string | null>(null);
  const [confirmDuplicatePhone, setConfirmDuplicatePhone] = useState(false);
  const [createdTicket, setCreatedTicket] = useState<CreateTicketResponse | null>(null);
  const [busy, setBusy] = useState(false);
  const [retryAfterSeconds, setRetryAfterSeconds] = useState(0);
  const createIntentRef = useRef<WriteIntent | null>(null);

  useEffect(() => {
    if (retryAfterSeconds <= 0) return;
    const timer = window.setTimeout(() => {
      setRetryAfterSeconds((current) => Math.max(0, current - 1));
    }, 1000);
    return () => window.clearTimeout(timer);
  }, [retryAfterSeconds]);

  useEffect(() => {
    if (!projects.length) return;
    if (!projects.some((project) => project.id === selectedProjectId)) {
      setSelectedProjectId(projects[0].id);
    }
  }, [projects, selectedProjectId]);

  const selectedProject = projects.find((project) => project.id === selectedProjectId);
  const minPartySize = selectedProject?.min_party_size ?? 1;
  const maxPartySize = selectedProject?.max_party_size ?? minPartySize;

  useEffect(() => {
    if (!selectedProject) return;
    setTicketForm((current) => ({
      ...current,
      party_size: typeof current.party_size === "number" && current.party_size >= minPartySize && current.party_size <= maxPartySize
        ? current.party_size
        : minPartySize,
    }));
  }, [selectedProject?.id]);

  function updateTicketForm(patch: Partial<VisitorTicketFormState>) {
    setTicketForm((current) => ({ ...current, ...patch }));
    setConfirmDuplicatePhone(false);
    setPhoneError(null);
    setFormError(null);
    createIntentRef.current = null;
  }

  function resetForAnotherTicket() {
    setCreatedTicket(null);
    setTicketForm({ ...initialTicket, party_size: minPartySize });
    setConfirmDuplicatePhone(false);
    setPhoneError(null);
    setFormError(null);
    createIntentRef.current = null;
  }

  async function submitTicket(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (retryAfterSeconds > 0) return;
    if (!selectedProjectId) {
      setFormError("请选择要排队的项目");
      return;
    }
    const partySize = ticketForm.party_size;
    if (typeof partySize !== "number" || !Number.isInteger(partySize) || partySize < minPartySize || partySize > maxPartySize) {
      setFormError(`本项目每个号码可绑定 ${minPartySize} 到 ${maxPartySize} 人`);
      return;
    }
    const phone = ticketForm.phone.trim();
    if (!isPhoneInputValid(phone)) {
      setPhoneError("请输入有效的手机号（7-15 位数字）");
      setFormError(null);
      return;
    }
    setPhoneError(null);
    setFormError(null);
    setBusy(true);
    const payload: CreateTicketPayload = { ...ticketForm, phone, party_size: partySize, allow_duplicate: confirmDuplicatePhone };
    const fingerprint = JSON.stringify([selectedProjectId, payload]);
    const idempotencyKey = keyForIntent(createIntentRef, fingerprint);
    try {
      const response = await api.publicCreateTicket(selectedProjectId, payload, idempotencyKey);
      createIntentRef.current = null;
      setCreatedTicket(response);
      setTicketForm({ ...initialTicket, party_size: minPartySize });
      setConfirmDuplicatePhone(false);
      setRetryAfterSeconds(0);
    } catch (caught) {
      if (caught instanceof ApiError && caught.code === "DUPLICATE_PHONE") {
        createIntentRef.current = null;
        setConfirmDuplicatePhone(true);
        setFormError(null);
        setRetryAfterSeconds(0);
      } else if (caught instanceof ApiError && caught.status === 429) {
        setConfirmDuplicatePhone(false);
        setFormError(null);
        setRetryAfterSeconds(caught.retryAfterSeconds ?? 60);
      } else {
        releaseIntentAfterDefinitiveError(createIntentRef, caught);
        setConfirmDuplicatePhone(false);
        setRetryAfterSeconds(0);
        setFormError(caught instanceof ApiError ? caught.message : "取号未提交，请检查当前数据后重试。");
      }
    } finally {
      setBusy(false);
    }
  }

  const statusPath = createdTicket ? ticketStatusPath(createdTicket) : null;

  return (
    <section className="visitor-lookup-card visitor-take-ticket-card" aria-label="取号">
      {projectsResource.loading && !projects.length ? <LoadingState label="正在读取可取号项目" /> : null}
      {projectsResource.error && !projects.length ? (
        <FeedbackBanner
          tone="danger"
          title="暂时无法读取项目"
          action={<button className="button button--secondary button--small" type="button" onClick={projectsResource.refresh}>重试</button>}
        >
          {projectsResource.error.message}
        </FeedbackBanner>
      ) : null}
      {!projectsResource.loading && !projectsResource.error && !projects.length ? (
        <FeedbackBanner tone="warning" title="当前暂无可取号项目">请稍后再试，或咨询现场工作人员。</FeedbackBanner>
      ) : null}

      {createdTicket ? (
        <div className="visitor-ticket-created" role="status" aria-live="polite">
          <span>取号成功</span>
          <p>您的排队号码</p>
          <strong>{createdTicket.ticket.ticket_number}</strong>
          <small>{selectedProject?.name ?? "当前项目"} · {createdTicket.ticket.party_size} 人 · 手机号尾号 {createdTicket.ticket.phone_last4 ?? "未返回"}</small>
          {statusPath ? <Link className="button button--primary button--wide" to={statusPath}>查看排队状态</Link> : null}
          <button className="button button--ghost button--wide" type="button" onClick={resetForAnotherTicket}>继续取号</button>
        </div>
      ) : (
        <form className="visitor-lookup-form visitor-take-ticket-form" onSubmit={submitTicket} noValidate>
          <label className="field" htmlFor="visitor-ticket-project">
            <span>排队项目</span>
            <select
              id="visitor-ticket-project"
              value={selectedProjectId}
              onChange={(event) => {
                setSelectedProjectId(event.target.value);
                setFormError(null);
              }}
              disabled={busy || !projects.length}
            >
              <option value="">请选择项目</option>
              {projects.map((project) => <option key={project.id} value={project.id}>{project.name}</option>)}
            </select>
          </label>
          {selectedProject?.visitor_notice ? <p className="visitor-take-ticket__notice">{selectedProject.visitor_notice}</p> : null}
          <label className="field" htmlFor="visitor-ticket-party-size">
            <span>同行人数</span>
            <input
              id="visitor-ticket-party-size"
              name="party_size"
              aria-label="同行人数"
              type="number"
              inputMode="numeric"
              min={minPartySize}
              max={maxPartySize}
              value={ticketForm.party_size}
              onChange={(event) => updateTicketForm({
                party_size: Number.isNaN(event.currentTarget.valueAsNumber) ? "" : event.currentTarget.valueAsNumber,
              })}
              disabled={busy}
              required
            />
            <small>本项目每个号码可绑定 {minPartySize}–{maxPartySize} 人</small>
          </label>
          <label className="field" htmlFor="visitor-ticket-phone">
            <span>手机号</span>
            <input
              id="visitor-ticket-phone"
              name="phone"
              type="tel"
              inputMode="tel"
              autoComplete="tel"
              placeholder="请输入手机号"
              value={ticketForm.phone}
              onChange={(event) => updateTicketForm({ phone: event.target.value })}
              disabled={busy}
              aria-invalid={phoneError ? "true" : "false"}
              aria-describedby={phoneError ? "visitor-ticket-phone-error" : undefined}
            />
            {phoneError ? <small id="visitor-ticket-phone-error" className="field-error" role="alert">{phoneError}</small> : null}
          </label>
          <div className="field-row">
            <label className="field" htmlFor="visitor-ticket-last-name">
              <span>姓氏（选填）</span>
              <input
                id="visitor-ticket-last-name"
                value={ticketForm.last_name}
                onChange={(event) => updateTicketForm({ last_name: event.target.value })}
                disabled={busy}
              />
            </label>
            <fieldset className="field honorific-field" disabled={busy}>
              <legend>称谓（选填）</legend>
              <div className="honorific-options">
                {[
                  { value: "", label: "不填写" },
                  { value: "先生", label: "先生" },
                  { value: "女士", label: "女士" },
                ].map((option) => (
                  <label key={option.label}>
                    <input
                      type="radio"
                      name="visitor-ticket-honorific"
                      value={option.value}
                      checked={ticketForm.honorific === option.value}
                      onChange={() => updateTicketForm({ honorific: option.value })}
                    />
                    <span>{option.label}</span>
                  </label>
                ))}
              </div>
            </fieldset>
          </div>
          {confirmDuplicatePhone ? <FeedbackBanner tone="warning" title="该手机号已有活动号码">如需继续取号，请再次点击确认按钮。</FeedbackBanner> : null}
          {retryAfterSeconds > 0 ? <FeedbackBanner tone="warning" title={`请求过于频繁，请在 ${retryAfterSeconds} 秒后重试。`} /> : null}
          {formError ? <FeedbackBanner tone="danger" title={formError} /> : null}
          <button className="button button--primary button--wide" type="submit" disabled={busy || retryAfterSeconds > 0 || !selectedProjectId || !projects.length}>
            {busy ? "正在创建排队号码" : retryAfterSeconds > 0 ? `请等待 ${retryAfterSeconds} 秒` : confirmDuplicatePhone ? "确认继续取号" : "创建排队号码"}
          </button>
        </form>
      )}

    </section>
  );
}
