import { format, formatDistance } from "date-fns";
import {
	AlertCircle,
	Bookmark,
	BookOpen,
	CheckCircle,
	ChevronDown,
	Clock,
	FileEdit,
	Heart,
	Layers,
	MessageSquare,
	MoreHorizontal,
	PenSquare,
	RefreshCw,
	Star,
	Tag,
	UserPlus,
	Users,
} from "lucide-react";
import { useState } from "react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { Timeline, TimelineItem } from "@/components/ui/timeline";
import { cn } from "@/lib/utils";

/**
 * Activity Feed component for displaying user activity timelines
 *
 * @example
 * ```tsx
 * <ActivityFeed
 *   activities={activities}
 *   isLoading={isLoading}
 *   onLoadMore={handleLoadMore}
 *   hasMore={hasMoreActivities}
 * />
 * ```
 */

export interface Activity {
	/**
	 * Unique ID for the activity
	 */
	id: string | number;
	/**
	 * Type of activity
	 */
	type: string;
	/**
	 * User who performed the activity
	 */
	user: {
		id: string | number;
		name: string;
		avatar?: string;
		role?: string;
	};
	/**
	 * Timestamp when the activity occurred
	 */
	timestamp: string | Date;
	/**
	 * Associated entity of the activity (work, comment, etc)
	 */
	entity?: {
		id: string | number;
		type: string;
		name: string;
		url?: string;
	};
	/**
	 * Secondary entity involved in the activity (e.g., the tag that was added)
	 */
	secondaryEntity?: {
		id: string | number;
		type: string;
		name: string;
		url?: string;
	};
	/**
	 * Additional metadata specific to the activity type
	 */
	meta?: Record<string, any>;
	/**
	 * Optional group identifier for grouping related activities
	 */
	groupId?: string | number;
}

export interface ActivityFeedProps {
	/**
	 * Array of activity items to display
	 */
	activities: Activity[];
	/**
	 * Whether activities are currently loading
	 */
	isLoading?: boolean;
	/**
	 * Callback to load more activities
	 */
	onLoadMore?: () => void;
	/**
	 * Whether there are more activities to load
	 */
	hasMore?: boolean;
	/**
	 * Callback when an activity is clicked
	 */
	onActivityClick?: (activity: Activity) => void;
	/**
	 * Maximum number of activities to display before scrolling
	 */
	maxItems?: number;
	/**
	 * Maximum height of the feed
	 */
	maxHeight?: string | number;
	/**
	 * Whether to group activities by date
	 */
	groupByDate?: boolean;
	/**
	 * Whether to use a compact layout
	 */
	compact?: boolean;
	/**
	 * Optional filter by activity type
	 */
	filter?: string[];
	/**
	 * Whether to hide the filter controls
	 */
	hideFilters?: boolean;
	/**
	 * Additional CSS classes
	 */
	className?: string;
}

interface ActivityGroup {
	date: string;
	activities: Activity[];
}

/**
 * Get icon for activity type
 */
const getActivityIcon = (type: string): React.ReactNode => {
	const icons: Record<string, React.ReactNode> = {
		comment: <MessageSquare className="h-4 w-4" />,
		like: <Heart className="h-4 w-4" />,
		create: <PenSquare className="h-4 w-4" />,
		edit: <FileEdit className="h-4 w-4" />,
		join: <UserPlus className="h-4 w-4" />,
		bookmark: <Bookmark className="h-4 w-4" />,
		rate: <Star className="h-4 w-4" />,
		alert: <AlertCircle className="h-4 w-4" />,
		complete: <CheckCircle className="h-4 w-4" />,
		schedule: <Clock className="h-4 w-4" />,
		read: <BookOpen className="h-4 w-4" />,
		follow: <Users className="h-4 w-4" />,
		tag: <Tag className="h-4 w-4" />,
		collection: <Layers className="h-4 w-4" />,
	};

	return icons[type] || <MoreHorizontal className="h-4 w-4" />;
};

/**
 * Get color variant for activity type
 */
