import { formatDistanceToNow } from "date-fns";
import {
	AlertTriangle,
	ChevronDown,
	ChevronUp,
	Edit,
	Heart,
	MessageSquare,
	MoreVertical,
	Reply,
	ThumbsUp,
	Trash2,
} 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 {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuSeparator,
	DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";

/**
 * Comment Thread component for displaying hierarchical comments
 *
 * @example
 * ```tsx
 * <CommentThread
 *   comments={comments}
 *   currentUserId={currentUser.id}
 *   onAddComment={(text, parentId) => handleAddComment(text, parentId)}
 *   onEditComment={(id, text) => handleEditComment(id, text)}
 *   onDeleteComment={(id) => handleDeleteComment(id)}
 *   onLikeComment={(id) => handleLikeComment(id)}
 * />
 * ```
 */

export interface User {
	id: string | number;
	name: string;
	avatar?: string;
	role?: string;
}

export interface Comment {
	id: string | number;
	user: User;
	text: string;
	timestamp: string | Date;
	parentId?: string | number | null;
	entityId: string | number;
	entityType: string;
	likes: number;
	isLiked?: boolean;
	replies?: number;
	status?: "published" | "pending" | "flagged" | "deleted";
	isPinned?: boolean;
	isEdited?: boolean;
	metadata?: Record<string, any>;
}

export interface CommentThreadProps {
	/**
	 * Array of comments to display
	 */
	comments: Comment[];
	/**
	 * ID of the current user
	 */
	currentUserId?: string | number;
	/**
	 * Whether the thread is loading
	 */
	isLoading?: boolean;
	/**
	 * Maximum nesting level for replies (default: 3)
	 */
	maxNestingLevel?: number;
	/**
	 * Whether to allow adding new comments
	 */
	allowComments?: boolean;
	/**
	 * Whether to show reply form by default
	 */
	showReplyForm?: boolean;
	/**
	 * Placeholder text for the comment input
	 */
	commentPlaceholder?: string;
	/**
	 * Whether to collapse long comments
	 */
	collapseComments?: boolean;
	/**
	 * Maximum comment length before collapsing
	 */
	maxCommentLength?: number;
	/**
	 * Whether to auto-expand the newest comment
	 */
	autoExpandNewest?: boolean;
	/**
	 * Callback for adding a new comment
	 */
	onAddComment?: (text: string, parentId?: string | number | null) => void;
	/**
	 * Callback for editing a comment
	 */
	onEditComment?: (id: string | number, text: string) => void;
	/**
	 * Callback for deleting a comment
	 */
	onDeleteComment?: (id: string | number) => void;
	/**
	 * Callback for liking a comment
	 */
	onLikeComment?: (id: string | number, isLiked: boolean) => void;
	/**
	 * Callback for reporting a comment
	 */
	onReportComment?: (id: string | number, reason?: string) => void;
	/**
	 * Callback for moderating a comment
	 */
	onModerateComment?: (
		id: string | number,
		action: "approve" | "reject" | "flag",
	) => void;
	/**
	 * Callback for pinning a comment
	 */
	onPinComment?: (id: string | number, isPinned: boolean) => void;
	/**
	 * CSS class for the container
	 */
	className?: string;
}

// Recursive function to build the comment tree
const buildCommentTree = (
	comments: Comment[],
	parentId: string | number | null = null,
): Comment[] => {
	return comments
		.filter((comment) => comment.parentId === parentId)
		.sort((a, b) => {
			// Sort pinned comments first
			if (a.isPinned && !b.isPinned) return -1;
			if (!a.isPinned && b.isPinned) return 1;

			// Then sort by timestamp (newest first)
			return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();
		});
};

// Format timestamps
const formatTimestamp = (date: string | Date): string => {
	return formatDistanceToNow(new Date(date), { addSuffix: true });
};

export function CommentThread({
	comments = [],
	currentUserId,
	isLoading = false,
	maxNestingLevel = 3,
	allowComments = true,
	showReplyForm = false,
	commentPlaceholder = "Add a comment...",
	collapseComments = true,
	maxCommentLength = 300,
	autoExpandNewest = true,
	onAddComment,
	onEditComment,
	onDeleteComment,
	onLikeComment,
	onReportComment,
	onModerateComment,
	onPinComment,
	className,
}: CommentThreadProps) {
	const [replyingTo, setReplyingTo] = useState<string | number | null>(null);
	const [editingId, setEditingId] = useState<string | number | null>(null);
	const [topLevelText, setTopLevelText] = useState("");
	const [editText, setEditText] = useState("");
	const [replyText, setReplyText] = useState("");
	const [expandedComments, setExpandedComments] = useState<
		Record<string | number, boolean>
	>({});
	const [expandedThreads, setExpandedThreads] = useState<
		Record<string | number, boolean>
	>({});

	// Get the newest comment ID for auto-expanding if needed
	const newestCommentId =
		comments.length > 0
			? comments.reduce((newest, comment) =>
					new Date(comment.timestamp) > new Date(newest.timestamp)
						? comment
						: newest,
				).id
			: null;

	// Initialize expanded states if not already set
	if (autoExpandNewest && newestCommentId && comments.length > 0) {
		expandedComments[newestCommentId] = true;
	}

	// Handle submitting a top-level comment
	const handleSubmitTopLevelComment = () => {
		if (topLevelText.trim() && onAddComment) {
			onAddComment(topLevelText.trim());
			setTopLevelText("");
		}
	};

	// Handle submitting a reply
	const handleSubmitReply = (parentId: string | number) => {
		if (replyText.trim() && onAddComment) {
			onAddComment(replyText.trim(), parentId);
			setReplyText("");
			setReplyingTo(null);
		}
	};

	// Handle submitting an edit
	const handleSubmitEdit = (id: string | number) => {
		if (editText.trim() && onEditComment) {
			onEditComment(id, editText.trim());
			setEditText("");
			setEditingId(null);
		}
	};

	// Handle liking a comment
	const handleLikeComment = (id: string | number, isLiked: boolean) => {
		onLikeComment?.(id, !isLiked);
	};

	// Toggle comment expansion
	const toggleCommentExpansion = (id: string | number) => {
		setExpandedComments((prev) => ({
			...prev,
			[id]: !prev[id],
		}));
	};

	// Toggle thread expansion
	const toggleThreadExpansion = (id: string | number) => {
		setExpandedThreads((prev) => ({
			...prev,
			[id]: !prev[id],
		}));
	};

	// Check if user can edit/delete a comment
	const canManageComment = (comment: Comment) => {
		if (!currentUserId) return false;
		return comment.user.id === currentUserId;
	};

	// Check if user is a moderator
	const isModerator = () => {
		// In a real app, you'd check the user's role
		return false;
	};

	// Render a single comment
	const renderComment = (comment: Comment, level: number = 0) => {
		const isExpanded = expandedComments[comment.id] || !collapseComments;
		const isThreadExpanded = expandedThreads[comment.id] !== false; // Default to expanded
		const isEditing = editingId === comment.id;
		const isReplying = replyingTo === comment.id;

		// Get replies for this comment
		const replies = buildCommentTree(comments, comment.id);

		// Check if comment text needs truncation
		const needsTruncation = comment.text.length > maxCommentLength;
		const displayText =
			needsTruncation && !isExpanded
				? `${comment.text.substring(0, maxCommentLength)}...`
				: comment.text;

		// Determine if nesting should continue
		const shouldNestReplies = level < maxNestingLevel;

		return (
			<div
				className={cn(
					"group",
					level > 0 && "ml-6 mt-3",
					comment.isPinned &&
						"relative bg-muted/20 p-3 rounded-md border-l-2 border-primary",
				)}
				key={comment.id}
			>
				{/* Pinned indicator */}
				{comment.isPinned && (
					<div className="absolute -left-1 -top-2">
						<Badge
							variant="outline"
							className="bg-background text-xs px-2 py-0"
						>
							Pinned
						</Badge>
					</div>
				)}

				<div className="flex gap-3">
					{/* User avatar */}
					<Avatar className="h-8 w-8 flex-shrink-0">
						<AvatarImage src={comment.user.avatar} alt={comment.user.name} />
						<AvatarFallback>{comment.user.name.charAt(0)}</AvatarFallback>
					</Avatar>

					{/* Comment content */}
					<div className="flex-1 space-y-1.5">
						{/* Comment header */}
						<div className="flex items-center justify-between">
							<div className="flex items-center gap-2">
								<span className="font-medium text-sm">{comment.user.name}</span>

								{/* User role badge */}
								{comment.user.role && (
									<Badge variant="outline" className="text-xs px-1 h-4">
										{comment.user.role}
									</Badge>
								)}

								{/* Comment status */}
								{comment.status === "pending" && (
									<Badge
										variant="outline"
										className="text-xs px-1 h-4 bg-amber-50 text-amber-700 border-amber-200"
									>
										Pending
									</Badge>
								)}
								{comment.status === "flagged" && (
									<Badge
										variant="outline"
										className="text-xs px-1 h-4 bg-red-50 text-red-700 border-red-200"
									>
										Flagged
									</Badge>
								)}

								<span className="text-xs text-muted-foreground">
									{formatTimestamp(comment.timestamp)}
								</span>

								{comment.isEdited && (
									<span className="text-xs text-muted-foreground">
										(edited)
									</span>
								)}
							</div>

							{/* Comment actions */}
							<DropdownMenu>
								<DropdownMenuTrigger asChild>
									<Button
										variant="ghost"
										size="icon"
										className="h-7 w-7 opacity-0 group-hover:opacity-100"
									>
										<MoreVertical className="h-4 w-4" />
										<span className="sr-only">More</span>
									</Button>
								</DropdownMenuTrigger>
								<DropdownMenuContent align="end">
									{canManageComment(comment) && (
										<>
											<DropdownMenuItem
												onClick={() => {
													setEditingId(comment.id);
													setEditText(comment.text);
												}}
											>
												<Edit className="h-4 w-4 mr-2" />
												Edit
											</DropdownMenuItem>
											<DropdownMenuItem
												className="text-destructive focus:text-destructive"
												onClick={() => onDeleteComment?.(comment.id)}
											>
												<Trash2 className="h-4 w-4 mr-2" />
												Delete
											</DropdownMenuItem>
											<DropdownMenuSeparator />
										</>
									)}

									{isModerator() && (
										<>
											<DropdownMenuItem
												onClick={() =>
													onPinComment?.(comment.id, !comment.isPinned)
												}
											>
												<ThumbsUp className="h-4 w-4 mr-2" />
												{comment.isPinned ? "Unpin" : "Pin"}
											</DropdownMenuItem>
											{comment.status === "pending" && (
												<DropdownMenuItem
													onClick={() =>
														onModerateComment?.(comment.id, "approve")
													}
												>
													<ThumbsUp className="h-4 w-4 mr-2" />
													Approve
												</DropdownMenuItem>
											)}
											<DropdownMenuItem
												onClick={() => onModerateComment?.(comment.id, "flag")}
											>
												<AlertTriangle className="h-4 w-4 mr-2" />
												Flag
											</DropdownMenuItem>
											<DropdownMenuSeparator />
										</>
									)}

									<DropdownMenuItem
										onClick={() => onReportComment?.(comment.id)}
									>
										<AlertTriangle className="h-4 w-4 mr-2" />
										Report
									</DropdownMenuItem>
								</DropdownMenuContent>
							</DropdownMenu>
						</div>

						{/* Comment text */}
						{isEditing ? (
							<div className="space-y-2">
								<Textarea
									value={editText}
									onChange={(e) => setEditText(e.target.value)}
									className="min-h-[100px]"
									placeholder="Edit your comment..."
								/>
								<div className="flex justify-end gap-2">
									<Button
										variant="outline"
										size="sm"
										onClick={() => setEditingId(null)}
									>
										Cancel
									</Button>
									<Button
										size="sm"
										onClick={() => handleSubmitEdit(comment.id)}
										disabled={!editText.trim()}
									>
										Save
									</Button>
								</div>
							</div>
						) : (
							<div className="text-sm leading-relaxed">
								<p className="whitespace-pre-line">{displayText}</p>

								{/* Expand/collapse button */}
								{needsTruncation && (
									<Button
										variant="ghost"
										size="sm"
										className="h-auto px-2 py-1 text-xs"
										onClick={() => toggleCommentExpansion(comment.id)}
									>
										{isExpanded ? "Show less" : "Read more"}
									</Button>
								)}
							</div>
						)}

						{/* Comment actions */}
						{!isEditing && (
							<div className="flex items-center gap-2 text-sm">
								<Button
									variant="ghost"
									size="sm"
									className="h-7 px-2 gap-1.5"
									onClick={() =>
										handleLikeComment(comment.id, !!comment.isLiked)
									}
								>
									<Heart
										className={cn(
											"h-3.5 w-3.5",
											comment.isLiked && "fill-current text-destructive",
										)}
									/>
									<span>{comment.likes || 0}</span>
								</Button>

								<Button
									variant="ghost"
									size="sm"
									className="h-7 px-2 gap-1.5"
									onClick={() => setReplyingTo(isReplying ? null : comment.id)}
								>
									<Reply className="h-3.5 w-3.5" />
									<span>Reply</span>
								</Button>

								{/* Show/hide replies button */}
								{replies.length > 0 && (
									<Button
										variant="ghost"
										size="sm"
										className="h-7 px-2 gap-1.5"
										onClick={() => toggleThreadExpansion(comment.id)}
									>
										{isThreadExpanded ? (
											<>
												<ChevronUp className="h-3.5 w-3.5" />
												<span>Hide replies</span>
											</>
										) : (
											<>
												<ChevronDown className="h-3.5 w-3.5" />
												<span>
													Show {replies.length}{" "}
													{replies.length === 1 ? "reply" : "replies"}
												</span>
											</>
										)}
									</Button>
								)}
							</div>
						)}

						{/* Reply form */}
						{isReplying && (
							<div className="mt-3 space-y-2">
								<Textarea
									value={replyText}
									onChange={(e) => setReplyText(e.target.value)}
									placeholder="Write a reply..."
									className="min-h-[80px]"
								/>
								<div className="flex justify-end gap-2">
									<Button
										variant="outline"
										size="sm"
										onClick={() => setReplyingTo(null)}
									>
										Cancel
									</Button>
									<Button
										size="sm"
										onClick={() => handleSubmitReply(comment.id)}
										disabled={!replyText.trim()}
									>
										Reply
									</Button>
								</div>
							</div>
						)}

						{/* Nested replies */}
						{replies.length > 0 && isThreadExpanded && (
							<div
								className={cn(
									"mt-3",
									shouldNestReplies ? "" : "ml-0 border-l-2 border-border pl-3",
								)}
							>
								{replies.map((reply) =>
									shouldNestReplies
										? renderComment(reply, level + 1)
										: renderFlatReply(reply, comment),
								)}
							</div>
						)}
					</div>
				</div>
			</div>
		);
	};

	// Render a flat reply (used when max nesting level is reached)
	const renderFlatReply = (reply: Comment, _parentComment: Comment) => {
		return (
			<div className="py-2" key={reply.id}>
				<div className="flex items-center gap-2 mb-1">
					<Avatar className="h-6 w-6">
						<AvatarImage src={reply.user.avatar} alt={reply.user.name} />
						<AvatarFallback>{reply.user.name.charAt(0)}</AvatarFallback>
					</Avatar>
					<span className="font-medium text-sm">{reply.user.name}</span>
					<span className="text-xs text-muted-foreground">
						{formatTimestamp(reply.timestamp)}
					</span>
				</div>
				<div className="pl-8 text-sm">
					<p>{reply.text}</p>
					<div className="flex items-center gap-2 mt-1">
						<Button
							variant="ghost"
							size="sm"
							className="h-6 px-2 text-xs gap-1"
							onClick={() => handleLikeComment(reply.id, !!reply.isLiked)}
						>
							<Heart
								className={cn(
									"h-3 w-3",
									reply.isLiked && "fill-current text-destructive",
								)}
							/>
							<span>{reply.likes || 0}</span>
						</Button>
					</div>
				</div>
			</div>
		);
	};

	return (
		<div className={cn("space-y-6", className)}>
			{/* Comment count and sort controls */}
			<div className="flex items-center justify-between">
				<h3 className="text-lg font-medium">Comments ({comments.length})</h3>
			</div>

			{/* Top-level comment form */}
			{allowComments && currentUserId && (
				<div className="flex gap-3">
					<Avatar className="h-8 w-8 flex-shrink-0">
						{/* This would show current user's avatar */}
						<AvatarFallback>U</AvatarFallback>
					</Avatar>
					<div className="flex-1 space-y-2">
						<Textarea
							value={topLevelText}
							onChange={(e) => setTopLevelText(e.target.value)}
							placeholder={commentPlaceholder}
							className="min-h-[100px]"
						/>
						<div className="flex justify-end">
							<Button
								onClick={handleSubmitTopLevelComment}
								disabled={!topLevelText.trim()}
							>
								Comment
							</Button>
						</div>
					</div>
				</div>
			)}

			{/* Comments list */}
			<div className="space-y-4">
				{isLoading ? (
					// Loading skeleton
					[1, 2, 3].map((i) => (
						<div className="flex gap-3 animate-pulse" key={i}>
							<div className="h-8 w-8 rounded-full bg-muted"></div>
							<div className="flex-1 space-y-2">
								<div className="flex gap-2">
									<div className="h-4 w-24 bg-muted rounded"></div>
									<div className="h-4 w-16 bg-muted rounded"></div>
								</div>
								<div className="h-12 bg-muted rounded"></div>
							</div>
						</div>
					))
				) : comments.length === 0 ? (
					// Empty state
					<div className="text-center py-6 text-muted-foreground">
						<MessageSquare className="mx-auto h-8 w-8 mb-2 text-muted-foreground/50" />
						<p>No comments yet</p>
						{allowComments && (
							<p className="text-sm">Be the first to share your thoughts</p>
						)}
					</div>
				) : (
					// Render comment threads
					buildCommentTree(comments).map((comment) => renderComment(comment))
				)}
			</div>
		</div>
	);
}

export default CommentThread;
