"use client";

import { formatDistanceToNow } from "date-fns";
import { fr } from "date-fns/locale";
import {
	ArrowLeft,
	Check,
	CheckCheck,
	Search,
	Send,
	UserPlus,
	X,
} from "lucide-react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import * as React from "react";
import { toast } from "sonner";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { ScrollArea } from "@/components/ui/scroll-area";
import { useAuth } from "@/providers/auth-provider";
import { useSocket } from "@/providers/socket-provider";
import {
	type Conversation,
	type Message,
	MessageService,
} from "@/services/message.service";
import { UserService } from "@/services/user.service";
import type { User } from "@/types/user";

export default function MessagesPage() {
	const { user } = useAuth();
	const { socket } = useSocket();
	const _router = useRouter();
	const searchParams = useSearchParams();
	const targetUserId = searchParams.get("user");

	const [conversations, setConversations] = React.useState<Conversation[]>([]);
	const [activeConv, setActiveConv] = React.useState<Conversation | null>(null);
	const [messages, setMessages] = React.useState<Message[]>([]);
	const [newMessage, setNewMessage] = React.useState("");
	const typingTimeoutRef = React.useRef<NodeJS.Timeout | null>(null);

	const handleTyping = () => {
		if (!socket || !activeConv) return;

		socket.emit("typing", {
			recipientId: activeConv.recipient.uuid,
			isTyping: true,
		});

		if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);

		typingTimeoutRef.current = setTimeout(() => {
			socket.emit("typing", {
				recipientId: activeConv.recipient.uuid,
				isTyping: false,
			});
		}, 3000);
	};
	const [isLoadingConvs, setIsLoadingConvs] = React.useState(true);
	const [isLoadingMsgs, setIsLoadingMsgs] = React.useState(false);
	const [isOtherTyping, setIsOtherTyping] = React.useState(false);
	const [onlineUsers, setOnlineUsers] = React.useState<Set<string>>(new Set());

	const [searchQuery, setSearchQuery] = React.useState("");
	const [searchResults, setSearchResults] = React.useState<User[]>([]);
	const [isSearching, setIsSearching] = React.useState(false);

	const scrollRef = React.useRef<HTMLDivElement>(null);

	// Charger les conversations initiales
	React.useEffect(() => {
		const fetchConvs = async () => {
			try {
				const data = await MessageService.getConversations();
				setConversations(data);

				// Si un utilisateur est spécifié dans l'URL, essayer de trouver la conversation
				if (targetUserId) {
					const existing = data.find((c) => c.recipient.uuid === targetUserId);
					if (existing) {
						setActiveConv(existing);
					} else {
						// Chercher les infos de l'utilisateur pour afficher une interface de chat vide
						try {
							const conv = await MessageService.getConversationWith(targetUserId);
							if (conv) {
								setConversations((prev) => [conv, ...prev]);
								setActiveConv(conv);
							}
						} catch (_e) {
							// Peut-être que l'utilisateur n'existe pas ou erreur
						}
					}
				}
			} catch (_error) {
				toast.error("Erreur lors du chargement des conversations");
			} finally {
				setIsLoadingConvs(false);
			}
		};
		fetchConvs();
	}, [targetUserId]);

	// Recherche d'utilisateurs
	React.useEffect(() => {
		const delayDebounceFn = setTimeout(async () => {
			if (searchQuery.length > 1) {
				setIsSearching(true);
				try {
					const results = await UserService.search(searchQuery);
					setSearchResults(results.filter((u) => u.uuid !== user?.uuid));
				} catch (_error) {
					console.error("Search failed");
				} finally {
					setIsSearching(false);
				}
			} else {
				setSearchResults([]);
			}
		}, 300);

		return () => clearTimeout(delayDebounceFn);
	}, [searchQuery, user?.uuid]);

	React.useEffect(() => {
		if (activeConv) {
			const fetchMsgs = async () => {
				setIsLoadingMsgs(true);
				try {
					const data = await MessageService.getMessages(activeConv.id);
					setMessages(data.reverse()); // Plus ancien au plus récent
				} catch (_error) {
					toast.error("Erreur lors du chargement des messages");
				} finally {
					setIsLoadingMsgs(false);
				}
			};
			fetchMsgs();
		}
	}, [activeConv]);

	React.useEffect(() => {
		if (socket) {
			socket.on(
				"new_message",
				(data: { conversationId: string; message: Message }) => {
					if (activeConv?.id === data.conversationId) {
						setMessages((prev) => [...prev, data.message]);
						setIsOtherTyping(false); // S'il a envoyé un message, il ne tape plus
						// Marquer comme lu immédiatement si on est sur la conversation
						MessageService.markAsRead(data.conversationId).catch(console.error);
					}
					// Mettre à jour la liste des conversations
					setConversations((prev) => {
						const index = prev.findIndex((c) => c.id === data.conversationId);
						if (index !== -1) {
							const updated = [...prev];
							updated[index] = {
								...updated[index],
								lastMessage: {
									text: data.message.text,
									createdAt: data.message.createdAt,
								},
								updatedAt: data.message.createdAt,
							};
							return updated.sort(
								(a, b) =>
									new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),
							);
						}
						return prev;
					});
				},
			);

			socket.on("user_status", (data: { userId: string; status: string }) => {
				setOnlineUsers((prev) => {
					const next = new Set(prev);
					if (data.status === "online") {
						next.add(data.userId);
					} else {
						next.delete(data.userId);
					}
					return next;
				});
			});

			socket.on("user_typing", (data: { userId: string; isTyping: boolean }) => {
				if (activeConv?.recipient.uuid === data.userId) {
					setIsOtherTyping(data.isTyping);
				}
			});

			socket.on(
				"messages_read",
				(data: { conversationId: string; readerId: string }) => {
					if (activeConv?.id === data.conversationId) {
						setMessages((prev) =>
							prev.map((msg) =>
								msg.senderId !== data.readerId && !msg.readAt
									? { ...msg, readAt: new Date().toISOString() }
									: msg,
							),
						);
					}
				},
			);

			return () => {
				socket.off("new_message");
				socket.off("user_status");
				socket.off("user_typing");
				socket.off("messages_read");
			};
		}
	}, [socket, activeConv]);

	React.useEffect(() => {
		if (scrollRef.current) {
			const scrollContainer = scrollRef.current.querySelector(
				"[data-slot='scroll-area-viewport']",
			);
			if (scrollContainer) {
				scrollContainer.scrollTop = scrollContainer.scrollHeight;
			}
		}
	}, []);

	const handleSendMessage = async (e: React.FormEvent) => {
		e.preventDefault();
		if (!newMessage.trim() || !activeConv) return;

		const text = newMessage.trim();
		setNewMessage("");

		try {
			const msg = await MessageService.sendMessage(
				activeConv.recipient.uuid,
				text,
			);

			// Si c'était une conv temporaire, on la remplace par la vraie
			if (activeConv.id.startsWith("temp-")) {
				const fetchConvs = async () => {
					const data = await MessageService.getConversations();
					setConversations(data);
					const realConv = data.find(
						(c) => c.recipient.uuid === activeConv.recipient.uuid,
					);
					if (realConv) setActiveConv(realConv);
				};
				fetchConvs();
			} else {
				setMessages((prev) => [...prev, msg]);
			}
		} catch (_error) {
			toast.error("Erreur lors de l'envoi");
		}
	};

	return (
		<div className="h-[calc(100vh-4rem)] flex overflow-hidden bg-white dark:bg-zinc-950">
			{/* Sidebar - Liste des conversations */}
			<div
				className={`w-full md:w-80 border-r flex flex-col ${
					activeConv ? "hidden md:flex" : "flex"
				}`}
			>
				<div className="p-4 border-b">
					<div className="flex items-center justify-between mb-4">
						<h2 className="text-xl font-bold">Messages</h2>
						<Button variant="ghost" size="icon" className="rounded-full">
							<UserPlus className="h-5 w-5" />
						</Button>
					</div>
					<div className="relative">
						<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
						<Input
							placeholder="Rechercher un membre..."
							className="pl-9"
							value={searchQuery}
							onChange={(e) => setSearchQuery(e.target.value)}
						/>
						{searchQuery && (
							<button
								type="button"
								onClick={() => setSearchQuery("")}
								className="absolute right-3 top-1/2 -translate-y-1/2 p-0.5 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-full"
							>
								<X className="h-3 w-3 text-muted-foreground" />
							</button>
						)}
					</div>
				</div>
				<ScrollArea className="flex-1">
					<div className="p-2 space-y-1">
						{searchQuery.length > 0 ? (
							<>
								<p className="px-3 py-2 text-[10px] font-bold uppercase tracking-wider text-muted-foreground">
									Membres
								</p>
								{isSearching ? (
									<div className="p-4 text-center text-sm text-muted-foreground">
										Recherche...
									</div>
								) : searchResults.length === 0 ? (
									<div className="p-4 text-center text-sm text-muted-foreground">
										Aucun membre trouvé.
									</div>
								) : (
									searchResults.map((result) => (
										<button
											key={result.uuid}
											type="button"
											onClick={async () => {
												setSearchQuery("");
												// Chercher si une conv existe déjà
												const existing = conversations.find(
													(c) => c.recipient.uuid === result.uuid,
												);
												if (existing) {
													setActiveConv(existing);
												} else {
													// Créer une interface de conv temporaire
													const newConv: Conversation = {
														id: `temp-${result.uuid}`,
														updatedAt: new Date().toISOString(),
														recipient: {
															uuid: result.uuid,
															username: result.username,
															displayName: result.displayName,
															avatarUrl: result.avatarUrl,
														},
													};
													setConversations((prev) => [newConv, ...prev]);
													setActiveConv(newConv);
												}
											}}
											className="w-full flex items-center gap-3 p-3 rounded-xl hover:bg-zinc-100 dark:hover:bg-zinc-900 transition-colors"
										>
											<Avatar className="h-10 w-10">
												<AvatarImage src={result.avatarUrl} />
												<AvatarFallback>{result.username[0].toUpperCase()}</AvatarFallback>
											</Avatar>
											<div className="flex-1 text-left overflow-hidden">
												<span className="font-bold block truncate">
													{result.displayName || result.username}
												</span>
												<span className="text-xs text-muted-foreground block truncate">
													@{result.username}
												</span>
											</div>
										</button>
									))
								)}
							</>
						) : isLoadingConvs ? (
							<div className="p-4 text-center text-sm text-muted-foreground">
								Chargement...
							</div>
						) : conversations.length === 0 ? (
							<div className="p-4 text-center text-sm text-muted-foreground">
								Aucune conversation.
							</div>
						) : (
							conversations.map((conv) => (
								<button
									key={conv.id}
									type="button"
									onClick={() => setActiveConv(conv)}
									className={`w-full flex items-center gap-3 p-3 rounded-xl transition-colors ${
										activeConv?.id === conv.id
											? "bg-primary/10 text-primary"
											: "hover:bg-zinc-100 dark:hover:bg-zinc-900"
									}`}
								>
									<Avatar isOnline={onlineUsers.has(conv.recipient.uuid)}>
										<AvatarImage src={conv.recipient.avatarUrl} />
										<AvatarFallback>
											{conv.recipient.username[0].toUpperCase()}
										</AvatarFallback>
									</Avatar>
									<div className="flex-1 text-left overflow-hidden">
										<div className="flex justify-between items-baseline">
											<span className="font-bold truncate">
												{conv.recipient.displayName || conv.recipient.username}
											</span>
											{conv.lastMessage && (
												<span className="text-[10px] text-muted-foreground whitespace-nowrap">
													{formatDistanceToNow(new Date(conv.lastMessage.createdAt), {
														locale: fr,
													})}
												</span>
											)}
										</div>
										<p className="text-xs text-muted-foreground truncate">
											{conv.lastMessage?.text || "Démarrer une conversation"}
										</p>
									</div>
								</button>
							))
						)}
					</div>
				</ScrollArea>
			</div>

			{/* Zone de chat */}
			<div
				className={`flex-1 flex flex-col ${
					!activeConv ? "hidden md:flex" : "flex"
				}`}
			>
				{activeConv ? (
					<>
						{/* Header */}
						<div className="p-4 border-b flex items-center gap-2">
							<Button
								variant="ghost"
								size="icon"
								className="md:hidden rounded-full"
								onClick={() => setActiveConv(null)}
							>
								<ArrowLeft className="h-5 w-5" />
							</Button>
							<Link
								href={`/user/${activeConv.recipient.username}`}
								className="flex-1 flex items-center gap-3 hover:opacity-80 transition-opacity"
							>
								<Avatar
									className="h-8 w-8"
									isOnline={onlineUsers.has(activeConv.recipient.uuid)}
								>
									<AvatarImage src={activeConv.recipient.avatarUrl} />
									<AvatarFallback>
										{activeConv.recipient.username[0].toUpperCase()}
									</AvatarFallback>
								</Avatar>
								<div>
									<h3 className="font-bold leading-none">
										{activeConv.recipient.displayName || activeConv.recipient.username}
									</h3>
									<span
										className={`text-xs font-medium ${
											onlineUsers.has(activeConv.recipient.uuid)
												? "text-green-500"
												: "text-muted-foreground"
										}`}
									>
										{onlineUsers.has(activeConv.recipient.uuid)
											? "En ligne"
											: "Hors ligne"}
									</span>
								</div>
							</Link>
						</div>

						{/* Messages */}
						<ScrollArea className="flex-1 p-4" viewportRef={scrollRef}>
							<div className="space-y-4">
								{isLoadingMsgs ? (
									<div className="text-center py-4 text-sm text-muted-foreground">
										Chargement...
									</div>
								) : (
									messages.map((msg) => (
										<div
											key={msg.id}
											className={`flex ${
												msg.senderId === user?.uuid ? "justify-end" : "justify-start"
											}`}
										>
											<div
												className={`max-w-[70%] p-3 rounded-2xl text-sm ${
													msg.senderId === user?.uuid
														? "bg-primary text-primary-foreground rounded-br-none"
														: "bg-zinc-100 dark:bg-zinc-800 rounded-bl-none"
												}`}
											>
												<p className="whitespace-pre-wrap">{msg.text}</p>
												<div
													className={`flex items-center gap-1 text-[10px] mt-1 ${
														msg.senderId === user?.uuid
															? "text-primary-foreground/70 justify-end"
															: "text-muted-foreground"
													}`}
												>
													<span>
														{new Date(msg.createdAt).toLocaleTimeString([], {
															hour: "2-digit",
															minute: "2-digit",
														})}
													</span>
													{msg.senderId === user?.uuid && (
														<span className="flex items-center">
															{msg.readAt ? (
																<CheckCheck className="h-3 w-3" />
															) : (
																<Check className="h-3 w-3" />
															)}
														</span>
													)}
												</div>
											</div>
										</div>
									))
								)}
								{isOtherTyping && (
									<div className="flex justify-start">
										<div className="bg-zinc-100 dark:bg-zinc-800 p-3 rounded-2xl rounded-bl-none">
											<div className="flex gap-1">
												<span className="w-1.5 h-1.5 bg-zinc-400 rounded-full animate-bounce [animation-delay:-0.3s]" />
												<span className="w-1.5 h-1.5 bg-zinc-400 rounded-full animate-bounce [animation-delay:-0.15s]" />
												<span className="w-1.5 h-1.5 bg-zinc-400 rounded-full animate-bounce" />
											</div>
										</div>
									</div>
								)}
							</div>
						</ScrollArea>

						{/* Input */}
						<div className="p-4 border-t">
							<form onSubmit={handleSendMessage} className="flex gap-2">
								<Input
									placeholder="Écrivez un message..."
									value={newMessage}
									onChange={(e) => {
										setNewMessage(e.target.value);
										handleTyping();
									}}
									className="rounded-full px-4"
								/>
								<Button
									type="submit"
									size="icon"
									className="rounded-full shrink-0"
									disabled={!newMessage.trim()}
								>
									<Send className="h-4 w-4" />
								</Button>
							</form>
						</div>
					</>
				) : (
					<div className="flex-1 flex flex-col items-center justify-center text-center p-8">
						<div className="bg-primary/10 p-6 rounded-full mb-4">
							<Send className="h-12 w-12 text-primary" />
						</div>
						<h2 className="text-2xl font-bold mb-2">Vos messages</h2>
						<p className="text-muted-foreground max-w-sm">
							Sélectionnez une conversation ou démarrez-en une nouvelle pour commencer
							à discuter.
						</p>
					</div>
				)}
			</div>
		</div>
	);
}
