import { useState, useRef, useEffect, useMemo } from 'react';
import {
	CircleCheck,
	ChevronRight,
	ChevronDown,
	ArrowLeft,
	SlidersHorizontal,
	Lock,
	CircleHelp,
	ExternalLink,
	Loader2,
	History,
	UserRound,
	Undo2,
	AlertCircle,
} from 'lucide-react';
import FocusAreaIcon from '@/features/dashboard/FocusAreaIcon';
import FlavioIcon from '@/components/ui/flavio-icon';
import useTimeline, { AREA_KEYS, getAreaName } from '@/hooks/useTimeline';
import ChangeDetails from '@/features/timeline/ChangeDetails';
import { interventionInfo } from '@/features/timeline/interventions';
import { AnimatePresence, LayoutGroup } from 'motion/react';
import SiteReportEntry from '@/features/timeline/SiteReportEntry';
import SiteReportFullscreen from '@/features/timeline/SiteReportFullscreen';
import { MultipleSelect } from '@/components/ui/multiple-select';
import { Button } from '@/components/ui/button';
import ConfirmDialog from '@/components/ui/confirm-dialog';
import { isAppPaused } from '@/api/client';
import UpgradeLock from '@/features/interventions/detail/UpgradeLock';
import {
	Empty,
	EmptyHeader,
	EmptyMedia,
	EmptyTitle,
	EmptyDescription,
} from '@/components/ui/empty';
import { getErrorMessage } from '@/utils/errorMessages';
import useAnalytics from '@/hooks/analytics/useAnalytics';
import { EVENTS } from '@/lib/events';

// ---------------------------------------------------------------------------
// Sub-components
// ---------------------------------------------------------------------------

// `whatWasDone` is executor-generated prose. It's usually a short sentence, but
// some handlers (e.g. content rewrite) dump the full before/after raw content,
// which reads as a wall of markup. Collapse whitespace and clip to an excerpt;
// normal descriptions stay untouched, the verbose ones get trimmed.
const excerpt = (str, max = 280) => {
	if (typeof str !== 'string') return '';
	const collapsed = str.replace(/\s+/g, ' ').trim();
	return collapsed.length > max ? `${collapsed.slice(0, max)}…` : collapsed;
};

// A row is shown if it's a successful change, or an intervention that did NOT end
// up applied. Resolved interventions whose apply produced a success row are hidden
// (both carry the same intervention.id), so we don't duplicate the ask.
const isVisibleTask = (task, appliedInterventionIds) =>
	task.status === 'success' ||
	(task.status === 'intervention' &&
		!(
			task.intervention?.id &&
			appliedInterventionIds.has(task.intervention.id)
		));

// The executor persists a Site Status monthly report as a single execution
// under the site-status FA, with one detail whose key is "sitereport" and whose
// `result` carries the report payload. We render it as a distinct block.
const getSiteReportTask = (fa) =>
	fa.tasks?.find((t) => t.key === 'sitereport' && t.report) || null;

/** Expanded task detail: "WHAT WAS DONE" + per-handler "TECHNICAL CHANGES" */
const TaskDetail = ({ task }) => (
	<div className="mt-4 rounded-lg border border-border bg-neutral-50 p-6 space-y-5">
		<div>
			<p className="label-semibold uppercase tracking-wider text-green-600 mb-2">
				What was done
			</p>
			<p className="small-regular text-muted-foreground m-0!">
				{excerpt(task.whatWasDone)}
			</p>
		</div>

		<ChangeDetails task={task} />
	</div>
);

/** A pill summarizing an intervention outcome. */
const OutcomePill = ({ label, pending }) => (
	<span
		className={`inline-flex items-center px-2.5 py-1 rounded-md text-xs font-semibold ${
			pending ? 'bg-amber-100 text-amber-700' : 'bg-neutral-100 text-muted-foreground'
		}`}
	>
		{label}
	</span>
);

/**
 * An intervention with no resulting change: a pending ask (amber, needs action)
 * or a closed one shown for history (neutral). Approved asks aren't shown here;
 * they're folded into their success change row.
 */
