// Lalaluxe booking — components/shared.jsx (split from app.jsx; load before app.jsx — see CLAUDE.md "multi-file Babel contract")
// Contact-validity predicates shared by the checkout gate (ContinueButton) and the
// per-field hints (CheckoutStep) so the two can never drift.
function contactChecks(c) {
	c = c || {};
	return {
		name: !!(c.name && c.name.trim().length > 1),
		email: !!(c.email && c.email.includes("@")),
		phone: !!(c.phone && c.phone.replace(/\D/g, "").length === 10),
	};
}

function ContinueButton({ s, sq, onNext }) {
	// figure out if continue is enabled
	let ok = true;
	let label = "Continue";
	// Subscription forks into new-vs-existing on this same screen; Continue must wait for that
	// pick or it routes (via next()) to the NEW-plan flow, silently sending an existing
	// subscriber past their "enter your code" redemption path.
	if (s.step === "visit" && (!s.visit || (s.visit === "subscription" && !s.subMode)))
		ok = false;
	if (s.step === "who" && !s.who) ok = false;
	if (s.step === "base" && !s.service) ok = false;
	if (s.step === "length" && !s.length) ok = false;
	// The look screen merges base style (finish) + art level (design): both are required to
	// continue UNLESS the customer chose "Other" (design === "custom"), the menu-escape that
	// clears finish and is satisfied on its own — they'll show inspo instead of picking presets.
	if (s.step === "design" && !(s.design === "custom" || (s.finish && s.design)))
		ok = false;
	if (s.step === "tbase" && (!s.tbase || !s.tfinish)) ok = false;
	if (s.step === "plan" && !s.plan) ok = false;
	if (s.step === "summary") label = "Pick a time";
	if (s.step === "calendar") {
		ok = !!(s.date && s.time);
		label = "To checkout";
	}
	if (s.step === "checkout") {
		const ck = contactChecks(s.contact);
		ok = ck.name && ck.email && ck.phone;
		// Opens the consent/disclosure modal first; the modal's own button is the actual
		// "Continue to Square" redirect — so this one must NOT duplicate that label.
		label = "Review & continue";
	}

	// multi-select steps always allow continue
	return (
		<button
			className={
				"cta " +
				(s.step === "checkout" || s.step === "summary" ? "cherry" : "")
			}
			disabled={!ok}
			onClick={onNext}
		>
			{label} <span className="arrow"></span>
		</button>
	);
}

function PicksTray({ s, cfg }) {
	const items = priceItems(s);
	if (items.length === 0) return null;
	const t = total(s);
	return (
		<div className="tray">
			<div className="head">
				<span className="label">
					{s.visit === "subscription" ? "Your plan so far" : "Your set so far"}
				</span>
				<span className="total">
					{items.some((i) => i.quote) ? "from " : ""}${t}
				</span>
			</div>
			<div className="chips">
				{items.map((it, i) => (
					<span className="chip" key={i}>
						<span className="x">♡</span>
						{it.label}
					</span>
				))}
			</div>
		</div>
	);
}

/* ============== Screens ============== */
function ShareImagePreviewList({ files, onRemove }) {
	const [previews, setPreviews] = useState([]);
	useEffect(() => {
		const urls = files.map((file, index) => ({
			file,
			index,
			url: URL.createObjectURL(file),
		}));
		setPreviews(urls);
		return () => {
			urls.forEach((item) => {
				URL.revokeObjectURL(item.url);
			});
		};
	}, [files]);

	if (!files.length) return null;

	return (
		<div className="share-previews">
			{previews.map((item) => (
				<div className="share-preview" key={item.url}>
					<img src={item.url} alt="" />
					<div className="share-preview-meta">
						<span>{item.file.name}</span>
						<small>{formatFileSize(item.file.size)}</small>
					</div>
					<button type="button" onClick={() => onRemove(item.index)}>
						Remove
					</button>
				</div>
			))}
		</div>
	);
}

// Inspo image picker, shared by the look screen ("Other" path) and checkout. Reads/writes the
// SAME s.shareImages, so a photo attached on either screen flows to the booking once.
function InspoUpload({ s, set }) {
	const files = s.shareImages || [];
	const [busy, setBusy] = useState(false);
	const [error, setError] = useState("");
	const pick = async (e) => {
		const list = e.target.files;
		if (!list || list.length === 0) return;
		setBusy(true);
		setError("");
		try {
			// Merge with what's already attached (the Remove buttons handle de-selection);
			// only prepare what fits so over-cap picks aren't resized then discarded.
			const room = Math.max(0, SHARE_IMAGE_LIMIT - files.length);
			const prepared = await prepareShareImages(Array.from(list).slice(0, room));
			set({ shareImages: [...files, ...prepared] });
			if (files.length + list.length > SHARE_IMAGE_LIMIT)
				setError(`Only the first ${SHARE_IMAGE_LIMIT} images were added.`);
		} catch (err) {
			setError(err.message || "Those images could not be added.");
		} finally {
			setBusy(false);
			e.target.value = "";
		}
	};
	return (
		<>
			<label className="upload-box">
				<input
					type="file"
					accept="image/jpeg,image/png,image/webp"
					multiple
					onChange={pick}
				/>
				<span className="upload-main">Add inspo images</span>
				<span className="upload-sub">
					JPG, PNG, or WebP. Up to {SHARE_IMAGE_LIMIT} images.
				</span>
			</label>
			{busy && (
				<div className="upload-help" role="status">
					Preparing images...
				</div>
			)}
			{error && (
				<div className="upload-error" role="alert">
					{error}
				</div>
			)}
			<ShareImagePreviewList
				files={files}
				onRemove={(i) => set({ shareImages: files.filter((_, idx) => idx !== i) })}
			/>
		</>
	);
}

// Light ⇆ dark theme toggle. State lives on <html data-theme>, owned by theme.js
// (loaded in <head> before paint); this just reflects/flips it and re-renders on the
// "themechange" event (so OS changes and multiple toggles stay in sync).
function ThemeToggle() {
	const [mode, setMode] = useState(
		typeof window !== "undefined" && window.__getTheme ? window.__getTheme() : "light",
	);
	useEffect(() => {
		const sync = () => setMode(window.__getTheme ? window.__getTheme() : "light");
		window.addEventListener("themechange", sync);
		return () => window.removeEventListener("themechange", sync);
	}, []);
	const dark = mode === "dark";
	return (
		<button
			type="button"
			className="theme-toggle"
			onClick={() => window.__setTheme && window.__setTheme(dark ? "light" : "dark")}
			aria-label={dark ? "Switch to light mode" : "Switch to dark mode"}
			title={dark ? "Light mode" : "Dark mode"}
		>
			{dark ? (
				<svg key="sun" viewBox="0 0 24 24" fill="none" aria-hidden="true">
					<circle cx="12" cy="12" r="4.1" fill="currentColor" />
					<g stroke="currentColor" strokeWidth="2" strokeLinecap="round">
						<path d="M12 2.6v2.3M12 19.1v2.3M2.6 12h2.3M19.1 12h2.3M5.1 5.1l1.6 1.6M17.3 17.3l1.6 1.6M18.9 5.1l-1.6 1.6M6.7 17.3l-1.6 1.6" />
					</g>
				</svg>
			) : (
				<svg key="moon" viewBox="0 0 24 24" aria-hidden="true">
					<path fill="currentColor" d="M20.2 14.6A8 8 0 0 1 9.4 3.8 6.6 6.6 0 1 0 20.2 14.6Z" />
				</svg>
			)}
		</button>
	);
}

