import React, { useEffect, useId, useMemo, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { Alert, Button, IconButton, Skeleton, SkeletonGroup, UIProvider } from '../../shared/ui';
import BookingApp, { BookingDialog } from './BookingApp';
import ConfirmationStep from './components/ConfirmationStep';
import { api, isSlotTaken } from './api';
import { brandTheme } from './config';

const num = (v) => Number(v) || null;

function presetsFrom(el) {
	const d = el.dataset;
	return {
		serviceId: num(d.bpServiceId),
		categoryId: num(d.bpCategoryId),
		agentId: num(d.bpAgentId),
		locationId: num(d.bpLocationId),
		date: /^\d{4}-\d{2}-\d{2}$/.test(d.bpDefaultDate || '') ? d.bpDefaultDate : null,
		hideNotes: d.bpHideNotes === '1',
		requirePhone: d.bpRequirePhone === '1',
		compact: d.bpCompact === '1',
	};
}

/**
 * [pointlybooking_booking_form] / booking-form block.
 *
 * mode "inline": the wizard is part of the page.
 * mode "button": a button (rendered by PHP, or here for older markup) opens the
 * wizard in a dialog. Any element with data-bp-open="wizard" also opens it.
 */
export default function Widget({ el }) {
	const mode = el.dataset.bpMode === 'inline' ? 'inline' : 'button';
	const label = el.dataset.bpLabel || __('Book Now', 'pointly-booking');
	const presets = useMemo(() => presetsFrom(el), [el]);
	const theme = useMemo(() => brandTheme(), []);
	const [open, setOpen] = useState(el.dataset.bpAutoOpen === '1');
	const headingId = `bp-bw-h-${useId().replace(/:/g, '')}`;
	const needsOwnButton = mode === 'button' && el.dataset.bpFallback !== '1' && el.dataset.bpAutoOpen !== '1';

	useEffect(() => {
		el.__bpOpen = () => setOpen(true);
		return () => {
			delete el.__bpOpen;
		};
	}, [el]);

	return (
		<UIProvider dark={theme.dark} vars={theme.vars}>
			{mode === 'inline' ? (
				<BookingApp presets={presets} />
			) : (
				<>
					{needsOwnButton ? (
						<Button variant="primary" size="lg" className="bp-book-btn" onClick={() => setOpen(true)}>
							{label}
						</Button>
					) : null}
					<BookingDialog open={open} onClose={() => setOpen(false)} labelledBy={headingId}>
						<BookingApp presets={presets} headingId={headingId} onClose={() => setOpen(false)} className={presets.compact ? 'bp-bw--compact' : ''} />
					</BookingDialog>
				</>
			)}
		</UIProvider>
	);
}

/* -------------------------------------------------------------------------
 * Back from a hosted checkout (Stripe Checkout / PayPal)
 * ---------------------------------------------------------------------- */

function cleanReturnUrl() {
	const url = new URL(window.location.href);
	['pointlybooking_payment', 'booking_id', 'key', 'token', 'PayerID', 'payment_intent', 'payment_intent_client_secret', 'redirect_status'].forEach((k) =>
		url.searchParams.delete(k)
	);
	return url.toString();
}

function readReturn() {
	const p = new URLSearchParams(window.location.search);
	const flag = p.get('pointlybooking_payment') || '';
	return {
		flag,
		id: Number(p.get('booking_id')) || 0,
		key: p.get('key') || '',
		token: p.get('token') || '',
		method: flag.startsWith('paypal') ? 'paypal' : 'stripe',
		cancelled: flag.endsWith('_cancel'),
	};
}

export function PaymentReturn() {
	const theme = useMemo(() => brandTheme(), []);
	const ret = useMemo(readReturn, []);
	const headingId = `bp-bw-h-${useId().replace(/:/g, '')}`;
	const [open, setOpen] = useState(true);
	const [state, setState] = useState({ phase: 'working', error: '' });

	useEffect(() => {
		let alive = true;
		(async () => {
			try {
				if (ret.cancelled) {
					await api.paymentCancel(ret.id, ret.key).catch(() => {});
					if (alive) setState({ phase: 'cancelled', error: '' });
				} else if (ret.method === 'paypal') {
					if (!ret.token) {
						await api.paymentCancel(ret.id, ret.key).catch(() => {});
						if (alive) setState({ phase: 'cancelled', error: '' });
					} else {
						await api.paypalCapture({ orderId: ret.token, bookingId: ret.id, key: ret.key });
						if (alive) setState({ phase: 'done', error: '' });
					}
				} else if (alive) {
					setState({ phase: 'done', error: '' });
				}
			} catch (e) {
				if (alive) setState({ phase: 'error', error: e.message, slotTaken: isSlotTaken(e) });
			}
			// The flag must not survive a reload (it would replay the result).
			try {
				window.history.replaceState({}, '', cleanReturnUrl());
			} catch (e) {
				// Non-critical.
			}
		})();
		return () => {
			alive = false;
		};
	}, [ret]);

	const close = () => setOpen(false);
	const startOver = () => window.location.assign(cleanReturnUrl());

	let content;
	if (state.phase === 'working') {
		content = (
			<SkeletonGroup label={__('Confirming your payment…', 'pointly-booking')} className="bp-bw-confirm__loading">
				<Skeleton height={64} circle width={64} />
				<Skeleton height={28} width="60%" />
				<Skeleton height={120} />
			</SkeletonGroup>
		);
	} else if (state.phase === 'cancelled') {
		content = (
			<div className="bp-bw-confirm">
				<Alert tone="warning" title={__('Payment cancelled', 'pointly-booking')}>
					{__('No money was taken and your time is no longer being held. You can start a new booking whenever you like.', 'pointly-booking')}
				</Alert>
				<div className="bp-bw-confirm__actions">
					<Button variant="primary" onClick={startOver}>
						{__('Book again', 'pointly-booking')}
					</Button>
					<Button variant="ghost" onClick={close}>
						{__('Close', 'pointly-booking')}
					</Button>
				</div>
			</div>
		);
	} else if (state.phase === 'error') {
		content = (
			<div className="bp-bw-confirm">
				<Alert tone="danger" live title={state.slotTaken ? __('That time is no longer available', 'pointly-booking') : __('We could not complete your payment', 'pointly-booking')}>
					{state.error}
				</Alert>
				<div className="bp-bw-confirm__actions">
					<Button variant="primary" onClick={startOver}>
						{__('Book again', 'pointly-booking')}
					</Button>
					<Button variant="ghost" onClick={close}>
						{__('Close', 'pointly-booking')}
					</Button>
				</div>
			</div>
		);
	} else {
		content = <ConfirmationStep id={ret.id} method={ret.method} bookingKey={ret.key} onAnother={startOver} onClose={close} onRetryPayment={startOver} />;
	}

	return (
		<UIProvider dark={theme.dark} vars={theme.vars}>
			<BookingDialog open={open} onClose={close} labelledBy={headingId}>
				<div className="bp-bw bp-bw--modal bp-bw--return">
					<header className="bp-bw__header">
						<div className="bp-bw__titles">
							<h2 className="bp-bw__title" id={headingId} tabIndex={-1}>
								{__('Your booking', 'pointly-booking')}
							</h2>
						</div>
						<IconButton icon="x" label={__('Close', 'pointly-booking')} variant="ghost" onClick={close} />
					</header>
					<div className="bp-bw__content">
						<div className="bp-bw__main">{content}</div>
					</div>
				</div>
			</BookingDialog>
		</UIProvider>
	);
}