const getActivityVariant = (type: string): string => {
	const variants: Record<string, string> = {
		comment: "bg-blue-100 dark:bg-blue-950/30 text-blue-700 dark:text-blue-400",
		like: "bg-pink-100 dark:bg-pink-950/30 text-pink-700 dark:text-pink-400",
		create:
			"bg-green-100 dark:bg-green-950/30 text-green-700 dark:text-green-400",
		edit: "bg-amber-100 dark:bg-amber-950/30 text-amber-700 dark:text-amber-400",
		join: "bg-indigo-100 dark:bg-indigo-950/30 text-indigo-700 dark:text-indigo-400",
		bookmark:
			"bg-purple-100 dark:bg-purple-950/30 text-purple-700 dark:text-purple-400",
		rate: "bg-yellow-100 dark:bg-yellow-950/30 text-yellow-700 dark:text-yellow-400",
		alert: "bg-red-100 dark:bg-red-950/30 text-red-700 dark:text-red-400",
		complete:
			"bg-emerald-100 dark:bg-emerald-950/30 text-emerald-700 dark:text-emerald-400",
		schedule:
			"bg-cyan-100 dark:bg-cyan-950/30 text-cyan-700 dark:text-cyan-400",
		read: "bg-violet-100 dark:bg-violet-950/30 text-violet-700 dark:text-violet-400",
		follow:
			"bg-indigo-100 dark:bg-indigo-950/30 text-indigo-700 dark:text-indigo-400",
		tag: "bg-orange-100 dark:bg-orange-950/30 text-orange-700 dark:text-orange-400",
		collection:
			"bg-teal-100 dark:bg-teal-950/30 text-teal-700 dark:text-teal-400",
	};

	return (
		variants[type] ||
		"bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-400"
	);
};

/**
 * Get formatted activity message
 */
const getActivityMessage = (activity: Activity): string => {
	const { type, entity, secondaryEntity, meta } = activity;

	const entityName = entity?.name || "item";
	const secondaryName = secondaryEntity?.name || "";

	const messages: Record<string, string> = {
		comment: `commented on ${entityName}`,
		like: `liked ${entityName}`,
		create: `created ${entityName}`,
		edit: `edited ${entityName}`,
		join: `joined the platform`,
		bookmark: `bookmarked ${entityName}`,
		rate: `rated ${entityName}`,
		read: `read ${entityName}`,
		follow: `followed ${entityName}`,
		tag: `tagged ${entityName} with ${secondaryName}`,
		collection: `added ${entityName} to collection ${secondaryName}`,
	};

	return messages[type] || `performed action on ${entityName}`;
};

/**
 * Function to group activities by date
 */
const groupActivitiesByDate = (activities: Activity[]): ActivityGroup[] => {
	const groups: Record<string, Activity[]> = {};

	activities.forEach((activity) => {
		const date = new Date(activity.timestamp);
		const dateKey = format(date, "yyyy-MM-dd");

		if (!groups[dateKey]) {
			groups[dateKey] = [];
		}

		groups[dateKey].push(activity);
	});

	return Object.entries(groups)
		.map(([date, activities]) => ({
			date,
			activities,
		}))
		.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
};

/**
 * Format date for group headers
 */
const formatGroupDate = (dateString: string): string => {
	const date = new Date(dateString);
	const today = new Date();
	const yesterday = new Date(today);
	yesterday.setDate(yesterday.getDate() - 1);

	if (format(date, "yyyy-MM-dd") === format(today, "yyyy-MM-dd")) {
		return "Today";
	} else if (format(date, "yyyy-MM-dd") === format(yesterday, "yyyy-MM-dd")) {
		return "Yesterday";
	} else {
		return format(date, "MMMM d, yyyy");
	}
};

