/**
 * Side-by-side current vs proposed template update preview.
 */
import { createPortal, useEffect, useMemo, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { api } from '../api';
import PreviewFrame from './PreviewFrame';
import { renderPreview } from './PreviewModal';
import Notice from './ui/Notice';

function ChangeList( { changes } ) {
	if ( ! changes?.length ) {
		return null;
	}

	return (
		<ul className="m-0 list-none space-y-2 p-0">
			{ changes.map( ( change, i ) => (
				<li
					key={ `${ change.type }-${ i }` }
					className="rounded-[10px] border border-outline-variant/25 bg-surface-low px-3 py-2.5"
				>
					<strong className="block text-[13px] text-on-surface">
						{ change.label }
					</strong>
					{ change.detail ? (
						<p className="m-0 mt-1 text-[12px] text-on-surface-variant">
							{ change.detail }
						</p>
					) : null }
					{ change.added?.length ? (
						<p className="m-0 mt-1 text-[12px] text-success-accent">
							{ __( 'Added:', 'joc-blockora-morph' ) }{ ' ' }
							{ change.added.join( ', ' ) }
						</p>
					) : null }
					{ change.removed?.length ? (
						<p className="m-0 mt-1 text-[12px] text-red-600">
							{ __( 'Removed:', 'joc-blockora-morph' ) }{ ' ' }
							{ change.removed.join( ', ' ) }
						</p>
					) : null }
				</li>
			) ) }
		</ul>
	);
}

export default function TemplateUpdateModal( {
	blockId,
	blockName,
	onClose,
	onApplied,
} ) {
	const [ diff, setDiff ] = useState( null );
	const [ loading, setLoading ] = useState( true );
	const [ applying, setApplying ] = useState( false );
	const [ error, setError ] = useState( '' );
	const [ viewport, setViewport ] = useState( 'desktop' );

	useEffect( () => {
		let cancelled = false;
		setLoading( true );
		setError( '' );
		api
			.get( `/user-blocks/${ blockId }/template-diff` )
			.then( ( res ) => {
				if ( ! cancelled ) {
					setDiff( res );
				}
			} )
			.catch( ( e ) => {
				if ( ! cancelled ) {
					setError(
						e?.message ||
							__( 'Could not load template comparison.', 'joc-blockora-morph' )
					);
				}
			} )
			.finally( () => {
				if ( ! cancelled ) {
					setLoading( false );
				}
			} );
		return () => {
			cancelled = true;
		};
	}, [ blockId ] );

	useEffect( () => {
		const onKey = ( e ) => {
			if ( e.key === 'Escape' && ! applying ) {
				onClose();
			}
		};
		const prevOverflow = document.body.style.overflow;
		document.body.style.overflow = 'hidden';
		window.addEventListener( 'keydown', onKey );
		return () => {
			document.body.style.overflow = prevOverflow;
			window.removeEventListener( 'keydown', onKey );
		};
	}, [ onClose, applying ] );

	const currentPreview = useMemo(
		() =>
			diff
				? renderPreview(
						diff.current.markup,
						diff.current.defaultAttrs,
						diff.current.cssVars
				  )
				: { __html: '' },
		[ diff ]
	);

	const proposedPreview = useMemo(
		() =>
			diff
				? renderPreview(
						diff.proposed.markup,
						diff.proposed.defaultAttrs,
						diff.proposed.cssVars
				  )
				: { __html: '' },
		[ diff ]
	);

	const apply = async () => {
		setApplying( true );
		setError( '' );
		try {
			await api.post( `/user-blocks/${ blockId }/sync-template`, {} );
			onApplied?.();
			onClose();
		} catch ( e ) {
			setError(
				e?.message || __( 'Could not update template.', 'joc-blockora-morph' )
			);
			setApplying( false );
		}
	};

	const portalTarget =
		document.getElementById( 'joc-blockora-morph-app' ) || document.body;
	const title = diff?.name || blockName || __( 'Block', 'joc-blockora-morph' );

	return createPortal(
		<div
			className="bm-modal-root bm-fade fixed inset-0 z-[100000] flex items-center justify-center p-4 font-sans sm:p-6"
			role="dialog"
			aria-modal="true"
			aria-labelledby="bm-template-update-title"
		>
			<div
				className="bm-modal-backdrop"
				onClick={ applying ? undefined : onClose }
			/>
			<div className="bm-rise relative z-10 flex h-[min(920px,94vh)] w-full max-w-[1440px] flex-col overflow-hidden rounded-xl border border-outline-variant/30 bg-surface-lowest shadow-card">
				<header className="flex shrink-0 items-start justify-between gap-4 border-b border-outline-variant/20 px-5 py-4">
					<div>
						<p className="mb-1 text-caps-micro font-bold uppercase tracking-widest text-outline">
							{ __( 'Template update', 'joc-blockora-morph' ) }
						</p>
						<h2
							id="bm-template-update-title"
							className="m-0 text-headline-lg text-on-surface"
						>
							{ title }
						</h2>
						<p className="mt-1 mb-0 text-body-md text-on-surface-variant">
							{ __(
								'Compare your current block with the library update before applying.',
								'joc-blockora-morph'
							) }
						</p>
					</div>
					<button
						type="button"
						className="bm-btn bm-btn--ghost shrink-0"
						onClick={ onClose }
						disabled={ applying }
					>
						{ __( 'Close', 'joc-blockora-morph' ) }
					</button>
				</header>

				<div className="grid min-h-0 flex-1 grid-cols-1 lg:grid-cols-[minmax(0,1fr)_300px]">
					<div className="min-h-0 overflow-auto bg-surface-low p-4 sm:p-5">
						{ loading && (
							<p className="m-0 text-body-md text-on-surface-variant">
								{ __( 'Loading comparison…', 'joc-blockora-morph' ) }
							</p>
						) }

						{ ! loading && diff && (
							<div className="grid grid-cols-1 gap-4 xl:grid-cols-2">
								<section className="min-w-0 rounded-[12px] border border-outline-variant/25 bg-surface-lowest">
									<div className="border-b border-outline-variant/20 px-4 py-3">
										<p className="m-0 text-caps-micro font-bold uppercase tracking-widest text-outline">
											{ __( 'Current', 'joc-blockora-morph' ) }
										</p>
										<p className="m-0 mt-1 text-[13px] text-on-surface-variant">
											{ __(
												'What imported blocks use today',
												'joc-blockora-morph'
											) }
										</p>
									</div>
									<PreviewFrame
										html={ currentPreview }
										viewport={ viewport }
										onViewportChange={ setViewport }
										showLabel={ false }
										minHeight={ 280 }
										className="border-0"
									/>
								</section>
								<section className="min-w-0 rounded-[12px] border border-primary/25 bg-surface-lowest">
									<div className="border-b border-primary/15 bg-primary/5 px-4 py-3">
										<p className="m-0 text-caps-micro font-bold uppercase tracking-widest text-primary">
											{ __( 'After update', 'joc-blockora-morph' ) }
										</p>
										<p className="m-0 mt-1 text-[13px] text-on-surface-variant">
											{ __(
												'Library template with your overrides kept',
												'joc-blockora-morph'
											) }
										</p>
									</div>
									<PreviewFrame
										html={ proposedPreview }
										viewport={ viewport }
										onViewportChange={ setViewport }
										showLabel={ false }
										minHeight={ 280 }
										className="border-0"
									/>
								</section>
							</div>
						) }
					</div>

					<aside className="flex min-h-0 flex-col gap-4 border-t border-outline-variant/20 p-5 lg:border-l lg:border-t-0">
						<div>
							<p className="m-0 text-caps-micro font-bold uppercase tracking-widest text-outline">
								{ __( 'What changes', 'joc-blockora-morph' ) }
							</p>
							<div className="mt-3">
								{ loading ? (
									<p className="m-0 text-body-md text-on-surface-variant">
										…
									</p>
								) : (
									<ChangeList changes={ diff?.changes || [] } />
								) }
							</div>
						</div>

						{ diff?.notes?.length ? (
							<div className="rounded-[10px] border border-outline-variant/25 bg-surface-low px-3 py-2.5">
								<p className="m-0 text-[12px] font-semibold text-on-surface">
									{ __( 'Keep in mind', 'joc-blockora-morph' ) }
								</p>
								<ul className="mb-0 mt-2 list-disc space-y-1 pl-4 text-[12px] text-on-surface-variant">
									{ diff.notes.map( ( note, i ) => (
										<li key={ i }>{ note }</li>
									) ) }
								</ul>
							</div>
						) : null }

						{ error ? (
							<Notice variant="danger">{ error }</Notice>
						) : null }

						<div className="mt-auto flex flex-col gap-2">
							<button
								type="button"
								className="bm-btn bm-btn--primary bm-btn--block"
								onClick={ apply }
								disabled={ loading || applying || ! diff }
							>
								{ applying
									? __( 'Updating…', 'joc-blockora-morph' )
									: __( 'Apply update', 'joc-blockora-morph' ) }
							</button>
							<button
								type="button"
								className="bm-btn bm-btn--ghost bm-btn--block"
								onClick={ onClose }
								disabled={ applying }
							>
								{ __( 'Cancel', 'joc-blockora-morph' ) }
							</button>
						</div>
					</aside>
				</div>
			</div>
		</div>,
		portalTarget
	);
}
