import type {
	Appointment,
	AppointmentBulkAction,
	AppointmentStatus,
	CreateAppointmentData,
} from '@/admin/api/appointments';
import { appointmentsApi } from '@/admin/api/appointments';
import { availabilitiesApi } from '@/admin/api/availabilities';
import { clientsApi } from '@/admin/api/clients';
import { enrollmentsApi } from '@/admin/api/enrollments';
import { GoogleIntegrationAlert } from '@/admin/components/google-integration-alert';
import { appointmentsQuery } from '@/admin/queries/appointments';
import { DataTable } from '@/components/table';
import {
	AlertDialog,
	AlertDialogAction,
	AlertDialogCancel,
	AlertDialogContent,
	AlertDialogDescription,
	AlertDialogFooter,
	AlertDialogHeader,
	AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { BulkActionBar } from '@/components/ui/bulk-action-bar';
import { Button, buttonVariants } from '@/components/ui/button';
import { Calendar } from '@/components/ui/calendar';
import {
	Dialog,
	DialogContent,
	DialogFooter,
	DialogHeader,
	DialogTitle,
} from '@/components/ui/dialog';
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
	InputGroup,
	InputGroupAddon,
	InputGroupInput,
} from '@/components/ui/input-group';
import { Label } from '@/components/ui/label';
import {
	Popover,
	PopoverContent,
	PopoverTrigger,
} from '@/components/ui/popover';
import {
	Select,
	SelectContent,
	SelectGroup,
	SelectItem,
	SelectTrigger,
	SelectValue,
} from '@/components/ui/select';
import { Spinner } from '@/components/ui/spinner';
import { Textarea } from '@/components/ui/textarea';
import {
	Tooltip,
	TooltipContent,
	TooltipTrigger,
} from '@/components/ui/tooltip';
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
import { cn } from '@/lib/utils';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { getRouteApi } from '@tanstack/react-router';
import { createColumnHelper } from '@tanstack/react-table';
import { dateI18n, getSettings } from '@wordpress/date';
import { __, sprintf } from '@wordpress/i18n';
import {
	AlertTriangle,
	CalendarIcon,
	CheckCircle2,
	EyeIcon,
	MoreVertical,
	Plus,
	SearchIcon,
	Trash2,
	Video,
	X,
	XCircle,
} from 'lucide-react';
import { useEffect, useState } from 'react';
import type { DateRange } from 'react-day-picker';
import { toast } from 'sonner';

const routeApi = getRouteApi('/_app/appointments/');

const ADD_APPOINTMENT_DEFAULTS = {
	client_id: '',
	enrollment_id: '',
	scheduled_date: '',
	start_time: '',
	end_time: '',
	notes: '',
};

const col = createColumnHelper<Appointment>();

const STATUS_LABELS: Record<AppointmentStatus, string> = {
	scheduled: __('Scheduled', 'allcoach'),
	completed: __('Completed', 'allcoach'),
	cancelled: __('Cancelled', 'allcoach'),
	no_show: __('No Show', 'allcoach'),
};

function extractErrorMessage(error: unknown, fallback: string): string {
	const err = error as any;
	const validationError =
		err?.code === 'allcoach_validation_error' &&
		Object.values<string>(err?.data?.additional_data?.errors ?? {})[0];
	return validationError
		? (new DOMParser().parseFromString(validationError, 'text/html').body
				.textContent ?? validationError)
		: err?.message || fallback;
}

const STATUS_STYLES: Record<AppointmentStatus, string> = {
	scheduled: 'bg-teal-50 text-teal-700 border-teal-200',
	completed: 'bg-gray-100 text-gray-600 border-gray-200',
	cancelled: 'bg-red-50 text-red-600 border-red-200',
	no_show: 'bg-orange-50 text-orange-600 border-orange-200',
};

function formatDateRange(range: DateRange): string {
	const fmt = (d: Date) =>
		dateI18n(getSettings().formats.date, d.toISOString());
	if (range.from && range.to) return `${fmt(range.from)} – ${fmt(range.to)}`;
	if (range.from) return fmt(range.from);
	return '';
}

const toDateStr = (d: Date) => d.toISOString().split('T')[0];