const InterventionRow = ({ task, onOpenIntervention }) => {
	const { title, detail, blocking, pending, outcome } = interventionInfo(task);
	// Only pending asks have a live detail page to open; resolved/closed ones
	// bounce straight back to the list, so we don't make them clickable.
	const interventionId = task.intervention?.id;
	const clickable = pending && !!interventionId && !!onOpenIntervention;

	const body = (
		<div className="flex items-center gap-3">
			<UserRound
				className={`w-5 h-5 shrink-0 ${
					pending ? 'text-amber-500' : 'text-muted-foreground'
				}`}
			/>
			<div className="flex-1 min-w-0">
				<p className="paragraph-semibold text-foreground m-0!">
					{title}
				</p>
				{detail && (
					<p className="small-regular text-muted-foreground m-0!">
						{detail}
					</p>
				)}
			</div>
			<div className="flex items-center gap-2 shrink-0">
				{blocking && pending && (
					<span className="inline-flex items-center px-2.5 py-1 rounded-md bg-red-50 text-red-600 text-xs font-semibold">
						Blocking
					</span>
				)}
				<OutcomePill label={outcome} pending={pending} />
				{clickable && (
					<ChevronRight className="w-4 h-4 text-amber-500" />
				)}
			</div>
		</div>
	);

	const className = `rounded-lg border p-5 ${
		pending ? 'border-amber-200 bg-amber-50/40' : 'border-border bg-white'
	}`;

	if (clickable) {
		return (
			<button
				type="button"
				onClick={() => onOpenIntervention(interventionId)}
				className={`block w-full text-left transition-colors hover:bg-amber-50 cursor-pointer ${className}`}
			>
				{body}
			</button>
		);
	}

	return <div className={className}>{body}</div>;
};

/**
 * Pill that surfaces the current revert state of a successful change. Shown
 * only when the row has actually been reverted (or a revert was attempted and
 * failed). For pristine rows we render nothing here — the action lives in the
 * "Manage changes" popover.
 */
const RevertStatusPill = ({ revertStatus }) => {
	if (revertStatus === 'reverting') {
		return (
			<span className="inline-flex items-center gap-1 px-2.5 py-1 rounded-md bg-neutral-100 text-muted-foreground text-xs font-semibold">
				<Loader2 className="w-3 h-3 animate-spin" />
				Reverting…
			</span>
		);
	}
	if (revertStatus === 'reverted') {
		return (
			<span className="inline-flex items-center gap-1 px-2.5 py-1 rounded-md bg-neutral-100 text-muted-foreground text-xs font-semibold">
				<Undo2 className="w-3 h-3" />
				Reverted
			</span>
		);
	}
	if (revertStatus === 'stale') {
		return (
			<span className="inline-flex items-center gap-1 px-2.5 py-1 rounded-md bg-red-50 text-red-600 text-xs font-semibold">
				<AlertCircle className="w-3 h-3" />
				Couldn't be undone
			</span>
		);
	}
	return null;
};

/** Single task row with expand/collapse */
const TaskRow = ({ task, askedInterventionIds, onOpenIntervention }) => {
	const [expanded, setExpanded] = useState(false);

	if (task.status === 'intervention')
		return (
			<InterventionRow
				task={task}
				onOpenIntervention={onOpenIntervention}
			/>
		);
	if (task.status !== 'success') return null;

	// Only relate the change to an intervention if there's actually an
	// intervention row for it. No intervention row = autonomous change → show
	// nothing (even if an intervention object happens to be attached).
	const itv = task.intervention;
	const wasAsked = itv && askedInterventionIds?.has(itv.id);
	const relation = wasAsked
		? itv.status === 'resolved'
			? { label: 'You approved this', pending: false }
			: { label: 'Action required', pending: true }
		: null;

	return (
		<div className="rounded-lg border border-border bg-white p-5">
			<div className="flex items-center gap-3">
				<FlavioIcon className="w-5 h-5 shrink-0" />
				<div className="flex-1 min-w-0">
					<p className="paragraph-semibold text-foreground m-0!">
						{task.title}
					</p>
				</div>
				<RevertStatusPill revertStatus={task.revertStatus} />
				{relation && (
					<OutcomePill
						label={relation.label}
						pending={relation.pending}
					/>
				)}
				<button
					type="button"
					onClick={() => setExpanded(!expanded)}
					className="inline-flex items-center gap-1 px-3 py-1.5 rounded-md border border-border text-sm font-medium text-foreground hover:bg-neutral-50 transition-colors cursor-pointer shrink-0"
				>
					{expanded ? (
						'Hide'
					) : (
						<>
							View <ChevronRight className="w-3.5 h-3.5" />
						</>
					)}
				</button>
			</div>
			{expanded && <TaskDetail task={task} />}
		</div>
	);
};

