"use client";
/* eslint-disable @next/next/no-img-element -- served through /api/media */

import * as React from "react";
import { useMutation, useQuery } from "convex/react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import { ArrowLeft, ArrowRight, BadgeCheck, Check, Lock, MessageCircle, Minus, Phone, Plus, ShieldCheck, Sparkles, Users, X, Zap } from "lucide-react";
import { api } from "../../../convex/_generated/api";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
import { AnimatedText } from "@/components/motion/animated-number";
import { AvailabilityCalendar } from "./availability-calendar";
import { getAttribution } from "@/lib/attribution";
import { track } from "./fb-pixel";
import { fmtMoney } from "@/lib/format";
import { addDays, dayKey, fmtDate, nightsBetween, parseDay, startOfMonth } from "@/lib/dates";
import type { Apartment, Avail, Business } from "./showroom-page";

const src = (id: string, w: number) => `/api/media/${id}?w=${w}`;
const digitsOf = (s: string) => s.replace(/[^\d]/g, "");
const ease = [0.16, 1, 0.3, 1] as const;
const spring = { type: "spring", stiffness: 420, damping: 36 } as const;
type Step = "dates" | "details" | "done";

/**
 * Self-serve booking in three screens: pick the nights on a live calendar,
 * leave name and phone, done. The reservation is created immediately as
 * "pending confirmation" (the nights are held), and the desk confirms by
 * WhatsApp within minutes. No account, no card, no friction.
 */
