import type { Section, SectionActivity } from '@/admin/api/sections';
import { programActivitiesApi, sectionsApi } from '@/admin/api/sections';
import {
	AlertDialog,
	AlertDialogAction,
	AlertDialogCancel,
	AlertDialogContent,
	AlertDialogDescription,
	AlertDialogFooter,
	AlertDialogHeader,
	AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Skeleton } from '@/components/ui/skeleton';
import { cn } from '@/lib/utils';
import type { DragEndEvent } from '@dnd-kit/core';
import {
	DndContext,
	KeyboardSensor,
	PointerSensor,
	closestCenter,
	useSensor,
	useSensors,
} from '@dnd-kit/core';
import {
	SortableContext,
	arrayMove,
	sortableKeyboardCoordinates,
	useSortable,
	verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { __ } from '@wordpress/i18n';
import {
	Activity,
	ChevronDown,
	GripVertical,
	Pencil,
	Plus,
	Trash2,
} from 'lucide-react';
import { useEffect, useRef, useState } from 'react';
import { toast } from 'sonner';
import { ActivityEditorModal } from './activity-editor';

// Shared sensors hook

const useDndSensors = () =>
	useSensors(
		useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
		useSensor(KeyboardSensor, {
			coordinateGetter: sortableKeyboardCoordinates,
		}),
	);

// Sortable activity row

type SortableActivityRowProps = {
	activity: SectionActivity;
	onDelete: (id: number) => void;
	onEdit: (id: number) => void;
};

const SortableActivityRow = ({
	activity,
	onDelete,
	onEdit,
}: SortableActivityRowProps) => {
	const { id, settings, schema } = activity;
	const {
		attributes,
		listeners,
		setNodeRef,
		transform,
		transition,
		isDragging,
	} = useSortable({ id: `activity-${id}` });

	const title =
		(settings.title as string | undefined) ||
		__('Untitled Activity', 'allcoach');
	// const blockCount = schema.fields?.length ?? 0;
	const [confirmOpen, setConfirmOpen] = useState(false);

	return (
		<>
			<div
				ref={setNodeRef}
				style={{ transform: CSS.Transform.toString(transform), transition }}
				className={cn(
					'group flex items-center gap-2.5 rounded-lg border border-gray-200 bg-white px-3.5 py-2.5 transition-shadow hover:border-gray-300 hover:shadow-sm',
					isDragging && 'opacity-30 shadow-lg',
				)}
			>
				<button
					type="button"
					{...attributes}
					{...listeners}
					className="cursor-grab touch-none text-gray-300 hover:text-gray-400"
				>
					<GripVertical className="size-3.5" />
				</button>

				<button
					type="button"
					onClick={() => onEdit(id)}
					className="min-w-0 flex-1 cursor-pointer text-left"
				>
					<strong className="block truncate text-[13px] font-semibold text-gray-800 transition-colors hover:text-teal-600">
						{title}
					</strong>
					{/* <span className="text-[11px] text-gray-400">
						{blockCount} {__('blocks', 'allcoach')}
					</span> */}
				</button>

				<div className="flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
					<Button
						variant="outline"
						size="icon-xs"
						className="cursor-pointer bg-white text-gray-400 hover:border-teal-200 hover:bg-teal-50 hover:text-teal-600"
						onClick={() => onEdit(id)}
					>
						<Pencil className="size-3" />
					</Button>
					<Button
						variant="outline"
						size="icon-xs"
						className="cursor-pointer bg-white text-gray-400 hover:border-red-200 hover:bg-red-50 hover:text-red-600"
						onClick={() => setConfirmOpen(true)}
					>
						<Trash2 className="size-3" />
					</Button>
				</div>
			</div>

			<AlertDialog open={confirmOpen} onOpenChange={setConfirmOpen}>
				<AlertDialogContent>
					<AlertDialogHeader>
						<AlertDialogTitle>
							{__('Delete activity?', 'allcoach')}
						</AlertDialogTitle>
						<AlertDialogDescription>
							{__(
								'This will permanently delete the activity. This action cannot be undone.',
								'allcoach',
							)}
						</AlertDialogDescription>
					</AlertDialogHeader>
					<AlertDialogFooter>
						<AlertDialogCancel className="cursor-pointer">
							{__('Cancel', 'allcoach')}
						</AlertDialogCancel>
						<AlertDialogAction
							className="cursor-pointer bg-red-600 hover:bg-red-700"
							onClick={() => onDelete(id)}
						>
							{__('Delete', 'allcoach')}
						</AlertDialogAction>
					</AlertDialogFooter>
				</AlertDialogContent>
			</AlertDialog>
		</>
	);
};

// Sortable section block

type SortableSectionProps = {
	section: Section;
	isExpanded: boolean;
	onToggle: () => void;
	onActivitiesReorder: (
		sectionId: number,
		activities: SectionActivity[],
	) => void;
	onAddActivity: (sectionId: number) => void;
	onEditActivity: (activityId: number) => void;
	onDeleteActivity: (activityId: number) => void;
	onRenameSection: (sectionId: number, title: string) => void;
	onDeleteSection: (sectionId: number) => void;
};

const SortableSection = ({
	section,
	isExpanded,
	onToggle,
	onActivitiesReorder,
	onAddActivity,
	onEditActivity,
	onDeleteActivity,
	onRenameSection,
	onDeleteSection,
}: SortableSectionProps) => {
	const { id, activities } = section;
	const {
		attributes,
		listeners,
		setNodeRef,
		transform,
		transition,
		isDragging,
	} = useSortable({ id: `section-${id}` });

	const sensors = useDndSensors();
	const [editTitle, setEditTitle] = useState(section.title);
	const [confirmOpen, setConfirmOpen] = useState(false);
	const inputRef = useRef<HTMLInputElement>(null);

	useEffect(() => {
		setEditTitle(section.title);
	}, [section.title]);

	const commit = () => {
		const t = editTitle.trim();
		if (t && t !== section.title) onRenameSection(id, t);
		else setEditTitle(section.title);
	};

	const cancel = () => {
		setEditTitle(section.title);
		inputRef.current?.blur();
	};

	const onActivityDragEnd = ({ active, over }: DragEndEvent) => {
		if (!over || active.id === over.id) return;
		const oldIdx = activities.findIndex(
			(a) => `activity-${a.id}` === String(active.id),
		);
		const newIdx = activities.findIndex(
			(a) => `activity-${a.id}` === String(over.id),
		);
		if (oldIdx === -1 || newIdx === -1) return;
		onActivitiesReorder(id, arrayMove(activities, oldIdx, newIdx));
	};

	return (
		<div
			ref={setNodeRef}
			style={{ transform: CSS.Transform.toString(transform), transition }}
			className={cn(isDragging && 'opacity-40')}
		>
			{/* Section header */}
			<div className="group flex items-center gap-2 rounded-lg bg-[#f4f4f4] px-3 py-2.5">
				<button
					type="button"
					{...attributes}
					{...listeners}
					className="cursor-grab touch-none text-gray-400 hover:text-gray-500"
				>
					<GripVertical className="size-3.5" />
				</button>

				<div className="group/title relative flex min-w-0 flex-1 items-center">
					<Input
						ref={inputRef}
						value={editTitle}
						onChange={(e) => setEditTitle(e.target.value)}
						onKeyDown={(e) => {
							if (e.key === 'Enter') {
								e.preventDefault();
								commit();
								inputRef.current?.blur();
							}
							if (e.key === 'Escape') cancel();
						}}
						onBlur={commit}
						spellCheck={false}
						className={cn(
							'h-auto min-w-0 flex-1 cursor-pointer rounded-[5px] px-1.5 py-0.5 pe-6 transition-colors',
							'text-[13px] font-semibold text-gray-800',
							'!bg-transparent !shadow-none',
							'hover:!bg-black/5 focus:cursor-text focus:!bg-white/70',
							'!border-0 focus-visible:!border-0 focus-visible:!ring-0',
						)}
					/>
					<span className="pointer-events-none absolute end-1.5 flex items-center opacity-0 transition-opacity group-focus-within/title:opacity-0 group-hover/title:opacity-100">
						<Pencil className="size-3 text-gray-400" />
					</span>
				</div>

				<div className="flex items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100">
					<button
						type="button"
						onClick={() => setConfirmOpen(true)}
						className="flex size-6 items-center justify-center rounded-md text-gray-400 hover:bg-red-100 hover:text-red-600"
					>
						<Trash2 className="size-3" />
					</button>
				</div>

				<button
					type="button"
					onClick={onToggle}
					className="flex size-6 cursor-pointer items-center justify-center rounded-md text-gray-400 hover:bg-gray-200 hover:text-gray-700"
				>
					<ChevronDown
						className={cn(
							'size-3.5 shrink-0 transition-transform duration-200',
							isExpanded && 'rotate-180',
						)}
					/>
				</button>
			</div>

			{/* Activities (only when expanded) */}
			{isExpanded && (
				<div className="mt-2">
					<DndContext
						sensors={sensors}
						collisionDetection={closestCenter}
						onDragEnd={onActivityDragEnd}
					>
						<SortableContext
							items={activities.map((a) => `activity-${a.id}`)}
							strategy={verticalListSortingStrategy}
						>
							<div className="mb-2.5 flex flex-col gap-1.5">
								{activities.map((a) => (
									<SortableActivityRow
										key={a.id}
										activity={a}
										onEdit={onEditActivity}
										onDelete={onDeleteActivity}
									/>
								))}
							</div>
						</SortableContext>
					</DndContext>

					<Button
						variant="outline"
						size="sm"
						className="cursor-pointer rounded-[7px] border-teal-200 bg-teal-50 text-[12px] text-teal-600 hover:border-teal-600 hover:bg-teal-100"
						onClick={() => onAddActivity(id)}
					>
						<Plus className="size-3" />
						{__('Add Activity', 'allcoach')}
					</Button>
				</div>
			)}

			{/* Delete section confirm */}
			<AlertDialog open={confirmOpen} onOpenChange={setConfirmOpen}>
				<AlertDialogContent>
					<AlertDialogHeader>
						<AlertDialogTitle>
							{__('Delete section?', 'allcoach')}
						</AlertDialogTitle>
						<AlertDialogDescription>
							{__(
								'This will permanently delete the section and all its activities. This action cannot be undone.',
								'allcoach',
							)}
						</AlertDialogDescription>
					</AlertDialogHeader>
					<AlertDialogFooter>
						<AlertDialogCancel className="cursor-pointer">
							{__('Cancel', 'allcoach')}
						</AlertDialogCancel>
						<AlertDialogAction
							className="cursor-pointer bg-red-600 hover:bg-red-700"
							onClick={() => onDeleteSection(id)}
						>
							{__('Delete', 'allcoach')}
						</AlertDialogAction>
					</AlertDialogFooter>
				</AlertDialogContent>
			</AlertDialog>
		</div>
	);
};

// Main component

type ProgramActivitiesProps = { programId: string };

const ProgramActivities = ({ programId }: ProgramActivitiesProps) => {
	const pid = Number(programId);
	const queryClient = useQueryClient();
	const [editorModal, setEditorModal] = useState<{
		activityId: number;
		autoFocusTitle?: boolean;
	} | null>(null);
	const inv = () =>
		queryClient.invalidateQueries({ queryKey: ['sections', programId] });

	const { data, isLoading } = useQuery({
		queryKey: ['sections', programId],
		queryFn: () => sectionsApi.list(pid),
	});

	const [sections, setSections] = useState<Section[]>([]);
	const [expandedId, setExpandedId] = useState<number | null>(null);

	useEffect(() => {
		if (data?.sections) {
			setSections(data.sections);
			setExpandedId((prev) =>
				prev === null && data.sections.length > 0 ? data.sections[0].id : prev,
			);
		}
	}, [data]);

	const sensors = useDndSensors();

	// ── Mutations ──
	const reorderSections = useMutation({
		mutationFn: (order: number[]) => sectionsApi.reorder(pid, order),
		onSuccess: () => toast.success(__('Sections reordered.', 'allcoach')),
		onError: () => {
			inv();
			toast.error(__('Failed to reorder sections.', 'allcoach'));
		},
	});

	const reorderActivities = useMutation({
		mutationFn: ({
			sectionId,
			activityIds,
		}: {
			sectionId: number;
			activityIds: number[];
		}) => sectionsApi.reorderActivities(pid, sectionId, activityIds),
		onSuccess: () => toast.success(__('Activities reordered.', 'allcoach')),
		onError: () => {
			inv();
			toast.error(__('Failed to reorder activities.', 'allcoach'));
		},
	});

	const createSection = useMutation({
		mutationFn: (title: string) => sectionsApi.create(pid, { title }),
		onSuccess: (s) => {
			setSections((prev) => [...prev, { ...s, activities: [] }]);
			inv();
			toast.success(__('Section added.', 'allcoach'));
		},
		onError: () => toast.error(__('Failed to add section.', 'allcoach')),
	});

	const createActivity = useMutation({
		mutationFn: ({ sectionId, title }: { sectionId: number; title: string }) =>
			sectionsApi.createActivity(pid, sectionId, {
				schema: { version: '1.0', fields: [] },
				settings: { title },
			}),
		onSuccess: (activity) => {
			inv();
			setEditorModal({ activityId: activity.id, autoFocusTitle: true });
		},
		onError: () => toast.error(__('Failed to add activity.', 'allcoach')),
	});

	const deleteActivity = useMutation({
		mutationFn: (id: number) => programActivitiesApi.delete(pid, id),
		onSuccess: (_, id) => {
			setSections((prev) =>
				prev.map((s) => ({
					...s,
					activities: s.activities.filter((a) => a.id !== id),
				})),
			);
			toast.success(__('Activity deleted.', 'allcoach'));
		},
		onError: () => toast.error(__('Failed to delete activity.', 'allcoach')),
	});

	const renameSection = useMutation({
		mutationFn: ({ sectionId, title }: { sectionId: number; title: string }) =>
			sectionsApi.update(pid, sectionId, { title }),
		onSuccess: (updated) => {
			setSections((prev) =>
				prev.map((s) =>
					s.id === updated.id ? { ...s, title: updated.title } : s,
				),
			);
			toast.success(__('Section renamed.', 'allcoach'));
		},
		onError: () => {
			inv();
			toast.error(__('Failed to rename section.', 'allcoach'));
		},
	});

	const deleteSection = useMutation({
		mutationFn: (id: number) => sectionsApi.delete(pid, id),
		onSuccess: (_, id) => {
			setSections((prev) => prev.filter((s) => s.id !== id));
			toast.success(__('Section deleted.', 'allcoach'));
		},
		onError: () => toast.error(__('Failed to delete section.', 'allcoach')),
	});

	// ── Drag handlers ──
	const onSectionDragEnd = ({ active, over }: DragEndEvent) => {
		if (!over || active.id === over.id) return;
		const oldIdx = sections.findIndex(
			(s) => `section-${s.id}` === String(active.id),
		);
		const newIdx = sections.findIndex(
			(s) => `section-${s.id}` === String(over.id),
		);
		if (oldIdx === -1 || newIdx === -1) return;
		const reordered = arrayMove(sections, oldIdx, newIdx);
		setSections(reordered);
		reorderSections.mutate(reordered.map((s) => s.id));
	};

	const onActivitiesReorder = (
		sectionId: number,
		newActivities: SectionActivity[],
	) => {
		setSections((prev) =>
			prev.map((s) =>
				s.id === sectionId ? { ...s, activities: newActivities } : s,
			),
		);
		reorderActivities.mutate({
			sectionId,
			activityIds: newActivities.map((a) => a.id),
		});
	};

	// ── Add section inline ──
	const [isAddingSection, setIsAddingSection] = useState(false);
	const [newSectionTitle, setNewSectionTitle] = useState('');
	const newSectionRef = useRef<HTMLInputElement>(null);

	const handleAddSection = () => {
		const title = newSectionTitle.trim();
		if (!title) {
			newSectionRef.current?.focus();
			return;
		}
		createSection.mutate(title);
		setNewSectionTitle('');
		setIsAddingSection(false);
	};

	// ── Loading skeleton ──
	if (isLoading) {
		return (
			<div className="flex flex-col gap-4 p-6">
				{[1, 2].map((i) => (
					<div key={i}>
						<Skeleton className="mb-2 h-9 w-full rounded-lg" />
						<div className="flex flex-col gap-1.5">
							<Skeleton className="h-[52px] w-full rounded-lg" />
							<Skeleton className="h-[52px] w-full rounded-lg" />
						</div>
					</div>
				))}
			</div>
		);
	}

	// ── Empty state ──
	if (sections.length === 0 && !isAddingSection) {
		return (
			<div className="flex flex-col items-center justify-center px-6 py-16 text-center">
				<div className="mb-4 flex size-12 items-center justify-center rounded-[13px] bg-teal-50 text-teal-600">
					<Activity className="size-5" />
				</div>
				<h3 className="mb-1.5 text-[15px] font-bold text-gray-900">
					{__('No activities yet', 'allcoach')}
				</h3>
				<p className="mb-5 max-w-xs text-[13px] leading-relaxed text-gray-500">
					{__(
						'Organise your program into sections and add activities for clients to complete.',
						'allcoach',
					)}
				</p>
				<Button
					size="sm"
					className="cursor-pointer bg-teal-600 text-[13px] text-white hover:bg-teal-700"
					onClick={() => setIsAddingSection(true)}
				>
					<Plus className="size-[14px]" />
					{__('Add Section', 'allcoach')}
				</Button>
			</div>
		);
	}

	return (
		<div className="p-6">
			<DndContext
				sensors={sensors}
				collisionDetection={closestCenter}
				onDragEnd={onSectionDragEnd}
			>
				<SortableContext
					items={sections.map((s) => `section-${s.id}`)}
					strategy={verticalListSortingStrategy}
				>
					<div className="flex flex-col gap-5">
						{sections.map((section) => (
							<SortableSection
								key={section.id}
								section={section}
								isExpanded={expandedId === section.id}
								onToggle={() =>
									setExpandedId((prev) =>
										prev === section.id ? null : section.id,
									)
								}
								onActivitiesReorder={onActivitiesReorder}
								onAddActivity={(sid) => {
									createActivity.mutate({
										sectionId: sid,
										title: __('Untitled Activity', 'allcoach'),
									});
								}}
								onEditActivity={(id) => setEditorModal({ activityId: id })}
								onDeleteActivity={(id) => deleteActivity.mutate(id)}
								onRenameSection={(sid, title) =>
									renameSection.mutate({ sectionId: sid, title })
								}
								onDeleteSection={(id) => deleteSection.mutate(id)}
							/>
						))}
					</div>
				</SortableContext>
			</DndContext>

			{/* Add section inline form */}
			{isAddingSection && (
				<div className="mt-5 flex items-center gap-2 rounded-lg bg-[#f4f4f4] px-3 py-2.5">
					<GripVertical className="size-3.5 text-gray-300" />
					<Input
						ref={newSectionRef}
						autoFocus
						value={newSectionTitle}
						onChange={(e) => setNewSectionTitle(e.target.value)}
						onKeyDown={(e) => {
							if (e.key === 'Enter') handleAddSection();
							if (e.key === 'Escape') {
								setIsAddingSection(false);
								setNewSectionTitle('');
							}
						}}
						placeholder={__('Section name…', 'allcoach')}
						className="h-auto flex-1 !border-0 !bg-transparent text-[13px] font-semibold text-gray-800 !shadow-none placeholder:font-medium placeholder:text-gray-400 focus-visible:!border-0 focus-visible:!ring-0"
					/>
					<Button
						size="sm"
						className="cursor-pointer bg-teal-600 text-[12px] text-white hover:bg-teal-700"
						disabled={createSection.isPending}
						onClick={handleAddSection}
					>
						{__('Save', 'allcoach')}
					</Button>
					<Button
						size="sm"
						variant="ghost"
						className="cursor-pointer text-[12px]"
						onClick={() => {
							setIsAddingSection(false);
							setNewSectionTitle('');
						}}
					>
						{__('Cancel', 'allcoach')}
					</Button>
				</div>
			)}

			{/* Add section button */}
			{!isAddingSection && (
				<div className="mt-5">
					<Button
						size="sm"
						className="cursor-pointer rounded-[7px] bg-teal-600 text-[13px] text-white hover:bg-teal-700"
						onClick={() => setIsAddingSection(true)}
					>
						<Plus className="size-[14px]" />
						{__('Add Section', 'allcoach')}
					</Button>
				</div>
			)}

			{/* Activity editor modal */}
			<ActivityEditorModal
				programId={programId}
				activityId={editorModal?.activityId ?? null}
				open={!!editorModal}
				autoFocusTitle={editorModal?.autoFocusTitle}
				onClose={() => {
					setEditorModal(null);
					inv();
				}}
			/>
		</div>
	);
};

export default ProgramActivities;