/** A single revertible row inside the "Manage changes" popover (auto mode). */
const AutoRevertRow = ({ task, pending, error, disabled, onUndo }) => {
	const reverting = task.revertStatus === 'reverting' || pending;
	// Trial ended: the change can't be undone, so the Undo button is swapped for
	// the single "unlock" upgrade CTA.
	const isPaused = isAppPaused();
	return (
		<div className="mt-2 space-y-1">
			<div className="flex items-center gap-3">
				<CircleCheck className="w-4.5 h-4.5 text-green-500 shrink-0" />
				<span className="small-regular text-foreground flex-1 min-w-0">
					{task.title}
				</span>
				{reverting ? (
					<span className="inline-flex items-center gap-1 px-2.5 py-1 rounded-md bg-neutral-100 text-muted-foreground text-xs font-semibold shrink-0">
						<Loader2 className="w-3 h-3 animate-spin" />
						Reverting…
					</span>
				) : isPaused ? (
					<UpgradeLock
						size="xs"
						label="Upgrade to Undo"
						icon={<Lock className="w-3 h-3" />}
						className="shrink-0"
					/>
				) : (
					<button
						type="button"
						onClick={() => onUndo(task)}
						disabled={disabled}
						className="inline-flex items-center gap-1 px-2.5 py-1 rounded-md border border-border bg-white text-foreground text-xs font-semibold shrink-0 hover:bg-neutral-50 transition-colors cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
					>
						<Undo2 className="w-3 h-3" />
						Undo
					</button>
				)}
			</div>
			{error && (
				<p className="small-regular text-red-600 m-0! pl-7">{error}</p>
			)}
		</div>
	);
};

// Re-enable once we have a public doc page explaining the revert flow.
const SHOW_REVERT_HELP_LINK = false;

/** Manage changes popover for a Focus Area */
const ManageChanges = ({ tasks, timelineId, onRevert, onClose }) => {
	const ref = useRef(null);
	const [pendingId, setPendingId] = useState(null);
	const [errorByTaskId, setErrorByTaskId] = useState({});
	const [confirmTask, setConfirmTask] = useState(null);

	useEffect(() => {
		const handler = (e) => {
			// While the confirm dialog is open, ignore outside clicks. The
			// dialog renders in a Radix portal outside this popover's DOM, so
			// without this guard a click on "Yes, undo it" would close the
			// popover (via mousedown) before the button's onClick could run.
			if (confirmTask) return;
			if (ref.current && !ref.current.contains(e.target)) onClose();
		};
		document.addEventListener('mousedown', handler);
		return () => document.removeEventListener('mousedown', handler);
	}, [onClose, confirmTask]);

	// Only changes still revertible (or in the middle of being reverted) appear
	// here. Reverted/stale rows live on the task row itself (see
	// RevertStatusPill).
	const successTasks = tasks.filter(
		(t) =>
			t.status === 'success' &&
			(t.revertStatus === 'not_reverted' ||
				t.revertStatus === 'reverting')
	);
	const auto = successTasks.filter((t) => t.revertMode === 'auto');
	const manual = successTasks.filter((t) => t.revertMode === 'audit_only');

	const handleConfirm = async () => {
		const task = confirmTask;
		if (!task) return;
		setConfirmTask(null);
		setPendingId(task.id);
		setErrorByTaskId((prev) => ({ ...prev, [task.id]: null }));
		try {
			await onRevert(timelineId, task.id);
		} catch (err) {
			setErrorByTaskId((prev) => ({
				...prev,
				[task.id]: getErrorMessage(
					err,
					"I couldn't undo this change. Please try again."
				),
			}));
		} finally {
			setPendingId(null);
		}
	};

	return (
		<div
			ref={ref}
			className="absolute right-0 top-full mt-2 z-50 w-100 rounded-lg border border-border bg-white shadow-lg p-5 space-y-4"
		>
			{/* Header */}
			<div className="flex items-center justify-between">
				<h4 className="heading-h4 text-foreground m-0!">
					Manage changes
				</h4>
				<button
					type="button"
					onClick={onClose}
					className="inline-flex items-center px-3 py-1.5 rounded-md border border-border text-sm font-medium text-foreground hover:bg-neutral-50 transition-colors cursor-pointer"
				>
					Hide
				</button>
			</div>

			{/* Empty state once everything's been reverted */}
			{auto.length === 0 && manual.length === 0 && (
				<p className="small-regular text-muted-foreground m-0!">
					Nothing left to manage. All changes here have already been
					reverted.
				</p>
			)}

			{/* Can be reverted automatically */}
			{auto.length > 0 && (
				<div className="space-y-2.5">
					<p className="label-semibold uppercase tracking-wider text-green-600 m-0!">
						Can be reverted
					</p>
					{auto.map((task) => (
						<AutoRevertRow
							key={task.id}
							task={task}
							pending={pendingId === task.id}
							error={errorByTaskId[task.id]}
							disabled={pendingId !== null}
							onUndo={setConfirmTask}
						/>
					))}
				</div>
			)}

			{/* Requires manual revert */}
			{manual.length > 0 && (
				<div className="space-y-2.5">
					<p className="label-semibold uppercase tracking-wider text-muted-foreground m-0!">
						Requires manual revert
					</p>
					{manual.map((task) => (
						<div
							key={task.id}
							className="flex items-center gap-3 mt-2"
						>
							<Lock className="w-4.5 h-4.5 text-muted-foreground shrink-0" />
							<span className="small-regular text-muted-foreground flex-1 min-w-0">
								{task.title}
							</span>
							<span className="inline-flex items-center px-2.5 py-1 rounded-md bg-neutral-100 text-muted-foreground text-xs font-semibold shrink-0">
								Manual
							</span>
						</div>
					))}
				</div>
			)}

			{SHOW_REVERT_HELP_LINK && (
				<div className="pt-1 border-t border-border">
					<button
						type="button"
						className="inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors cursor-pointer bg-transparent border-0 p-0 mt-2"
					>
						<CircleHelp className="w-4 h-4" />
						<span>How does reverting work?</span>
						<ExternalLink className="w-3.5 h-3.5" />
					</button>
				</div>
			)}

			<ConfirmDialog
				open={confirmTask !== null}
				onOpenChange={(open) => {
					if (!open) setConfirmTask(null);
				}}
				title="Undo this change?"
				description={
					confirmTask
						? `I'll revert "${confirmTask.title}" on your site. This can't be undone.`
						: undefined
				}
				confirmLabel="Yes, undo it"
				cancelLabel="Keep it"
				onConfirm={handleConfirm}
			/>
		</div>
	);
};