export function BookingFlow({ open, apartment: a, business, checkIn: initIn, checkOut: initOut, guests: initGuests, today, onClose, onDates }: { open: boolean; apartment: Apartment | null; business: Business; checkIn: string; checkOut: string; guests: number; today: string; onClose: () => void; onDates: (ci: string, co: string) => void }) {
  const reduced = useReducedMotion();
  const book = useMutation(api.showroom.book);
  const [step, setStep] = React.useState<Step>("dates");
  const [checkIn, setCheckIn] = React.useState(initIn);
  const [checkOut, setCheckOut] = React.useState(initOut);
  const [guests, setGuests] = React.useState(initGuests);
  const [pickStart, setPickStart] = React.useState<string | null>(null);
  const [month, setMonth] = React.useState<Date>(startOfMonth(parseDay(initIn || today)));
  const [name, setName] = React.useState("");
  const [phone, setPhone] = React.useState("");
  const [email, setEmail] = React.useState("");
  const [note, setNote] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [done, setDone] = React.useState<{ code: string | null; total: number | null; review: boolean } | null>(null);

  React.useEffect(() => {
    if (!open) return;
    setStep("dates");
    setCheckIn(initIn);
    setCheckOut(initOut);
    setGuests(Math.min(initGuests, a?.maxGuests ?? initGuests));
    setPickStart(null);
    setMonth(startOfMonth(parseDay(initIn || today)));
    setError(null);
    setDone(null);
    setBusy(false);
    if (a) track("InitiateCheckout", { content_name: a.code, content_type: "apartment" });
    // eslint-disable-next-line react-hooks/exhaustive-deps -- reset only when the sheet opens
  }, [open, a?.id]);

  const nights = checkIn && checkOut ? nightsBetween(parseDay(checkIn), parseDay(checkOut)) : 0;
  const availData = useQuery(api.showroom.availability, open && a && nights > 0 ? { checkIn, checkOut } : "skip") as { items: Avail[] } | undefined;
  const avail = a ? availData?.items.find((x) => x.id === a.id) : undefined;
  const booked = useQuery(api.showroom.calendar, open && a ? { apartmentId: a.id as never, from: dayKey(month), days: 70 } : "skip");
  const taken = React.useMemo(() => new Set(booked ?? []), [booked]);
  const conflict = nights > 0 && [...Array(nights)].some((_, i) => taken.has(dayKey(addDays(parseDay(checkIn), i))));
  const free = nights > 0 && !conflict && (avail ? avail.available : true);
  const total = avail?.subtotal ?? (a ? a.basePrice * Math.max(1, nights) : 0);

  const pick = (day: string) => {
    if (!pickStart) {
      setPickStart(day);
      setCheckIn(day);
      setCheckOut("");
      return;
    }
    if (day <= pickStart) {
      setPickStart(day);
      setCheckIn(day);
      setCheckOut("");
      return;
    }
    setCheckOut(day);
    setPickStart(null);
    onDates(pickStart, day);
  };

  async function submit(e?: React.FormEvent) {
    e?.preventDefault();
    if (!a || busy) return;
    if (name.trim().length < 2) return setError("Your name, please.");
    if (digitsOf(phone).length < 8) return setError("A phone number we can reach you on — we confirm there.");
    setBusy(true);
    setError(null);
    try {
      const r = await book({ apartmentId: a.id as never, checkIn, checkOut, guests, name: name.trim(), phone: phone.trim(), email: email.trim() || undefined, message: note.trim() || undefined, attribution: getAttribution() });
      if (!r.ok) {
        setError(r.error ?? "Please try again.");
        if (/took these nights/i.test(r.error ?? "")) setStep("dates");
        return;
      }
      setDone({ code: r.code ?? null, total: r.total ?? null, review: !!r.pendingReview });
      setStep("done");
      track("Lead", { content_name: a.code, value: r.total ?? total, currency: business.currency });
      if ("vibrate" in navigator) navigator.vibrate?.([10, 40, 10]);
    } catch {
      setError("Could not send right now — message us on WhatsApp instead.");
    } finally {
      setBusy(false);
    }
  }

  const waText = a && done ? `Hello ${business.name}, I just booked ${a.name} (${a.code})${done.code ? ` — reference ${done.code}` : ""} for ${fmtDate(parseDay(checkIn), { style: "weekday" })} → ${fmtDate(parseDay(checkOut), { style: "weekday" })}, ${guests} guest${guests > 1 ? "s" : ""}. Please confirm.` : "";
  const progress = step === "dates" ? 1 : step === "details" ? 2 : 3;

  return (
    <Dialog open={open && !!a} onOpenChange={(o) => !o && onClose()}>
      <DialogContent size="lg" hideClose className="overflow-hidden p-0">
        {a ? (
          <>
            <DialogTitle className="sr-only">Book {a.name}</DialogTitle>
            <button type="button" onClick={onClose} className="absolute right-3 top-3 z-10 flex size-9 items-center justify-center rounded-full bg-stone-950/40 text-white backdrop-blur transition hover:rotate-90 hover:bg-stone-950/60" aria-label="Close"><X className="size-4" /></button>
            {/* Header strip */}
            <div className="relative h-36 overflow-hidden bg-stone-950 text-white sm:h-40">
              <img src={src(a.images[0].id, 960)} alt="" className="absolute inset-0 size-full object-cover opacity-80" />
              <div className="absolute inset-0 bg-gradient-to-t from-stone-950/90 via-stone-950/30 to-transparent" />
              <div className="absolute inset-x-5 bottom-4">
                <p className="text-2xs font-semibold uppercase tracking-[0.2em] text-white/70">{step === "done" ? "Booked" : "Book direct · no payment now"}</p>
                <p className="font-display text-2xl font-medium leading-tight sm:text-3xl">{a.name}</p>
              </div>
              {/* Progress */}
              <div className="absolute inset-x-0 bottom-0 h-1 bg-white/15">
                <motion.div className="h-full bg-primary" initial={false} animate={{ width: `${(progress / 3) * 100}%` }} transition={{ duration: 0.6, ease }} />
              </div>
            </div>

            <div className="max-h-[70dvh] overflow-y-auto p-4 scrollbar-thin sm:p-5">
              <AnimatePresence mode="wait" initial={false}>
                {step === "dates" ? (
                  <motion.div key="dates" initial={{ opacity: 0, x: -20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }} transition={{ duration: 0.3, ease }} className="grid gap-5 lg:grid-cols-[1.2fr_1fr]">
                    <div>
                      <p className="eyebrow">Step 1 of 2 · Your nights</p>
                      <p className="text-sm text-fg-muted">Tap a check-in day, then a check-out day. Taken nights are hatched — the calendar is live.</p>
                      <div className="mt-3">{booked === undefined ? <div className="skeleton h-64" /> : <AvailabilityCalendar booked={taken} checkIn={pickStart ?? checkIn} checkOut={pickStart ? "" : checkOut} today={today} onPick={pick} month={month} onMonth={setMonth} />}</div>
                    </div>
                    <div className="flex flex-col gap-3">
                      <div className="rounded-2xl border border-border bg-surface-2/50 p-4">
                        <div className="flex items-center justify-between">
                          <span className="text-xs font-medium text-fg-muted">Guests</span>
                          <div className="flex items-center gap-1 rounded-xl border border-border bg-surface px-1">
                            <button type="button" onClick={() => setGuests((g) => Math.max(1, g - 1))} className="flex size-8 items-center justify-center rounded-lg text-fg-muted transition hover:bg-surface-2 active:scale-90" aria-label="Fewer guests"><Minus className="size-4" /></button>
                            <span key={guests} className="w-6 text-center text-sm font-semibold tabular animate-badge-pop">{guests}</span>
                            <button type="button" onClick={() => setGuests((g) => Math.min(a.maxGuests, g + 1))} className="flex size-8 items-center justify-center rounded-lg text-fg-muted transition hover:bg-surface-2 active:scale-90" aria-label="More guests"><Plus className="size-4" /></button>
                          </div>
                        </div>
                        <p className="mt-1 text-2xs text-fg-subtle">Up to {a.maxGuests} guests</p>
                        <div className="mt-3 border-t border-border pt-3">
                          {nights > 0 ? (
                            <>
                              <p className="text-sm font-medium">{fmtDate(parseDay(checkIn), { style: "weekday" })} → {fmtDate(parseDay(checkOut), { style: "weekday" })}</p>
                              <p className="text-xs text-fg-muted">{nights} night{nights > 1 ? "s" : ""} · {fmtMoney(total / nights, business.currency, { whole: true })} avg per night</p>
                              <div className="mt-2 flex items-end justify-between">
                                <span className={cn("inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-2xs font-semibold", free ? "bg-positive-500/12 text-positive-700 dark:text-positive-500" : "bg-negative-500/12 text-negative-600")}><span className={cn("size-1.5 rounded-full", free ? "bg-positive-500 live-dot" : "bg-negative-500")} /> {free ? "Free for these nights" : "Not free — pick other nights"}</span>
                                <span className="font-display text-2xl font-medium tabular"><AnimatedText text={fmtMoney(total, business.currency, { whole: true })} /></span>
                              </div>
                            </>
                          ) : (
                            <p className="text-sm text-fg-muted">Pick your check-out day to see the price.</p>
                          )}
                        </div>
                      </div>
                      <ul className="space-y-1.5 text-xs text-fg-muted">
                        <li className="flex items-center gap-2"><Lock className="size-3.5 text-positive-600" /> No payment online — you pay at check-in</li>
                        <li className="flex items-center gap-2"><BadgeCheck className="size-3.5 text-positive-600" /> Confirmed by a real person in about {business.replyMinutes} min</li>
                        <li className="flex items-center gap-2"><Sparkles className="size-3.5 text-positive-600" /> Direct price — no platform fees</li>
                      </ul>
                      <Button size="lg" className={cn("mt-auto w-full rounded-xl", free && "shine")} disabled={!free} onClick={() => setStep("details")}>
                        Continue <ArrowRight />
                      </Button>
                    </div>
                  </motion.div>
                ) : step === "details" ? (
                  <motion.form key="details" onSubmit={submit} initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: 20 }} transition={{ duration: 0.3, ease }} className="grid gap-5 lg:grid-cols-[1.2fr_1fr]">
                    <div className="space-y-3">
                      <div>
                        <p className="eyebrow">Step 2 of 2 · Who is coming?</p>
                        <p className="text-sm text-fg-muted">Two fields and you are done. We confirm on WhatsApp or by phone.</p>
                      </div>
                      <Input value={name} onChange={(e) => setName(e.target.value)} placeholder="Your full name" autoComplete="name" className="h-12 rounded-xl text-base" autoFocus aria-label="Name" />
                      <Input value={phone} onChange={(e) => setPhone(e.target.value)} placeholder="+212 6 XX XX XX XX" inputMode="tel" autoComplete="tel" className="h-12 rounded-xl text-base" aria-label="Phone" />
                      <Input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email (optional)" inputMode="email" autoComplete="email" className="h-11 rounded-xl" aria-label="Email" />
                      <Input value={note} onChange={(e) => setNote(e.target.value)} placeholder="Arrival time, baby cot, anything… (optional)" className="h-11 rounded-xl" aria-label="Note" />
                      {error ? <p role="alert" className="rounded-lg bg-negative-50 px-3 py-2 text-xs font-medium text-negative-700 animate-slide-up dark:bg-negative-500/10">{error}</p> : null}
                    </div>
                    <div className="flex flex-col gap-3">
                      <div className="rounded-2xl border border-border bg-surface-2/50 p-4 text-sm">
                        <p className="font-semibold">{a.name} <span className="font-mono text-xs text-fg-muted">{a.code}</span></p>
                        <p className="mt-1 text-fg-muted">{fmtDate(parseDay(checkIn), { style: "weekday" })} → {fmtDate(parseDay(checkOut), { style: "weekday" })}</p>
                        <p className="flex items-center gap-1 text-fg-muted"><Users className="size-3.5" /> {guests} guest{guests > 1 ? "s" : ""} · {nights} night{nights > 1 ? "s" : ""}</p>
                        <div className="mt-3 flex items-end justify-between border-t border-border pt-3">
                          <span className="text-xs text-fg-muted">Total · pay at check-in</span>
                          <span className="font-display text-2xl font-medium tabular">{fmtMoney(total, business.currency, { whole: true })}</span>
                        </div>
                      </div>
                      <p className="flex items-start gap-2 text-2xs text-fg-subtle"><ShieldCheck className="size-3.5 shrink-0 text-positive-600" /> Your number is used only to confirm this booking. No account, no card, nothing charged online.</p>
                      <div className="mt-auto flex gap-2">
                        <Button type="button" size="lg" variant="secondary" onClick={() => setStep("dates")} disabled={busy} aria-label="Back"><ArrowLeft /></Button>
                        <Button type="submit" size="lg" className="flex-1 rounded-xl shine" loading={busy}>
                          <Zap /> Confirm my booking
                        </Button>
                      </div>
                    </div>
                  </motion.form>
                ) : (
                  <motion.div key="done" initial={{ opacity: 0, scale: 0.96 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.35, ease }} className="flex flex-col items-center py-2 text-center">
                    <span className="relative">
                      <motion.span initial={{ scale: 0 }} animate={{ scale: 1 }} transition={{ type: "spring", stiffness: 380, damping: 15, delay: 0.1 }} className="flex size-20 items-center justify-center rounded-full bg-positive-500/15 text-positive-600">
                        <Check className="size-10" />
                      </motion.span>
                      {!reduced ? [0, 1, 2, 3, 4, 5].map((i) => <motion.span key={i} aria-hidden initial={{ opacity: 0, x: 0, y: 0, scale: 0 }} animate={{ opacity: [0, 1, 0], x: Math.cos((i / 6) * Math.PI * 2) * 54, y: Math.sin((i / 6) * Math.PI * 2) * 54, scale: [0, 1.2, 0.6] }} transition={{ duration: 0.9, delay: 0.25 + i * 0.03, ease }} className="absolute left-1/2 top-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-gold-500" />) : null}
                    </span>
                    <p className="mt-4 font-display text-3xl font-medium leading-tight">{done?.review ? "Request received" : "Your nights are held"}</p>
                    {done?.code ? <p className="mt-1 font-mono text-sm text-fg-muted">Reference {done.code}</p> : null}
                    <p className="mt-2 max-w-sm text-sm text-fg-muted">{done?.review ? `Thank you ${name.split(" ")[0]} — a team member will call you on ${phone} shortly to finalise.` : `${name.split(" ")[0]}, ${business.name} will confirm on WhatsApp or by phone within about ${business.replyMinutes} minutes. Nothing to pay now.`}</p>
                    <ol className="mt-5 grid w-full max-w-md grid-cols-3 gap-2 text-left text-2xs">
                      {[["1", "Booked", "Nights held for you"], ["2", "Confirmed", `A real person confirms in ~${business.replyMinutes} min`], ["3", "Welcome", `Check-in from ${business.checkInTime}`]].map(([n, t, d], i) => (
                        <motion.li key={n} initial={{ opacity: 0, y: 8 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.4 + i * 0.12 }} className={cn("rounded-xl border p-2.5", i === 0 ? "border-positive-500/40 bg-positive-500/8" : "border-border")}>
                          <span className={cn("flex size-5 items-center justify-center rounded-full text-[10px] font-bold", i === 0 ? "bg-positive-500 text-white" : "bg-surface-2 text-fg-muted")}>{i === 0 ? <Check className="size-3" /> : n}</span>
                          <span className="mt-1 block font-semibold text-fg">{t}</span>
                          <span className="text-fg-muted">{d}</span>
                        </motion.li>
                      ))}
                    </ol>
                    <div className="mt-5 flex w-full max-w-md flex-col gap-2 sm:flex-row">
                      {digitsOf(business.whatsapp) ? (
                        <Button size="lg" className="flex-1 bg-[#25D366] text-white hover:bg-[#1fb857]" asChild onClick={() => track("Contact", { method: "whatsapp", content_name: "post-booking" })}>
                          <a href={`https://wa.me/${digitsOf(business.whatsapp)}?text=${encodeURIComponent(waText)}`} target="_blank" rel="noreferrer"><MessageCircle /> Send it to WhatsApp</a>
                        </Button>
                      ) : null}
                      <Button size="lg" variant="secondary" className="flex-1" asChild>
                        <a href={`tel:${business.phone}`}><Phone /> Call {business.name}</a>
                      </Button>
                    </div>
                    <button type="button" onClick={onClose} className="mt-3 text-xs font-medium text-fg-muted transition hover:text-fg">Back to the apartments</button>
                  </motion.div>
                )}
              </AnimatePresence>
            </div>
          </>
        ) : null}
      </DialogContent>
    </Dialog>
  );
}