export function ActivityFeed({
	activities,
	isLoading = false,
	onLoadMore,
	hasMore = false,
	onActivityClick,
	maxItems = 50,
	maxHeight = "500px",
	groupByDate = true,
	compact = false,
	filter = [],
	hideFilters = false,
	className,
}: ActivityFeedProps) {
	const [activeFilters, setActiveFilters] = useState<string[]>(filter);
	const [expanded, setExpanded] = useState<Record<string, boolean>>({});

	// Apply filters to activities
	const filteredActivities =
		activeFilters.length > 0
			? activities.filter((activity) => activeFilters.includes(activity.type))
			: activities;

	// Group activities by date if needed
	const groupedActivities = groupByDate
		? groupActivitiesByDate(filteredActivities)
		: [{ date: "all", activities: filteredActivities }];

	// Function to handle toggling activity expansion
	const toggleExpanded = (id: string | number) => {
		setExpanded((prev) => ({
			...prev,
			[id.toString()]: !prev[id.toString()],
		}));
	};

	// Toggle a filter
	const toggleFilter = (type: string) => {
		setActiveFilters((prev) =>
			prev.includes(type) ? prev.filter((t) => t !== type) : [...prev, type],
		);
	};

	// Generate list of available types from activities
	const availableTypes = Array.from(
		new Set(activities.map((activity) => activity.type)),
	);

	return (
		<div className={cn("space-y-4", className)}>
			{/* Filter controls */}
			{!hideFilters && availableTypes.length > 0 && (
				<div className="flex flex-wrap gap-2 mb-4">
					{availableTypes.map((type) => (
						<Badge
							key={type}
							variant={activeFilters.includes(type) ? "default" : "outline"}
							className="cursor-pointer"
							onClick={() => toggleFilter(type)}
						>
							<span className="flex items-center gap-1">
								{getActivityIcon(type)}
								<span className="capitalize">{type}</span>
							</span>
						</Badge>
					))}

					{activeFilters.length > 0 && (
						<Button
							variant="ghost"
							size="sm"
							onClick={() => setActiveFilters([])}
							className="h-6 px-2 text-xs"
						>
							Clear filters
						</Button>
					)}
				</div>
			)}

			{/* Activity list */}
			<ScrollArea
				className={cn(
					"w-full",
					typeof maxHeight === "number"
						? `max-h-[${maxHeight}px]`
						: `max-h-[${maxHeight}]`,
				)}
			>
				{groupedActivities.length === 0 || filteredActivities.length === 0 ? (
					<div className="py-8 text-center text-muted-foreground">
						No activities to display
					</div>
				) : (
					<div className="space-y-6">
						{groupedActivities.map((group) => (
							<div key={group.date} className="space-y-4">
								{/* Date header (if grouping by date) */}
								{groupByDate && (
									<div className="sticky top-0 z-10 bg-background/80 backdrop-blur-sm pb-2">
										<h3 className="text-sm font-medium text-muted-foreground">
											{formatGroupDate(group.date)}
										</h3>
										<Separator className="mt-2" />
									</div>
								)}

								{/* Activities list */}
								<Timeline>
									{group.activities.map((activity) => {
										const timestamp = new Date(activity.timestamp);
										const isExpanded = expanded[activity.id.toString()];

										return (
											<TimelineItem
												key={activity.id.toString()}
												date={
													compact
														? undefined
														: format(timestamp, "h:mm a").toString()
												}
												title={
													<div className="flex items-center gap-2">
														<div className="flex items-center gap-2 min-w-0">
															<Avatar className="h-6 w-6">
																<AvatarImage
																	src={activity.user.avatar}
																	alt={activity.user.name}
																/>
																<AvatarFallback>
																	{activity.user.name.charAt(0)}
																</AvatarFallback>
															</Avatar>
															<span className="font-medium truncate">
																{activity.user.name}
															</span>
														</div>
														<div className="flex items-center gap-1">
															<span className="text-xs text-muted-foreground font-normal">
																{formatDistance(timestamp, new Date(), {
																	addSuffix: true,
																})}
															</span>
														</div>
													</div>
												}
												description={
													<div className="flex flex-col space-y-2">
														<div className="flex items-center gap-2">
															<div
																className={cn(
																	"flex items-center justify-center h-6 w-6 rounded-full",
																	getActivityVariant(activity.type),
																)}
															>
																{getActivityIcon(activity.type)}
															</div>
															<span>{getActivityMessage(activity)}</span>
														</div>

														{activity.entity && (
															<div className="pl-8">
																<div
																	className={cn(
																		"text-sm p-2 rounded bg-muted/50 border border-border/50 cursor-pointer",
																		isExpanded ? "mb-2" : "",
																	)}
																	onClick={() => toggleExpanded(activity.id)}
																>
																	<div className="flex items-center justify-between">
																		<div className="font-medium">
																			{activity.entity.name}
																		</div>
																		<ChevronDown
																			className={cn(
																				"h-4 w-4 text-muted-foreground transition-transform",
																				isExpanded
																					? "transform rotate-180"
																					: "",
																			)}
																		/>
																	</div>

																	{isExpanded && activity.meta && (
																		<div className="mt-2 text-xs text-muted-foreground">
																			{activity.meta.excerpt && (
																				<div className="mt-2 italic">
																					"{activity.meta.excerpt}"
																				</div>
																			)}
																			{activity.meta.details && (
																				<div className="mt-1">
																					{activity.meta.details}
																				</div>
																			)}
																		</div>
																	)}
																</div>
															</div>
														)}
													</div>
												}
												icon={
													activity.meta?.important ? AlertCircle : undefined
												}
												active={activity.meta?.active}
												variant={
													activity.meta?.highlighted ? "highlight" : undefined
												}
											/>
										);
									})}
								</Timeline>
							</div>
						))}
					</div>
				)}

				{/* Load more button */}
				{hasMore && (
					<div className="py-4 flex justify-center">
						<Button
							variant="outline"
							size="sm"
							onClick={onLoadMore}
							disabled={isLoading}
							className="w-full max-w-xs"
						>
							{isLoading ? (
								<>
									<RefreshCw className="h-4 w-4 mr-2 animate-spin" />
									Loading...
								</>
							) : (
								"Load more"
							)}
						</Button>
					</div>
				)}
			</ScrollArea>
		</div>
	);
}

export default ActivityFeed;