/** A Focus Area entry in the timeline */
const TimelineEntry = ({
	fa,
	defaultExpanded = false,
	entryRef,
	appliedInterventionIds,
	askedInterventionIds,
	onRevert,
	onOpenIntervention,
}) => {
	const [expanded, setExpanded] = useState(defaultExpanded);
	const [showManage, setShowManage] = useState(false);
	const { track } = useAnalytics();

	const visibleTasks =
		fa.tasks?.filter((t) => isVisibleTask(t, appliedInterventionIds)) || [];
	// "Manage changes" surfaces revertible successes — once everything has been
	// reverted (or there's nothing revertible to begin with), the button goes
	// away. Audit-only rows still show up here so users can learn how to revert
	// them manually.
	const hasChanges =
		fa.tasks?.some(
			(t) =>
				t.status === 'success' &&
				(t.revertMode === 'auto' || t.revertMode === 'audit_only') &&
				(t.revertStatus === 'not_reverted' ||
					t.revertStatus === 'reverting')
		) || false;

	return (
		<div ref={entryRef} className="relative flex items-start gap-5 mb-10">
			{/* Icon on the timeline */}
			<div className="relative z-10 shrink-0 mt-4">
				<FocusAreaIcon icon={fa.icon} color={fa.color} size="md" />
			</div>

			{/* Card */}
			<div className="flex-1 min-w-0">
				<div className="rounded-lg border border-border shadow-sm bg-card p-6">
					{/* Header */}
					<div className="flex items-start justify-between gap-4">
						<div>
							<h3 className="heading-h3 text-foreground mb-1">
								{fa.title}
							</h3>
							<p className="small-regular text-muted-foreground m-0!">
								{fa.isCurrent
									? 'Current activity'
									: fa.completedAt
										? new Date(fa.completedAt).toLocaleDateString('en-US', {
												month: 'short',
												day: 'numeric',
											})
										: ''}
							</p>
						</div>
						<div className="flex items-center gap-2 relative shrink-0">
							{hasChanges && (
								<>
									<button
										type="button"
										onClick={() =>
											setShowManage(!showManage)
										}
										className="inline-flex items-center gap-2 px-4 py-2 rounded-md border border-border text-sm font-medium text-foreground hover:bg-neutral-50 transition-colors cursor-pointer"
									>
										<SlidersHorizontal className="w-4 h-4" />
										Manage changes
									</button>
									{showManage && (
										<ManageChanges
											tasks={fa.tasks}
											timelineId={fa.id}
											onRevert={onRevert}
											onClose={() =>
												setShowManage(false)
											}
										/>
									)}
								</>
							)}
							{visibleTasks.length > 0 && (
								<button
									type="button"
									onClick={() => {
										if (!expanded) {
											track(
												EVENTS.RECOMMENDATION_CARD_VIEWED,
												{
													focus_area_id: fa.id,
													focus_area: fa.title,
												}
											);
										}
										setExpanded(!expanded);
									}}
									className="inline-flex items-center px-4 py-2 rounded-md border border-border text-sm font-medium text-foreground hover:bg-neutral-50 transition-colors cursor-pointer"
								>
									{expanded ? 'Hide' : 'Details >'}
								</button>
							)}
						</div>
					</div>

					{/* Expanded tasks */}
					{expanded && (
						<div className="mt-6 space-y-3">
							{visibleTasks.map((task) => (
								<TaskRow
									key={task.id}
									task={task}
									askedInterventionIds={askedInterventionIds}
									onOpenIntervention={onOpenIntervention}
								/>
							))}
						</div>
					)}
				</div>
			</div>
		</div>
	);
};

