import { demoApi } from '@/admin/api/demo';
import type { ProgramCategory } from '@/admin/api/program-categories';
import { programCategoriesApi } from '@/admin/api/program-categories';
import type { BulkAction, Program } from '@/admin/api/programs';
import { programsApi } from '@/admin/api/programs';
import { programCategoriesQuery } from '@/admin/queries/program-categories';
import { programsQuery } from '@/admin/queries/programs';
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 {
	Dialog,
	DialogContent,
	DialogHeader,
	DialogTitle,
} from '@/components/ui/dialog';
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import {
	InputGroup,
	InputGroupAddon,
	InputGroupInput,
} from '@/components/ui/input-group';
import { Label } from '@/components/ui/label';
import {
	Select,
	SelectContent,
	SelectGroup,
	SelectItem,
	SelectTrigger,
	SelectValue,
} from '@/components/ui/select';
import { Spinner } from '@/components/ui/spinner';
import { Switch } from '@/components/ui/switch';
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
import { cn } from '@/lib/utils';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { getRouteApi, Link } from '@tanstack/react-router';
import { createColumnHelper } from '@tanstack/react-table';
import { dateI18n, getSettings } from '@wordpress/date';
import { __, sprintf } from '@wordpress/i18n';
import {
	CheckCircle2,
	Eye,
	MoreVertical,
	PencilIcon,
	Plus,
	SearchIcon,
	Trash2,
	XCircle,
} from 'lucide-react';
import { useEffect, useState } from 'react';
import { toast } from 'sonner';

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

