"use client";

import { useState } from "react";
import { CalendarIcon, Plus, X, ChevronLeft, ChevronRight, Trash2 } from "lucide-react";
import { Booking, PublicUser, Station, User } from "@repo/db";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { deleteBookingAPI, getBookingsAPI } from "(app)/_querys/bookings";
import { Button } from "@repo/shared-components";
import { formatTimeRange } from "../../helper/timerange";
import toast from "react-hot-toast";

interface BookingTimelineModalProps {
	isOpen: boolean;
	onClose: () => void;
	onOpenNewBooking: () => void;
	currentUser: User;
}

type ViewMode = "day" | "week" | "month";

export const BookingTimelineModal = ({
	isOpen,
	onClose,
	onOpenNewBooking,
	currentUser,
}: BookingTimelineModalProps) => {
	const queryClient = useQueryClient();
	const [currentDate, setCurrentDate] = useState(new Date());
	const [viewMode, setViewMode] = useState<ViewMode>("day");
	const getTimeRange = () => {
		const start = new Date(currentDate);
		const end = new Date(currentDate);

		switch (viewMode) {
			case "day":
				start.setHours(0, 0, 0, 0);
				end.setHours(23, 59, 59, 999);
				break;
			case "week": {
				const dayOfWeek = start.getDay();
				const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
				start.setDate(start.getDate() + mondayOffset);
				start.setHours(0, 0, 0, 0);
				end.setDate(start.getDate() + 6);
				end.setHours(23, 59, 59, 999);
				break;
			}
			case "month":
				start.setDate(1);
				start.setHours(0, 0, 0, 0);
				end.setMonth(end.getMonth() + 1);
				end.setDate(0);
				end.setHours(23, 59, 59, 999);
				break;
		}

		return { start, end };
	};

	const { data: bookings, isLoading: isBookingsLoading } = useQuery({
		queryKey: ["bookings", getTimeRange().start, getTimeRange().end],
		queryFn: () =>
			getBookingsAPI({
				startTime: {
					gte: getTimeRange().start,
				},
				endTime: {
					lte: getTimeRange().end,
				},
			}),
	});

	const { mutate: deleteBooking } = useMutation({
		mutationKey: ["deleteBooking"],
		mutationFn: async (bookingId: string) => {
			await deleteBookingAPI(bookingId);
			queryClient.invalidateQueries({ queryKey: ["bookings"] });
		},
		onSuccess: () => {
			toast.success("Buchung erfolgreich gelöscht");
		},
	});

	// Check if user can create bookings
	const canCreateBookings =
		currentUser &&
		currentUser.emailVerified &&
		!currentUser.isBanned &&
		(currentUser.permissions.includes("PILOT") || currentUser.permissions.includes("DISPO"));

	// Check if user can delete a booking
	const canDeleteBooking = (bookingUserPublicId: string) => {
		if (!currentUser) return false;
		if (currentUser.permissions.includes("ADMIN_BOOKING")) return true;

		// User can delete their own bookings if they meet basic requirements
		if (bookingUserPublicId === currentUser.publicId) {
			return true;
		}

		// Admins can delete any booking
		return false;
	};

	const navigate = (direction: "prev" | "next") => {
		const newDate = new Date(currentDate);

		switch (viewMode) {
			case "day":
				newDate.setDate(newDate.getDate() + (direction === "next" ? 1 : -1));
				break;
			case "week":
				newDate.setDate(newDate.getDate() + (direction === "next" ? 7 : -7));
				break;
			case "month":
				newDate.setMonth(newDate.getMonth() + (direction === "next" ? 1 : -1));
				break;
		}

		setCurrentDate(newDate);
	};

	const formatDateRange = () => {
		const { start, end } = getTimeRange();
		const options: Intl.DateTimeFormatOptions = {
			day: "2-digit",
			month: "2-digit",
			year: "numeric",
		};

		switch (viewMode) {
			case "day":
				return start.toLocaleDateString("de-DE", options);
			case "week":
				return `${start.toLocaleDateString("de-DE", options)} - ${end.toLocaleDateString("de-DE", options)}`;
			case "month":
				return start.toLocaleDateString("de-DE", { month: "long", year: "numeric" });
		}
	};

	const groupBookingsByResource = () => {
		if (!bookings) return {};
		// For day view, group by resource (station/type)
		if (viewMode === "day") {
			const groups: Record<string, (Booking & { Station: Station; User: PublicUser })[]> = {};

			bookings.forEach((booking) => {
				let key: string = booking.type;
				if (booking.Station) {
					key = `${booking.Station.bosCallsign}`;
				}

				if (!groups[key]) {
					groups[key] = [];
				}
				groups[key]!.push(booking);
			});

			// Sort bookings within each group, LST_ types first, then alphanumerical
			Object.keys(groups).forEach((key) => {
				groups[key] = groups[key]!.sort((a, b) => {
					const aIsLST = a.type.startsWith("LST_");
					const bIsLST = b.type.startsWith("LST_");
					if (aIsLST && !bIsLST) return -1;
					if (!aIsLST && bIsLST) return 1;
					// Within same category (both LST_ or both non-LST_), sort alphanumerically by type
					return a.type.localeCompare(b.type);
				});
			});

			// Sort the groups themselves - LST_ types first, then alphabetical
			const sortedGroups: Record<string, (Booking & { Station: Station; User: PublicUser })[]> = {};
			Object.keys(groups)
				.sort((a, b) => {
					// Check if groups contain LST_ types
					const aHasLST = groups[a]?.some((booking) => booking.type.startsWith("LST_"));
					const bHasLST = groups[b]?.some((booking) => booking.type.startsWith("LST_"));
					if (aHasLST && !bHasLST) return -1;
					if (!aHasLST && bHasLST) return 1;
					// Within same category, sort alphabetically by group name
					return a.localeCompare(b);
				})
				.forEach((key) => {
					sortedGroups[key] = groups[key]!;
				});

			return sortedGroups;
		}

		// For week and month views, group by date
		const groups: Record<string, (Booking & { Station: Station; User: PublicUser })[]> = {};

		bookings.forEach((booking) => {
			const dateKey = new Date(booking.startTime).toLocaleDateString("de-DE", {
				weekday: "long",
				day: "2-digit",
				month: "2-digit",
				year: "numeric",
			});

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

		// Sort groups by date for week/month view and sort bookings within each group
		const sortedGroups: Record<string, (Booking & { Station: Station; User: PublicUser })[]> = {};
		Object.keys(groups)
			.sort((a, b) => {
				// Extract date from the formatted string and compare
				const dateA = groups[a]?.[0]?.startTime;
				const dateB = groups[b]?.[0]?.startTime;
				if (!dateA || !dateB) return 0;
				return new Date(dateA).getTime() - new Date(dateB).getTime();
			})
			.forEach((key) => {
				const bookingsForKey = groups[key];
				if (bookingsForKey) {
					// Sort bookings within each date group, LST_ types first, then alphanumerical
					sortedGroups[key] = bookingsForKey.sort((a, b) => {
						const aIsLST = a.type.startsWith("LST_");
						const bIsLST = b.type.startsWith("LST_");
						if (aIsLST && !bIsLST) return -1;
						if (!aIsLST && bIsLST) return 1;
						// Within same category (both LST_ or both non-LST_), sort alphanumerically by type
						return a.type.localeCompare(b.type);
					});
				}
			});

		return sortedGroups;
	};

	if (!isOpen) return null;

	const groupedBookings = groupBookingsByResource();

	return (
		<div className="modal modal-open">
			<div className="modal-box flex max-h-[83vh] w-11/12 max-w-7xl flex-col">
				<div className="mb-4 flex items-center justify-between">
					<h3 className="flex items-center gap-2 text-lg font-bold">
						<CalendarIcon size={24} />
						Slot Buchung
					</h3>
					<button className="btn btn-sm btn-circle btn-ghost" onClick={onClose}>
						<X size={20} />
					</button>
				</div>

				{/* Controls */}
				<div className="mb-6 flex items-center justify-between">
					<div className="flex items-center gap-2">
						<button className="btn btn-sm btn-ghost" onClick={() => navigate("prev")}>
							<ChevronLeft size={16} />
						</button>
						<span className="min-w-[200px] text-center font-medium">{formatDateRange()}</span>
						<button className="btn btn-sm btn-ghost" onClick={() => navigate("next")}>
							<ChevronRight size={16} />
						</button>
					</div>

					<div className="join">
						{(["day", "week", "month"] as ViewMode[]).map((mode) => (
							<button
								key={mode}
								className={`btn btn-sm join-item ${viewMode === mode ? "btn-active" : ""}`}
								onClick={() => setViewMode(mode)}
							>
								{mode === "day" ? "Tag" : mode === "week" ? "Woche" : "Monat"}
							</button>
						))}
					</div>
				</div>

				{isBookingsLoading ? (
					<div className="flex justify-center py-8">
						<span className="loading loading-spinner loading-lg"></span>
					</div>
				) : (
					<div className="grid max-h-[calc(83vh-200px)] grid-cols-1 gap-3 overflow-y-auto md:grid-cols-2">
						{Object.entries(groupedBookings).map(([groupName, resourceBookings]) => (
							<div key={groupName} className="card bg-base-200 shadow-sm">
								<div className="card-body p-3">
									<h4 className="mb-2 text-sm font-medium opacity-70">
										{viewMode === "day" ? groupName : groupName}
									</h4>
									<div className="space-y-1">
										{resourceBookings.map((booking) => (
											<div
												key={booking.id}
												className={`alert alert-horizontal ${booking.type.startsWith("LST_") ? "alert-success" : "alert-info"} alert-soft px-3 py-2`}
											>
												<div className="flex items-center gap-3">
													<span className="badge badge-outline text-xs">
														{booking.type.startsWith("LST_")
															? "LST"
															: booking.Station.bosCallsignShort || booking.Station.bosCallsign}
													</span>
													<span className="text-sm font-medium">{booking.User.fullName}</span>
												</div>
												<div className="flex items-center gap-2">
													<div className="text-right">
														<p className="text-xs font-medium">{formatTimeRange(booking)}</p>
													</div>
													{canDeleteBooking(booking.User.publicId) && (
														<Button
															onClick={() => deleteBooking(booking.id)}
															className={`btn btn-xs ${
																currentUser?.permissions.includes("ADMIN_EVENT") &&
																booking.User.publicId !== currentUser.publicId
																	? "btn-error"
																	: "btn-neutral"
															}`}
															title="Buchung löschen"
														>
															<Trash2 size={12} />
														</Button>
													)}
												</div>
											</div>
										))}
									</div>
								</div>
							</div>
						))}
						{Object.keys(groupedBookings).length === 0 && !isBookingsLoading && (
							<div className="col-span-full py-8 text-center opacity-70">
								Keine Buchungen im aktuellen Zeitraum gefunden
							</div>
						)}
					</div>
				)}

				<div className="modal-action">
					{canCreateBookings && (
						<button className="btn btn-primary" onClick={onOpenNewBooking}>
							<Plus size={20} />
							Neue Buchung
						</button>
					)}
					<button className="btn" onClick={onClose}>
						Schließen
					</button>
				</div>
			</div>
		</div>
	);
};