// ---------------------------------------------------------------------------
// Main component
// ---------------------------------------------------------------------------

/**
 * TimelinePage
 *
 * Chronological view of all Focus Area activity.
 * Fetches data from GET /timeline and groups by date.
 */
const TimelinePage = ({
	onBack,
	transition,
	focusedFaId,
	onOpenIntervention,
	expandedReportId,
	onOpenReport,
	onCloseReport,
}) => {
	const {
		groups,
		loading,
		error,
		hasMore,
		loadMore,
		loadingMore,
		selectedAreas,
		setSelectedAreas,
		isEmpty,
		retry,
		revertDetail,
	} = useTimeline();
	const focusedRef = useRef(null);

	useEffect(() => {
		if (focusedFaId && !loading && focusedRef.current) {
			setTimeout(() => {
				focusedRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });
			}, 600);
		}
	}, [focusedFaId, loading]);

	// Two sets, across all loaded executions:
	// - applied: interventions that produced a success row (hide the ask dup).
	// - asked: interventions that actually have an intervention row. A success
	//   only shows a relation when its intervention was really asked; otherwise
	//   it's an autonomous change and we show nothing.
	const { appliedInterventionIds, askedInterventionIds } = useMemo(() => {
		const applied = new Set();
		const asked = new Set();
		for (const group of groups) {
			for (const fa of group.entries) {
				for (const task of fa.tasks || []) {
					const id = task.intervention?.id;
					if (!id) continue;
					if (task.status === 'success') applied.add(id);
					if (task.status === 'intervention') asked.add(id);
				}
			}
		}
		return { appliedInterventionIds: applied, askedInterventionIds: asked };
	}, [groups]);

	// Resolve the report payload for the currently expanded execution (if any).
	// The modal is mounted only when both the URL flag and the data are present;
	// otherwise (deep-link before data loads, stale id) we silently skip. The
	// React Compiler memoizes this for us, so no useMemo wrapper.
	const expandedReportTask = (() => {
		if (!expandedReportId) return null;
		for (const group of groups) {
			for (const fa of group.entries) {
				if (String(fa.id) !== String(expandedReportId)) continue;
				return getSiteReportTask(fa);
			}
		}
		return null;
	})();

	const animationClass =
		transition === 'timeline-enter'
			? 'animate-slide-in-from-bottom'
			: transition === 'timeline-exit'
				? 'animate-slide-out-to-bottom'
				: '';

	if (loading && groups.length === 0) {
		return (
			<main className="flex-1 overflow-y-auto pt-12 pb-24">
				<div className="max-w-4xl mx-auto px-8">
					<div className="flex items-center gap-4">
						<div className="w-12 h-12 rounded-full bg-neutral-100 animate-pulse" />
						<div className="h-8 w-64 bg-neutral-100 rounded animate-pulse" />
					</div>
				</div>
			</main>
		);
	}

	return (
		<main className={`flex-1 overflow-y-auto pt-12 pb-24 ${animationClass}`}>
			<LayoutGroup>
			<div className="max-w-4xl mx-auto px-8">
				{/* Back link */}
				<button
					type="button"
					onClick={onBack}
					className="inline-flex items-center gap-1.5 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors cursor-pointer mb-6"
				>
					<ArrowLeft className="w-4 h-4" />
					Back
				</button>

				{/* Page header + area filter */}
				<div className="mb-12 flex items-start justify-between gap-4">
					<header>
						<h1 className="heading-h1 mb-2">What I've been up to</h1>
						<p className="paragraph-regular text-muted-foreground m-0!">
							A log of everything I've done on your site.
						</p>
					</header>
					<div className="w-64 shrink-0 mt-2">
						<MultipleSelect
							value={selectedAreas}
							options={AREA_KEYS}
							onChange={setSelectedAreas}
							getLabel={getAreaName}
							placeholder="All areas"
						/>
					</div>
				</div>

				{error ? (
					/* Error state */
					<div className="p-6 bg-destructive/10 border border-destructive/20 rounded-lg text-center">
						<p className="paragraph-regular text-destructive mb-4">
							{getErrorMessage(
								error,
								"I couldn't load your activity right now."
							)}
						</p>
						<Button onClick={retry}>Try again</Button>
					</div>
				) : isEmpty ? (
					/* Empty state */
					<Empty>
						<EmptyHeader>
							<EmptyMedia variant="icon">
								<History className="size-5" />
							</EmptyMedia>
							<EmptyTitle>
								{selectedAreas.length > 0
									? 'No activity for these areas'
									: 'Nothing here yet'}
							</EmptyTitle>
							<EmptyDescription>
								{selectedAreas.length > 0
									? 'Try removing some filters to see more activity.'
									: "As I work on your site, everything I do will show up here."}
							</EmptyDescription>
						</EmptyHeader>
					</Empty>
				) : (
					<>
						{/* Timeline */}
						<div className="relative">
							{/* Vertical line */}
							<div className="absolute left-5 top-0 bottom-0 w-px bg-neutral-200" />

							{groups.map((group) => (
								<div key={group.label}>
									{/* Date badge */}
									<div className="relative z-10 mb-8 ml-1">
										<span className="inline-flex items-center px-3 py-1 bg-white border border-neutral-200 rounded-full text-xs font-bold text-foreground tracking-wide">
											{group.label}
										</span>
									</div>

									{/* Entries */}
									{group.entries.map((fa) => {
										const reportTask = getSiteReportTask(fa);
										const entryRef =
											fa.key === focusedFaId
												? focusedRef
												: undefined;
										if (reportTask) {
											return (
												<SiteReportEntry
													key={fa.id}
													fa={fa}
													report={reportTask.report}
													entryRef={entryRef}
													onOpenIntervention={
														onOpenIntervention
													}
													onExpand={onOpenReport}
												/>
											);
										}
										return (
											<TimelineEntry
												key={fa.id}
												fa={fa}
												defaultExpanded={fa.key === focusedFaId}
												entryRef={entryRef}
												appliedInterventionIds={
													appliedInterventionIds
												}
												askedInterventionIds={
													askedInterventionIds
												}
												onRevert={revertDetail}
												onOpenIntervention={
													onOpenIntervention
												}
											/>
										);
									})}
								</div>
							))}
						</div>

						{/* Load older */}
						{hasMore && (
							<div className="relative z-10 ml-1 mt-2">
								<button
									type="button"
									onClick={loadMore}
									disabled={loadingMore}
									className="inline-flex items-center gap-1.5 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors cursor-pointer disabled:opacity-50"
								>
									{loadingMore ? (
										<>
											<Loader2 className="w-4 h-4 animate-spin" />
											Loading...
										</>
									) : (
										<>
											Load older activity
											<ChevronDown className="w-4 h-4" />
										</>
									)}
								</button>
							</div>
						)}
					</>
				)}
			</div>

			{/* Expanded report modal. AnimatePresence keeps the modal mounted
			    during its exit transition so motion can morph the panel back
			    into the source card via the shared `layoutId`. */}
			<AnimatePresence>
				{expandedReportTask && expandedReportId && (
					<SiteReportFullscreen
						key={expandedReportId}
						report={expandedReportTask.report}
						reportId={expandedReportId}
						onClose={onCloseReport}
						onOpenIntervention={onOpenIntervention}
					/>
				)}
			</AnimatePresence>
			</LayoutGroup>
		</main>
	);
};

export default TimelinePage;