const col = createColumnHelper<Program>();
const Programs = () => {
	const queryClient = useQueryClient();
	const navigate = routeApi.useNavigate();
	const search = routeApi.useSearch();
	const [deleteTargetId, setDeleteTargetId] = useState<number | null>(null);
	const [selectedPrograms, setSelectedPrograms] = useState<Program[]>([]);
	const [bulkDeleteConfirm, setBulkDeleteConfirm] = useState(false);
	const [resetSelectionKey, setResetSelectionKey] = useState(0);
	const [manageCatsOpen, setManageCatsOpen] = useState(false);
	const [editingCatId, setEditingCatId] = useState<number | null>(null);
	const [editingCatName, setEditingCatName] = useState('');
	const [newCatName, setNewCatName] = useState('');
	const [searchInput, setSearchInput] = useState(search.search);
	const debouncedSearch = useDebouncedValue(searchInput);

	// Sync input when URL changes externally (e.g. browser back/forward)
	useEffect(() => {
		setSearchInput(search.search);
	}, [search.search]);

	// Update URL after debounce
	useEffect(() => {
		if (debouncedSearch !== search.search) {
			setFilter({ search: debouncedSearch });
		}
	}, [debouncedSearch]);

	const { data, isLoading, isFetching } = useQuery(
		programsQuery({
			page: search.page,
			per_page: search.per_page,
			search: search.search || undefined,
			status: search.status !== 'any' ? search.status : undefined,
			category_id: search.category_id,
		}),
	);

	const { data: categoriesData } = useQuery(programCategoriesQuery());

	const programs = data?.programs ?? [];
	const total = data?.total ?? 0;

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

	const createProgram = useMutation({
		mutationFn: () =>
			programsApi.create({
				title: __('Untitled Program', 'allcoach'),
				duration_value: 1,
				duration_unit: 'weeks',
			}),
		onSuccess: (program) => {
			navigate({
				to: '/programs/$programId/edit',
				params: { programId: String(program.id) },
			});
		},
		onError: () => {
			toast.error(
				__('Failed to create program. Please try again.', 'allcoach'),
			);
		},
	});

	const toggleStatus = useMutation({
		mutationFn: ({ id, is_active }: { id: number; is_active: boolean }) =>
			programsApi.update(id, { is_active }),
		onSuccess: (_, { is_active }) => {
			queryClient.invalidateQueries({ queryKey: ['programs'] });
			toast.success(
				is_active
					? __('Program activated.', 'allcoach')
					: __('Program deactivated.', 'allcoach'),
			);
		},
	});

	const createCategory = useMutation({
		mutationFn: (name: string) => programCategoriesApi.create({ name }),
		onSuccess: () => {
			queryClient.invalidateQueries({ queryKey: ['program-categories'] });
			setNewCatName('');
			toast.success(__('Category created.', 'allcoach'));
		},
		onError: () => toast.error(__('Failed to create category.', 'allcoach')),
	});

	const updateCategory = useMutation({
		mutationFn: ({ id, name }: { id: number; name: string }) =>
			programCategoriesApi.update(id, { name }),
		onSuccess: () => {
			queryClient.invalidateQueries({ queryKey: ['program-categories'] });
			setEditingCatId(null);
			setEditingCatName('');
			toast.success(__('Category updated.', 'allcoach'));
		},
		onError: () => toast.error(__('Failed to update category.', 'allcoach')),
	});

	const deleteCategory = useMutation({
		mutationFn: (id: number) => programCategoriesApi.delete(id),
		onSuccess: () => {
			queryClient.invalidateQueries({ queryKey: ['program-categories'] });
			queryClient.invalidateQueries({ queryKey: ['programs'] });
			toast.success(__('Category deleted.', 'allcoach'));
		},
		onError: () => toast.error(__('Failed to delete category.', 'allcoach')),
	});

	const deleteProgram = useMutation({
		mutationFn: (id: number) => programsApi.delete(id),
		onSuccess: () => {
			queryClient.invalidateQueries({ queryKey: ['programs'] });
			toast.success(__('Program deleted.', 'allcoach'));
		},
		onError: () => {
			toast.error(
				__('Failed to delete program. Please try again.', 'allcoach'),
			);
		},
	});

	const demoMutation = useMutation({
		mutationFn: demoApi.start,
		mutationKey: ['demo'],
		onSuccess: (data) => {
			window.location.href = data.url;
		},
		onError(e) {
			toast.error(e.message);
		},
	});

	const bulkAction = useMutation({
		mutationFn: ({ action, ids }: { action: BulkAction; ids: number[] }) =>
			programsApi.bulk(action, ids),
		onSuccess: (result) => {
			queryClient.invalidateQueries({ queryKey: ['programs'] });
			setResetSelectionKey((k) => k + 1);
			if (result.failed === 0) {
				toast.success(
					sprintf(
						/* translators: %d: number of programs updated */
						__('%d program(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 toEditPage = (id: number) =>
		navigate({
			to: '/programs/$programId/edit',
			params: { programId: String(id) },
		});

	const columns = [
		col.display({
			id: 'program',
			header: 'Program',
			cell: ({ row }) => (
				<div className="flex flex-col gap-1">
					<button
						className="hover:text-primary cursor-pointer text-start font-semibold text-gray-700"
						onClick={() => toEditPage(row.original.id)}
					>
						{row.original.title}
					</button>
					<div className="flex flex-wrap gap-1">
						{row.original.categories.map((c) => (
							<span
								key={c.id}
								className="rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-500"
							>
								{c.name}
							</span>
						))}
					</div>
				</div>
			),
		}),
		col.accessor('booking_count', {
			header: 'Clients',
			cell: ({ getValue }) => (
				<span className="font-medium text-gray-500">{getValue()}</span>
			),
		}),
		col.display({
			id: 'price',
			header: 'Price',
			cell: ({ row }) => {
				const { is_free, amount, currency } = row.original.price;
				if (is_free) {
					return (
						<span className="rounded-full bg-teal-50 px-2 py-0.5 text-xs font-medium text-teal-600">
							{__('Free', 'allcoach')}
						</span>
					);
				}
				const currencyData = __ALLCOACH_ADMIN__.currencies.find(
					(c) => c.code === currency,
				);
				const label = currencyData
					? `${currency} (${currencyData.symbol})`
					: currency;
				return (
					<span className="text-xs font-medium text-gray-700">
						{amount} {label}
					</span>
				);
			},
		}),
		col.accessor('created_at', {
			header: 'Created Date',
			cell: ({ getValue }) => (
				<span className="text-gray-500">
					{dateI18n(getSettings().formats.date, getValue())}
				</span>
			),
		}),
		col.display({
			id: 'status',
			header: 'Status',
			cell: ({ row }) => {
				const active = row.original.is_active;
				const switchId = `status-switch-${row.original.id}`;
				return (
					<div className="flex items-center gap-2">
						<Switch
							className="cursor-pointer"
							id={switchId}
							checked={active}
							onCheckedChange={(checked) =>
								toggleStatus.mutate({
									id: row.original.id,
									is_active: checked,
								})
							}
						/>
						<Label
							htmlFor={switchId}
							className={cn(
								'text-xs',
								active ? 'text-primary' : 'text-gray-600',
							)}
						>
							{active ? __('Active', 'allcoach') : __('Draft', 'allcoach')}
						</Label>
					</div>
				);
			},
		}),
		col.display({
			id: 'actions',
			header: () => <div className="w-full text-right">{__('Actions')}</div>,
			cell: ({ row }) => {
				const id = row.original.id;
				return (
					<div className="flex items-center justify-end gap-1.5">
						<Button
							size="xs"
							variant="outline"
							className="cursor-pointer text-xs! font-medium!"
							onClick={() => demoMutation.mutate(id)}
						>
							<Eye /> {__('View as Demo Client', 'allcoach')}
						</Button>
						<Button
							variant="outline"
							size="xs"
							className="w-18 cursor-pointer"
							asChild
						>
							<Link
								to="/programs/$programId/edit"
								params={{ programId: row.original.id.toString() }}
							>
								<PencilIcon /> {__('Edit', 'allcoach')}
							</Link>
						</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={() => toEditPage(id)}
								>
									<PencilIcon className="size-3.5" />
									{__('Edit', 'allcoach')}
								</DropdownMenuItem>
								<DropdownMenuItem
									className="cursor-pointer text-red-600 focus:bg-red-50 focus:text-red-600"
									onClick={() => setDeleteTargetId(id)}
								>
									<Trash2 className="size-3.5" />
									{__('Delete', '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="programs-search"
						placeholder={__('Search…', 'allcoach')}
					/>
					<InputGroupAddon align="inline-start">
						<SearchIcon className="text-muted-foreground" />
					</InputGroupAddon>
				</InputGroup>
			</div>

			<Select
				value={search.status}
				onValueChange={(value) =>
					setFilter({ status: value as 'active' | 'draft' | 'any' })
				}
			>
				<SelectTrigger className="w-full md:w-[180px]">
					<SelectValue placeholder="Status" />
				</SelectTrigger>
				<SelectContent>
					<SelectGroup>
						<SelectItem value="any">{__('All Status', 'allcoach')}</SelectItem>
						<SelectItem value="active">{__('Active', 'allcoach')}</SelectItem>
						<SelectItem value="draft">{__('Draft', 'allcoach')}</SelectItem>
					</SelectGroup>
				</SelectContent>
			</Select>

			<Select
				value={search.category_id ? String(search.category_id) : 'all'}
				onValueChange={(value) =>
					setFilter({
						category_id: value === 'all' ? undefined : Number(value),
					})
				}
			>
				<SelectTrigger className="w-full md:w-[180px]">
					<SelectValue placeholder={__('All Types', 'allcoach')} />
				</SelectTrigger>
				<SelectContent>
					<SelectGroup>
						<SelectItem value="all">{__('All Types', 'allcoach')}</SelectItem>
						{(categoriesData?.program_categories ?? []).map((cat) => (
							<SelectItem key={cat.id} value={String(cat.id)}>
								{cat.name}
							</SelectItem>
						))}
					</SelectGroup>
				</SelectContent>
			</Select>

			<Button
				variant="outline"
				onClick={() => setManageCatsOpen(true)}
				className="w-full cursor-pointer md:ms-auto md:w-auto"
			>
				{__('Manage Categories', 'allcoach')}
			</Button>
			<Button
				onClick={() => createProgram.mutate()}
				disabled={createProgram.isPending}
				className="w-full cursor-pointer md:w-auto"
			>
				{createProgram.isPending ? <Spinner /> : <Plus />}
				{__('Create New Program', 'allcoach')}
			</Button>
		</div>
	);

	return (
		<div className="min-h-screen p-4 md:p-6">
			<DataTable
				data={programs}
				columns={columns}
				isLoading={isLoading}
				isFetching={isFetching}
				enableRowSelection
				toolbar={toolbar}
				rowsPerPageLabel={__('Programs 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) => setSelectedPrograms(rows as Program[])}
				resetSelectionKey={resetSelectionKey}
			/>

			{/* Manage Categories dialog */}
			<Dialog
				open={manageCatsOpen}
				onOpenChange={(open) => {
					setManageCatsOpen(open);
					if (!open) {
						setEditingCatId(null);
						setEditingCatName('');
						setNewCatName('');
					}
				}}
			>
				<DialogContent className="gap-0 p-0 sm:max-w-md">
					<DialogHeader className="px-6 py-4 pe-12">
						<DialogTitle className="text-[15px] font-semibold text-gray-900">
							{__('Manage Categories', 'allcoach')}
						</DialogTitle>
					</DialogHeader>
					<div className="max-h-[400px] overflow-y-auto border-t border-gray-100">
						<ul className="divide-y divide-gray-100">
							{(categoriesData?.program_categories ?? []).map(
								(cat: ProgramCategory) => (
									<li
										key={cat.id}
										className="flex items-center gap-2 px-4 py-2.5"
									>
										{editingCatId === cat.id ? (
											<>
												<Input
													autoFocus
													value={editingCatName}
													onChange={(e) => setEditingCatName(e.target.value)}
													onKeyDown={(e) => {
														if (e.key === 'Enter' && editingCatName.trim()) {
															updateCategory.mutate({
																id: cat.id,
																name: editingCatName.trim(),
															});
														} else if (e.key === 'Escape') {
															setEditingCatId(null);
															setEditingCatName('');
														}
													}}
													className="h-7 flex-1 text-[13px]"
												/>
												<Button
													size="xs"
													className="cursor-pointer bg-teal-600 text-[12px] hover:bg-teal-700"
													disabled={
														!editingCatName.trim() || updateCategory.isPending
													}
													onClick={() => {
														if (editingCatName.trim()) {
															updateCategory.mutate({
																id: cat.id,
																name: editingCatName.trim(),
															});
														}
													}}
												>
													{__('Save', 'allcoach')}
												</Button>
												<Button
													size="xs"
													variant="outline"
													className="cursor-pointer text-[12px]"
													onClick={() => {
														setEditingCatId(null);
														setEditingCatName('');
													}}
												>
													{__('Cancel', 'allcoach')}
												</Button>
											</>
										) : (
											<>
												<span className="flex-1 text-[13px] text-gray-700">
													{cat.name}
												</span>
												<Button
													variant="ghost"
													size="icon-xs"
													className="cursor-pointer text-gray-400 hover:text-gray-700"
													onClick={() => {
														setEditingCatId(cat.id);
														setEditingCatName(cat.name);
													}}
												>
													<PencilIcon className="size-3.5" />
												</Button>
												<Button
													variant="ghost"
													size="icon-xs"
													className="cursor-pointer text-gray-400 hover:text-red-600"
													onClick={() => deleteCategory.mutate(cat.id)}
												>
													<Trash2 className="size-3.5" />
												</Button>
											</>
										)}
									</li>
								),
							)}

							{/* Add row */}
							{editingCatId === -1 ? (
								<li className="flex items-center gap-2 px-4 py-2.5">
									<Input
										autoFocus
										value={newCatName}
										onChange={(e) => setNewCatName(e.target.value)}
										onKeyDown={(e) => {
											if (e.key === 'Enter' && newCatName.trim()) {
												createCategory.mutate(newCatName.trim());
												setEditingCatId(null);
											} else if (e.key === 'Escape') {
												setEditingCatId(null);
												setNewCatName('');
											}
										}}
										placeholder={__('Category name…', 'allcoach')}
										className="h-7 flex-1 text-[13px]"
									/>
									<Button
										size="xs"
										className="cursor-pointer bg-teal-600 text-[12px] hover:bg-teal-700"
										disabled={!newCatName.trim() || createCategory.isPending}
										onClick={() => {
											if (newCatName.trim()) {
												createCategory.mutate(newCatName.trim());
												setEditingCatId(null);
											}
										}}
									>
										{__('Save', 'allcoach')}
									</Button>
									<Button
										size="xs"
										variant="outline"
										className="cursor-pointer text-[12px]"
										onClick={() => {
											setEditingCatId(null);
											setNewCatName('');
										}}
									>
										{__('Cancel', 'allcoach')}
									</Button>
								</li>
							) : (
								<li>
									<button
										className="flex w-full cursor-pointer items-center gap-2 px-4 py-2.5 text-[13px] text-gray-400 hover:bg-gray-50 hover:text-gray-600"
										onClick={() => {
											setNewCatName('');
											setEditingCatId(-1);
										}}
									>
										<Plus className="size-3.5" />
										{__('Add a category', 'allcoach')}
									</button>
								</li>
							)}
						</ul>
					</div>
				</DialogContent>
			</Dialog>

			<AlertDialog
				open={deleteTargetId !== null}
				onOpenChange={(open) => !open && setDeleteTargetId(null)}
			>
				<AlertDialogContent>
					<AlertDialogHeader>
						<AlertDialogTitle>
							{__('Delete Program', 'allcoach')}
						</AlertDialogTitle>
						<AlertDialogDescription>
							{__(
								'Are you sure you want to delete this program? 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={() => {
								if (deleteTargetId !== null) {
									deleteProgram.mutate(deleteTargetId);
									setDeleteTargetId(null);
								}
							}}
						>
							{__('Delete', 'allcoach')}
						</AlertDialogAction>
					</AlertDialogFooter>
				</AlertDialogContent>
			</AlertDialog>

			{/* Bulk delete confirm */}
			<AlertDialog
				open={bulkDeleteConfirm}
				onOpenChange={(open) => !open && setBulkDeleteConfirm(false)}
			>
				<AlertDialogContent>
					<AlertDialogHeader>
						<AlertDialogTitle>
							{__('Delete Programs', 'allcoach')}
						</AlertDialogTitle>
						<AlertDialogDescription>
							{__(
								`Are you sure you want to delete ${selectedPrograms.length} program(s)? 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={() => {
								bulkAction.mutate({
									action: 'delete',
									ids: selectedPrograms.map((p) => p.id),
								});
								setBulkDeleteConfirm(false);
							}}
						>
							{__('Delete', 'allcoach')}
						</AlertDialogAction>
					</AlertDialogFooter>
				</AlertDialogContent>
			</AlertDialog>

			{/* Bulk action bar */}
			<BulkActionBar
				count={selectedPrograms.length}
				isPending={bulkAction.isPending}
				onDismiss={() => setResetSelectionKey((k) => k + 1)}
				actions={[
					{
						label: __('Set Active', 'allcoach'),
						icon: <CheckCircle2 className="size-3.5" />,
						variant: 'success',
						onClick: () =>
							bulkAction.mutate({
								action: 'activate',
								ids: selectedPrograms.map((p) => p.id),
							}),
					},
					{
						label: __('Set Inactive', 'allcoach'),
						icon: <XCircle className="size-3.5" />,
						onClick: () =>
							bulkAction.mutate({
								action: 'deactivate',
								ids: selectedPrograms.map((p) => p.id),
							}),
					},
					{
						label: __('Delete', 'allcoach'),
						icon: <Trash2 className="size-3.5" />,
						variant: 'danger',
						onClick: () => setBulkDeleteConfirm(true),
					},
				]}
			/>
		</div>
	);
};

export default Programs;