const Appointments = () => {
	const queryClient = useQueryClient();
	const navigate = routeApi.useNavigate();
	const search = routeApi.useSearch();

	const [calendarOpen, setCalendarOpen] = useState(false);
	const [selectedAppointments, setSelectedAppointments] = useState<
		Appointment[]
	>([]);
	const [resetSelectionKey, setResetSelectionKey] = useState(0);
	const [viewTarget, setViewTarget] = useState<Appointment | null>(null);
	const [cancelTargetId, setCancelTargetId] = useState<number | null>(null);
	const [addDialogOpen, setAddDialogOpen] = useState(false);
	const [addForm, setAddForm] = useState(ADD_APPOINTMENT_DEFAULTS);
	const [searchInput, setSearchInput] = useState(search.search);
	const debouncedSearch = useDebouncedValue(searchInput);

	useEffect(() => {
		setSearchInput(search.search);
	}, [search.search]);

	useEffect(() => {
		if (debouncedSearch !== search.search) {
			setFilter({ search: debouncedSearch });
		}
	}, [debouncedSearch]);

	const setFilter = (updates: Partial<typeof search>) => {
		navigate({ search: { ...search, ...updates, page: 1 } });
	};

	const dateRange: DateRange | undefined = search.from_date
		? {
				from: new Date(search.from_date + 'T00:00:00'),
				to: search.to_date ? new Date(search.to_date + 'T00:00:00') : undefined,
			}
		: undefined;

	const { data, isLoading, isFetching } = useQuery(
		appointmentsQuery({
			page: search.page,
			per_page: search.per_page,
			search: debouncedSearch || undefined,
			status: search.status,
			from_date: search.from_date,
			to_date: search.to_date,
		}),
	);

	const appointments = data?.session_bookings ?? [];
	const total = data?.total ?? 0;

	const { data: clientsData } = useQuery({
		queryKey: ['clients', 'all'],
		queryFn: () => clientsApi.list({ per_page: 100 }),
		enabled: addDialogOpen,
	});

	const { data: enrollmentsData, isFetching: enrollmentsFetching } = useQuery({
		queryKey: ['enrollments', addForm.client_id],
		queryFn: () =>
			enrollmentsApi.list({ client_id: Number(addForm.client_id) }),
		enabled: addDialogOpen && !!addForm.client_id,
	});

	const { data: availableDaysData } = useQuery({
		queryKey: ['availability-days', addForm.enrollment_id],
		queryFn: () =>
			availabilitiesApi.availableDays(Number(addForm.enrollment_id)),
		enabled: addDialogOpen && !!addForm.enrollment_id,
	});

	const { data: slotsData, isFetching: slotsFetching } = useQuery({
		queryKey: [
			'availability-slots',
			addForm.enrollment_id,
			addForm.scheduled_date,
		],
		queryFn: () =>
			availabilitiesApi.slots(
				Number(addForm.enrollment_id),
				addForm.scheduled_date,
			),
		enabled:
			addDialogOpen && !!addForm.enrollment_id && !!addForm.scheduled_date,
	});

	const enrollments = enrollmentsData?.enrollments ?? [];
	const noEnrollments =
		!!addForm.client_id && !enrollmentsFetching && enrollments.length === 0;

	const openAdd = () => {
		setAddForm(ADD_APPOINTMENT_DEFAULTS);
		setAddDialogOpen(true);
	};

	const createAppointment = useMutation({
		mutationFn: (data: CreateAppointmentData) => appointmentsApi.create(data),
		onSuccess: () => {
			queryClient.invalidateQueries({ queryKey: ['session-bookings'] });
			toast.success(__('Appointment created.', 'allcoach'));
			setAddDialogOpen(false);
		},
		onError: (error: unknown) => {
			toast.error(
				extractErrorMessage(
					error,
					__('Failed to create appointment. Please try again.', 'allcoach'),
				),
			);
		},
	});

	const handleCreateAppointment = () => {
		if (
			!addForm.enrollment_id ||
			!addForm.scheduled_date ||
			!addForm.start_time ||
			!addForm.end_time
		)
			return;
		createAppointment.mutate({
			enrollment_id: Number(addForm.enrollment_id),
			scheduled_date: addForm.scheduled_date,
			start_time: addForm.start_time,
			end_time: addForm.end_time,
			notes: addForm.notes.trim() || undefined,
		});
	};

	const isAddFormValid =
		!!addForm.enrollment_id &&
		!!addForm.scheduled_date &&
		!!addForm.start_time &&
		!!addForm.end_time;

	const completeAppointment = useMutation({
		mutationFn: (id: number) => appointmentsApi.complete(id),
		onSuccess: (updated) => {
			queryClient.invalidateQueries({ queryKey: ['session-bookings'] });
			toast.success(__('Appointment marked as completed.', 'allcoach'));
			setViewTarget(updated);
		},
		onError: () => {
			toast.error(__('Failed to complete appointment.', 'allcoach'));
		},
	});

	const cancelAppointment = useMutation({
		mutationFn: (id: number) => appointmentsApi.cancel(id),
		onSuccess: () => {
			queryClient.invalidateQueries({ queryKey: ['session-bookings'] });
			toast.success(__('Appointment cancelled.', 'allcoach'));
			setCancelTargetId(null);
			setViewTarget(null);
		},
		onError: () => {
			toast.error(__('Failed to cancel appointment.', 'allcoach'));
		},
	});

	const bulkAction = useMutation({
		mutationFn: ({
			action,
			ids,
		}: {
			action: AppointmentBulkAction;
			ids: number[];
		}) => appointmentsApi.bulk(action, ids),
		onSuccess: (result) => {
			queryClient.invalidateQueries({ queryKey: ['session-bookings'] });
			setResetSelectionKey((k) => k + 1);
			if (result.failed === 0) {
				toast.success(
					sprintf(
						/* translators: %d: number of appointments updated */
						__('%d appointment(s) updated.', 'allcoach'),
						result.processed,
					),
				);
			} else {
				toast.warning(
					sprintf(
						/* translators: %1$d: number of succeeded actions, %2$d: number of failed actions */
						__('%1$d succeeded, %2$d failed.', 'allcoach'),
						result.processed,
						result.failed,
					),
				);
			}
		},
		onError: () => {
			toast.error(__('Bulk action failed. Please try again.', 'allcoach'));
		},
	});

	const columns = [
		col.accessor('id', {
			header: 'ID',
			cell: ({ getValue }) => (
				<span className="font-mono text-sm text-gray-500">#{getValue()}</span>
			),
		}),
		col.accessor('scheduled_date', {
			header: __('Appointment Date', 'allcoach'),
			cell: ({ getValue, row }) => {
				const { start_time, end_time } = row.original;
				return (
					<div className="flex flex-col gap-0.5">
						<span className="text-gray-700">
							{dateI18n(getSettings().formats.date, getValue() + 'T00:00:00')}
						</span>
						<span className="text-xs text-gray-400">
							{start_time} – {end_time}
						</span>
					</div>
				);
			},
		}),
		col.accessor('client', {
			header: __('Client', 'allcoach'),
			cell: ({ getValue, row }) => {
				const client = getValue();
				return (
					<div className="flex flex-col gap-0.5">
						<span className="font-semibold text-gray-800">
							{!client?.first_name && !client?.last_name
								? `#${row.original.enrollment_id}`
								: (client?.first_name ?? '') + ' ' + (client?.last_name ?? '')}
						</span>
						{client?.email && (
							<span className="text-xs text-gray-400">{client.email}</span>
						)}
					</div>
				);
			},
		}),
		col.accessor('program', {
			header: __('Program', 'allcoach'),
			cell: ({ getValue }) => (
				<span className="font-medium text-gray-700">
					{getValue()?.title ?? '—'}
				</span>
			),
		}),
		col.accessor('coach', {
			header: __('Coach', 'allcoach'),
			cell: ({ getValue }) => (
				<span className="text-gray-600">{getValue()?.name ?? '—'}</span>
			),
		}),
		col.accessor('status', {
			header: __('Status', 'allcoach'),
			cell: ({ getValue, row }) => {
				const status = getValue() as AppointmentStatus;
				const missingMeetingUrl =
					status === 'scheduled' && !row.original.meeting_url;
				return (
					<div className="flex items-center gap-1.5">
						<span
							className={cn(
								'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium',
								STATUS_STYLES[status],
							)}
						>
							{STATUS_LABELS[status]}
						</span>
						{missingMeetingUrl && (
							<Tooltip>
								<TooltipTrigger asChild>
									<AlertTriangle className="size-4 shrink-0 text-orange-400" />
								</TooltipTrigger>
								<TooltipContent side="top" className="!z-[999999]">
									{__("Meeting URL doesn't exist", 'allcoach')}
								</TooltipContent>
							</Tooltip>
						)}
					</div>
				);
			},
		}),
		col.display({
			id: 'actions',
			header: () => <div className="w-full text-right">{__('Actions')}</div>,
			cell: ({ row }) => {
				const apt = row.original;
				return (
					<div className="flex items-center justify-end gap-1.5 text-xs font-medium">
						<Button
							variant="outline"
							size="xs"
							className="w-18 cursor-pointer"
							onClick={() => setViewTarget(apt)}
						>
							<EyeIcon /> {__('View', 'allcoach')}
						</Button>
						<DropdownMenu>
							<DropdownMenuTrigger
								className={cn(
									buttonVariants({ variant: 'outline', size: 'icon-xs' }),
									'cursor-pointer',
								)}
							>
								<MoreVertical className="size-4" />
							</DropdownMenuTrigger>
							<DropdownMenuContent align="end">
								<DropdownMenuItem
									className="cursor-pointer"
									onClick={() => setViewTarget(apt)}
								>
									<EyeIcon className="size-3.5" />
									{__('View', 'allcoach')}
								</DropdownMenuItem>
								{apt.meeting_url && apt.status !== 'completed' ? (
									<DropdownMenuItem className="cursor-pointer" asChild>
										<a
											href={apt.meeting_url}
											target="_blank"
											rel="noreferrer"
											className="!text-inherit"
										>
											<Video className="size-3.5" />
											{__('Join Meeting', 'allcoach')}
										</a>
									</DropdownMenuItem>
								) : (
									<DropdownMenuItem disabled className="opacity-40">
										<Video className="size-3.5" />
										{__('Join Meeting', 'allcoach')}
									</DropdownMenuItem>
								)}
								<DropdownMenuItem
									className="cursor-pointer text-red-600 focus:bg-red-50 focus:text-red-600"
									onClick={() => setCancelTargetId(apt.id)}
								>
									<Trash2 className="size-3.5" />
									{__('Cancel', 'allcoach')}
								</DropdownMenuItem>
							</DropdownMenuContent>
						</DropdownMenu>
					</div>
				);
			},
		}),
	];

	const toolbar = (
		<div className="flex flex-wrap items-center gap-3">
			<div className="relative w-full md:w-72">
				<InputGroup>
					<InputGroupInput
						value={searchInput}
						onChange={(e) => setSearchInput(e.target.value)}
						id="appointments-search"
						placeholder={__('Search client or program…', 'allcoach')}
					/>
					<InputGroupAddon align="inline-start">
						<SearchIcon className="text-muted-foreground" />
					</InputGroupAddon>
				</InputGroup>
			</div>

			<Popover open={calendarOpen} onOpenChange={setCalendarOpen}>
				<PopoverTrigger asChild>
					<Button
						variant="outline"
						className={cn(
							'w-full justify-start gap-2 text-start font-normal md:w-[300px]',
							!dateRange && 'text-muted-foreground',
						)}
					>
						<CalendarIcon className="size-4 shrink-0" />
						{dateRange?.from
							? formatDateRange(dateRange)
							: __('Pick a date range', 'allcoach')}
						{dateRange?.from && (
							<span
								role="button"
								className="ms-auto inline-flex size-4 items-center justify-center rounded-full hover:bg-gray-200"
								onClick={(e) => {
									e.stopPropagation();
									setFilter({ from_date: undefined, to_date: undefined });
								}}
							>
								<X className="size-3" />
							</span>
						)}
					</Button>
				</PopoverTrigger>
				<PopoverContent className="w-auto p-0" align="start">
					<Calendar
						mode="range"
						selected={dateRange}
						onSelect={(range) => {
							setFilter({
								from_date: range?.from ? toDateStr(range.from) : undefined,
								to_date: range?.to ? toDateStr(range.to) : undefined,
							});
							if (range?.from && range?.to) setCalendarOpen(false);
						}}
						numberOfMonths={2}
						autoFocus
					/>
				</PopoverContent>
			</Popover>

			<Select
				value={search.status ?? 'all'}
				onValueChange={(value) =>
					setFilter({
						status: value === 'all' ? undefined : (value as AppointmentStatus),
					})
				}
			>
				<SelectTrigger className="w-full md:w-[180px]">
					<SelectValue placeholder={__('Status', 'allcoach')} />
				</SelectTrigger>
				<SelectContent>
					<SelectGroup>
						<SelectItem value="all">{__('All Status', 'allcoach')}</SelectItem>
						<SelectItem value="scheduled">
							{__('Scheduled', 'allcoach')}
						</SelectItem>
						<SelectItem value="completed">
							{__('Completed', 'allcoach')}
						</SelectItem>
						<SelectItem value="cancelled">
							{__('Cancelled', 'allcoach')}
						</SelectItem>
						<SelectItem value="no_show">{__('No Show', 'allcoach')}</SelectItem>
					</SelectGroup>
				</SelectContent>
			</Select>
			<Button
				onClick={openAdd}
				className="w-full cursor-pointer md:ms-auto md:w-auto"
			>
				<Plus />
				{__('New Appointment', 'allcoach')}
			</Button>
		</div>
	);

	return (
		<div className="min-h-screen p-4 md:p-6">
			<GoogleIntegrationAlert />
			<DataTable
				data={appointments}
				columns={columns}
				enableRowSelection
				toolbar={toolbar}
				isLoading={isLoading}
				isFetching={isFetching}
				rowsPerPageLabel={__('Appointments per page', 'allcoach')}
				pageSizeOptions={[10, 25, 50, 100]}
				serverPagination={{
					total,
					page: search.page,
					perPage: search.per_page,
					onPageChange: (page) => navigate({ search: { ...search, page } }),
					onPerPageChange: (perPage) =>
						setFilter({ per_page: perPage as typeof search.per_page }),
				}}
				onSelectionChange={(rows) =>
					setSelectedAppointments(rows as Appointment[])
				}
				resetSelectionKey={resetSelectionKey}
			/>

			{/* New Appointment dialog */}
			<Dialog open={addDialogOpen} onOpenChange={setAddDialogOpen}>
				<DialogContent className="flex max-h-[90svh] flex-col overflow-hidden sm:max-w-lg">
					<DialogHeader>
						<DialogTitle>{__('New Appointment', 'allcoach')}</DialogTitle>
					</DialogHeader>

					<div className="flex flex-col gap-4 overflow-y-auto pe-0.5 pt-2 pb-4">
						{/* Client */}
						<div className="flex flex-col gap-1.5">
							<Label htmlFor="new-apt-client">
								{__('Client', 'allcoach')}{' '}
								<span className="text-red-500">*</span>
							</Label>
							<Select
								value={addForm.client_id}
								onValueChange={(v) =>
									setAddForm((f) => ({ ...f, client_id: v, enrollment_id: '' }))
								}
							>
								<SelectTrigger id="new-apt-client" className="w-full">
									<SelectValue
										placeholder={__('Select a client…', 'allcoach')}
									/>
								</SelectTrigger>
								<SelectContent className="!z-[999999] max-h-60">
									<SelectGroup>
										{(clientsData?.clients ?? []).map((c) => (
											<SelectItem key={c.id} value={String(c.id)}>
												<span className="font-medium">{c.name}</span>
												<span className="ms-1.5 text-xs text-gray-400">
													{c.email}
												</span>
											</SelectItem>
										))}
									</SelectGroup>
								</SelectContent>
							</Select>
						</div>

						{/* Enrollment / Program */}
						<div className="flex flex-col gap-1.5">
							<Label htmlFor="new-apt-enrollment">
								{__('Program', 'allcoach')}{' '}
								<span className="text-red-500">*</span>
							</Label>
							<Select
								value={addForm.enrollment_id}
								onValueChange={(v) =>
									setAddForm((f) => ({
										...f,
										enrollment_id: v,
										scheduled_date: '',
										start_time: '',
										end_time: '',
									}))
								}
								disabled={
									!addForm.client_id || enrollmentsFetching || noEnrollments
								}
							>
								<SelectTrigger
									id="new-apt-enrollment"
									className={cn(
										'w-full',
										noEnrollments && 'border-orange-200 text-orange-500',
									)}
								>
									<SelectValue
										placeholder={
											!addForm.client_id
												? __('Select a client first…', 'allcoach')
												: enrollmentsFetching
													? __('Loading…', 'allcoach')
													: noEnrollments
														? __('No active enrollments', 'allcoach')
														: __('Select a program…', 'allcoach')
										}
									/>
								</SelectTrigger>
								<SelectContent className="!z-[999999] max-h-60">
									<SelectGroup>
										{enrollments.map((e) => (
											<SelectItem key={e.id} value={String(e.id)}>
												{e.program?.title ?? `#${e.program_id}`}
											</SelectItem>
										))}
									</SelectGroup>
								</SelectContent>
							</Select>
							{noEnrollments && (
								<p className="text-xs text-orange-500">
									{__(
										'This client has no active program enrollments. Create an order first.',
										'allcoach',
									)}
								</p>
							)}
						</div>

						{/* Date */}
						<div className="flex flex-col gap-1.5">
							<Label>
								{__('Date', 'allcoach')} <span className="text-red-500">*</span>
							</Label>
							<Popover>
								<PopoverTrigger asChild>
									<Button
										variant="outline"
										className={cn(
											'w-full justify-start gap-2 text-start font-normal',
											!addForm.scheduled_date && 'text-muted-foreground',
										)}
									>
										<CalendarIcon className="size-4 shrink-0" />
										{addForm.scheduled_date
											? dateI18n(
													getSettings().formats.date,
													addForm.scheduled_date + 'T00:00:00',
												)
											: __('Pick a date…', 'allcoach')}
									</Button>
								</PopoverTrigger>
								<PopoverContent
									className="!z-[999999] w-auto p-0"
									align="start"
								>
									<Calendar
										mode="single"
										selected={
											addForm.scheduled_date
												? new Date(addForm.scheduled_date + 'T00:00:00')
												: undefined
										}
										onSelect={(d) =>
											setAddForm((f) => ({
												...f,
												scheduled_date: d
													? `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
													: '',
												start_time: '',
												end_time: '',
											}))
										}
										startMonth={new Date()}
										disabled={[
											{ before: new Date() },
											(date) => {
												const days = availableDaysData?.available_days;
												if (!days || days.length === 0) return false;
												return !days.includes(date.getDay());
											},
										]}
										autoFocus
									/>
								</PopoverContent>
							</Popover>
						</div>

						{/* Time Slots */}
						{addForm.enrollment_id && addForm.scheduled_date && (
							<div className="flex flex-col gap-1.5">
								<Label>
									{__('Available Time Slots', 'allcoach')}{' '}
									<span className="text-red-500">*</span>
								</Label>
								{slotsFetching ? (
									<div className="flex h-16 items-center justify-center">
										<Spinner className="size-4" />
									</div>
								) : !slotsData?.slots.length ? (
									<p className="rounded-lg border border-gray-100 bg-gray-50 py-4 text-center text-xs text-gray-400">
										{__('No slots available for this date.', 'allcoach')}
									</p>
								) : (
									<div className="grid grid-cols-4 gap-1.5">
										{slotsData.slots.map((slot) => {
											const isSelected = addForm.start_time === slot.start_time;
											return (
												<button
													key={slot.start_time}
													type="button"
													disabled={!slot.available}
													onClick={() =>
														setAddForm((f) => ({
															...f,
															start_time: slot.start_time,
															end_time: slot.end_time,
														}))
													}
													className={cn(
														'rounded-md border px-2 py-1.5 text-xs font-medium transition-colors',
														isSelected
															? 'border-primary bg-primary text-primary-foreground'
															: slot.available
																? 'hover:border-primary hover:bg-primary/5 hover:text-primary cursor-pointer border-gray-200'
																: 'cursor-not-allowed border-gray-100 text-gray-300 line-through',
													)}
												>
													{slot.start_time}
												</button>
											);
										})}
									</div>
								)}
								{addForm.start_time && (
									<p className="text-xs text-gray-500">
										{__('Selected:', 'allcoach')} {addForm.start_time} –{' '}
										{addForm.end_time}
									</p>
								)}
							</div>
						)}

						{/* Notes */}
						<div className="flex flex-col gap-1.5">
							<Label htmlFor="new-apt-notes">{__('Notes', 'allcoach')}</Label>
							<Textarea
								id="new-apt-notes"
								value={addForm.notes}
								onChange={(e) =>
									setAddForm((f) => ({ ...f, notes: e.target.value }))
								}
								placeholder={__('Optional notes…', 'allcoach')}
								rows={3}
							/>
						</div>
					</div>

					<DialogFooter>
						<Button
							variant="outline"
							className="cursor-pointer"
							onClick={() => setAddDialogOpen(false)}
						>
							{__('Cancel', 'allcoach')}
						</Button>
						<Button
							className="cursor-pointer"
							disabled={!isAddFormValid || createAppointment.isPending}
							onClick={handleCreateAppointment}
						>
							{createAppointment.isPending && <Spinner />}
							{__('Create Appointment', 'allcoach')}
						</Button>
					</DialogFooter>
				</DialogContent>
			</Dialog>

			{/* View / Detail dialog */}
			<Dialog
				open={viewTarget !== null}
				onOpenChange={(open) => !open && setViewTarget(null)}
			>
				<DialogContent className="flex max-h-[90svh] flex-col overflow-hidden sm:max-w-2xl">
					<DialogHeader className="gap-0.5">
						<div className="flex items-center gap-2">
							<DialogTitle>
								{__('Appointment', 'allcoach')} #{viewTarget?.id}
							</DialogTitle>
							{viewTarget && (
								<span
									className={cn(
										'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium',
										STATUS_STYLES[viewTarget.status],
									)}
								>
									{STATUS_LABELS[viewTarget.status]}
								</span>
							)}
						</div>
						{viewTarget && (
							<div className="flex items-center justify-between gap-2">
								<p className="text-xs text-gray-400">
									{__('Created at:', 'allcoach')}{' '}
									{dateI18n(getSettings().formats.date, viewTarget.created_at)}{' '}
									{dateI18n(getSettings().formats.time, viewTarget.created_at)}
								</p>
								{viewTarget.meeting_url &&
									viewTarget.status !== 'completed' && (
										<Button asChild size="xs">
											<a
												href={viewTarget.meeting_url}
												target="_blank"
												rel="noreferrer"
												className="!text-primary-foreground"
											>
												<Video className="size-3.5" />
												{__('Join Meeting', 'allcoach')}
											</a>
										</Button>
									)}
							</div>
						)}
					</DialogHeader>

					{viewTarget && (
						<div className="flex flex-col gap-3 overflow-x-hidden overflow-y-auto py-1 pb-4">
							{/* Participants */}
							<div className="grid grid-cols-2 gap-4 rounded-lg border border-gray-100 bg-gray-50 p-4 text-sm">
								<div>
									<p className="mb-1 text-xs font-medium tracking-wide text-gray-400 uppercase">
										{__('Client', 'allcoach')}
									</p>
									<p className="font-semibold text-gray-800">
										{!viewTarget.client?.first_name &&
										viewTarget.client?.last_name
											? '—'
											: (viewTarget.client?.first_name ?? '') +
												' ' +
												(viewTarget.client?.last_name ?? '')}
									</p>
									{viewTarget.client?.email && (
										<p className="text-xs text-gray-400">
											{viewTarget.client.email}
										</p>
									)}
									{viewTarget.client?.phone && (
										<p className="text-xs text-gray-400">
											{viewTarget.client.phone}
										</p>
									)}
								</div>
								<div>
									<p className="mb-1 text-xs font-medium tracking-wide text-gray-400 uppercase">
										{__('Coach', 'allcoach')}
									</p>
									<p className="font-semibold text-gray-800">
										{viewTarget.coach?.name ?? '—'}
									</p>
									{viewTarget.coach?.email && (
										<p className="text-xs text-gray-400">
											{viewTarget.coach.email}
										</p>
									)}
								</div>
							</div>

							{/* Program + Schedule */}
							<div className="divide-y divide-gray-100 rounded-lg border border-gray-100 bg-gray-50 text-sm">
								<div className="grid grid-cols-3 gap-x-2 gap-y-0 p-3">
									<div>
										<p className="mb-1 text-xs font-medium tracking-wide text-gray-400 uppercase">
											{__('Program', 'allcoach')}
										</p>
										<p className="font-semibold text-gray-800">
											{viewTarget.program?.title ?? '—'}
										</p>
									</div>
									<div>
										<p className="mb-1 text-xs font-medium tracking-wide text-gray-400 uppercase">
											{__('Date', 'allcoach')}
										</p>
										<p className="font-medium text-gray-800">
											{dateI18n(
												getSettings().formats.date,
												viewTarget.scheduled_date + 'T00:00:00',
											)}
										</p>
									</div>
									<div>
										<p className="mb-1 text-xs font-medium tracking-wide text-gray-400 uppercase">
											{__('Time', 'allcoach')}
										</p>
										<p className="font-medium text-gray-800">
											{viewTarget.start_time} – {viewTarget.end_time}
										</p>
										{viewTarget.client?.timezone && (
											<p className="text-xs text-gray-400">
												{viewTarget.client.timezone}
											</p>
										)}
									</div>
								</div>
								{viewTarget.notes && (
									<div className="p-3">
										<p className="mb-0.5 text-xs font-medium tracking-wide text-gray-400 uppercase">
											{__('Notes', 'allcoach')}
										</p>
										<p className="text-sm text-gray-600">{viewTarget.notes}</p>
									</div>
								)}
							</div>

							{viewTarget.status === 'scheduled' && (
								<div className="flex gap-2">
									<Button
										variant="outline"
										size="sm"
										className="cursor-pointer border-teal-200 text-teal-600 hover:bg-teal-50"
										disabled={completeAppointment.isPending}
										onClick={() => completeAppointment.mutate(viewTarget.id)}
									>
										{__('Mark as Completed', 'allcoach')}
									</Button>
									<Button
										variant="outline"
										size="sm"
										className="cursor-pointer border-red-200 text-red-600 hover:bg-red-50"
										onClick={() => {
											setViewTarget(null);
											setCancelTargetId(viewTarget.id);
										}}
									>
										{__('Cancel Appointment', 'allcoach')}
									</Button>
								</div>
							)}
						</div>
					)}
				</DialogContent>
			</Dialog>

			{/* Cancel confirmation */}
			<AlertDialog
				open={cancelTargetId !== null}
				onOpenChange={(open) => !open && setCancelTargetId(null)}
			>
				<AlertDialogContent>
					<AlertDialogHeader>
						<AlertDialogTitle>
							{__('Cancel Appointment', 'allcoach')}
						</AlertDialogTitle>
						<AlertDialogDescription>
							{__(
								'Are you sure you want to cancel this appointment? This action cannot be undone.',
								'allcoach',
							)}
						</AlertDialogDescription>
					</AlertDialogHeader>
					<AlertDialogFooter>
						<AlertDialogCancel className="cursor-pointer">
							{__('Keep', 'allcoach')}
						</AlertDialogCancel>
						<AlertDialogAction
							className="cursor-pointer bg-red-600 hover:bg-red-700"
							disabled={cancelAppointment.isPending}
							onClick={() => {
								if (cancelTargetId !== null) {
									cancelAppointment.mutate(cancelTargetId);
								}
							}}
						>
							{__('Cancel Appointment', 'allcoach')}
						</AlertDialogAction>
					</AlertDialogFooter>
				</AlertDialogContent>
			</AlertDialog>
			{/* Bulk action bar */}
			<BulkActionBar
				count={selectedAppointments.length}
				isPending={bulkAction.isPending}
				onDismiss={() => setResetSelectionKey((k) => k + 1)}
				actions={[
					{
						label: __('Mark Complete', 'allcoach'),
						icon: <CheckCircle2 className="size-3.5" />,
						variant: 'success',
						onClick: () =>
							bulkAction.mutate({
								action: 'complete',
								ids: selectedAppointments.map((a) => a.id),
							}),
					},
					{
						label: __('Cancel', 'allcoach'),
						icon: <XCircle className="size-3.5" />,
						variant: 'danger',
						onClick: () =>
							bulkAction.mutate({
								action: 'cancel',
								ids: selectedAppointments.map((a) => a.id),
							}),
					},
				]}
			/>
		</div>
	);
};

export default Appointments;
