"use client";

import { ApiResponse } from "@/types/types";
import request from "@/lib/request";
import "@schedule-x/theme-shadcn/dist/index.css";
import { useNextCalendarApp, ScheduleXCalendar } from "@schedule-x/react";
import { createEventsServicePlugin } from "@schedule-x/events-service";
import { createDragAndDropPlugin } from "@schedule-x/drag-and-drop";
import { createResizePlugin } from "@schedule-x/resize";
import { createEventRecurrencePlugin } from "@schedule-x/event-recurrence";
import { createViewDay, createViewWeek } from "@schedule-x/calendar";
import { useEffect, useState } from "react";
import { format } from "date-fns";
import { Dialog, DialogProps } from "@radix-ui/react-dialog";
import {
	DialogContent,
	DialogDescription,
	DialogFooter,
	DialogHeader,
	DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { KeyedMutator } from "swr";
import { getCookie } from "cookies-next";
import { useTheme } from "next-themes";
import { EventForm, eventFormSchema, EventFormValues } from "./event-dialog";
import ICalendarEvent from "@/interfaces/ICalendarEvent";
import { UseFormReturn } from "react-hook-form";
import mapFrequencyToRrule from "@/lib/mapFrequencyToRrule";

const Planning: React.FC<{
	events: ICalendarEvent[];
	mutate?: KeyedMutator<ApiResponse<ICalendarEvent[]>>;
}> = ({ events, mutate }) => {
	const { resolvedTheme } = useTheme();
	console.log(resolvedTheme);
	const isConnected = getCookie("auth_token");
	const plugins = isConnected
		? [
				createEventsServicePlugin(),
				createDragAndDropPlugin(),
				createResizePlugin(),
				createEventRecurrencePlugin(),
			]
		: [];
	const [eventSelected, setEventSelected] = useState<ICalendarEvent | null>(
		null,
	);
	const [newEvent, setNewEvent] = useState<Omit<ICalendarEvent, "id"> | null>(
		null,
	);

	const handleEventUpdate = async (
		eventSelected: ICalendarEvent | Omit<ICalendarEvent, "id">,
	) => {
		const event = {
			...eventSelected,
			start: `${new Date(eventSelected.start).toISOString()}`,
			end: `${new Date(eventSelected.end).toISOString()}`,
		} as ICalendarEvent;
		try {
			const res = await request<undefined>(`/events/${event.id}/update`, {
				method: "PATCH",
				body: event,
				requiresAuth: true,
				csrfToken: false,
			});
			if (res.status === "Error") {
				// calendar?.events?.update(oldEvent);
			}
		} catch (e) {
			console.log(e);
		}
	};

	const calendar = useNextCalendarApp(
		{
			theme: "shadcn",
			views: [createViewDay(), createViewWeek()],
			defaultView: "week",
			isDark: resolvedTheme === "dark" ? true : false,
			isResponsive: true,
			locale: "fr-FR",
			dayBoundaries: {
				start: "06:00",
				end: "00:00",
			},
			events: events.map((event) => ({
				...event,
				start: format(new Date(event.start), "yyyy-MM-dd HH:mm"),
				end: format(new Date(event.end), "yyyy-MM-dd HH:mm"),
			})),
			callbacks: {
				onEventClick(event, e) {
					setEventSelected(event as ICalendarEvent);
				},
				async onEventUpdate(newEvent) {
					await handleEventUpdate(newEvent as ICalendarEvent);
				},
			},
		},
		plugins,
	);

	useEffect(() => {
		calendar?.events.getAll();
	}, []);

	useEffect(() => {
		calendar?.setTheme(resolvedTheme === "dark" ? "dark" : "light");
	}, [resolvedTheme]);

	const AddButton: React.FC = () => (
		<Button onClick={() => setNewEvent({})} variant="outline">
			Nouveau
		</Button>
	);

	return (
		<div>
			<div className="m-8">
				<AddButton />
				<ScheduleXCalendar calendarApp={calendar} />
			</div>
			{newEvent && (
				<EventDialog
					open={newEvent !== null || false}
					onOpenChange={(open) => {
						setNewEvent((e) => (open ? e : null));
					}}
					onAdd={async (formValues) => {
						const rrule = mapFrequencyToRrule(
							formValues.frequency,
							formValues.frequencyEndDate,
						);
						const [sHours, sMinutes] =
							formValues.startTime.split(":");
						formValues.startDate.setHours(
							parseInt(sHours),
							parseInt(sMinutes),
						);
						const [eHours, eMinutes] =
							formValues.endTime.split(":");
						formValues.endDate.setHours(
							parseInt(eHours),
							parseInt(eMinutes),
						);
						const event: Omit<ICalendarEvent, "id"> = {
							...newEvent,
							start: formValues.startDate.toISOString(),
							end: formValues.endDate.toISOString(),
							title: `${formValues.title}`,
							fullday: formValues.fullDay,
							rrule: rrule,
							isVisible: formValues.isVisible,
						};
						const res = await request<undefined>(`/events/new`, {
							method: "POST",
							body: event,
							requiresAuth: true,
							csrfToken: false,
						});
						if (res.status === "Error") {
							console.log("Error");
						}
						if (res.status === "Success") {
							mutate?.();
							console.log("Success");
						}
					}}
					event={newEvent}
				/>
			)}
			{eventSelected && (
				<EventDialog
					open={eventSelected !== null || false}
					onOpenChange={(open) => {
						setEventSelected((e) => (open ? e : null));
					}}
					event={eventSelected}
					onDelete={async (id) => {
						calendar?.events?.remove(id);
						try {
							const res = await request<undefined>(
								`/events/${id}/delete`,
								{
									method: "DELETE",
									requiresAuth: false,
									csrfToken: false,
								},
							);
							if (res.status === "Error") {
								console.log("Error");
							}
							if (res.status === "Success") {
								console.log("Success");
							}
						} catch (e) {
							console.log(e);
						}
						setEventSelected(null);
					}}
					onUpdate={async (formValues) => {
						const rrule = mapFrequencyToRrule(
							formValues.frequency,
							formValues.frequencyEndDate,
						);
						const [sHours, sMinutes] =
							formValues.startTime.split(":");
						formValues.startDate.setHours(
							parseInt(sHours),
							parseInt(sMinutes),
						);
						const [eHours, eMinutes] =
							formValues.endTime.split(":");
						formValues.endDate.setHours(
							parseInt(eHours),
							parseInt(eMinutes),
						);
						const event: ICalendarEvent = {
							...eventSelected,
							start: formValues.startDate.toISOString(),
							end: formValues.endDate.toISOString(),
							title: `${formValues.title}`,
							fullday: formValues.fullDay,
							rrule: rrule,
							isVisible: formValues.isVisible,
						};
						await handleEventUpdate(event);
						setEventSelected(null);
					}}
				/>
			)}
		</div>
	);
};

const EventDialog: React.FC<
	{
		onDelete?: (id: string) => void;
		onUpdate?: (formValues: EventFormValues) => void;
		onAdd?: (formValues: EventFormValues) => void;
		event: ICalendarEvent | Omit<ICalendarEvent, "id">;
	} & DialogProps
> = ({ open, onOpenChange, onDelete, onUpdate, onAdd, event }) => {
	const [form, setForm] = useState<UseFormReturn<EventFormValues>>();

	const handleOnAdd = (data: EventFormValues) => {
		onAdd?.(data);
	};

	const onSubmit = (data: EventFormValues) => {
		try {
			const validatedData = eventFormSchema.parse(data);
			handleOnAdd(data);
		} catch (e) {
			console.error(e);
		}
	};

	return (
		<Dialog open={open} onOpenChange={onOpenChange}>
			<DialogContent className="sm:max-w-md">
				<DialogHeader>
					<DialogTitle>{event.title}</DialogTitle>
					<DialogDescription>{event.description}</DialogDescription>
				</DialogHeader>
				<EventForm event={event} onSubmit={onSubmit} />
				<DialogFooter className="flex flex-row justify-end">
					{onUpdate && (
						<Button
							variant="outline"
							onClick={() => {
								form?.handleSubmit((data) => {
									console.log(data);
									try {
										const validatedData =
											eventFormSchema.parse(data);
										console.log(validatedData);
										onUpdate(validatedData);
									} catch (e) {
										console.error(e);
									}
								});
							}}
							type="submit"
						>
							Actualiser
						</Button>
					)}
					{onDelete && (
						<Button
							variant="destructive"
							onClick={() => onDelete(event.id)}
							type="submit"
						>
							Supprimer
						</Button>
					)}
					{onAdd && !onUpdate && !onDelete && (
						<Button
							onClick={() => form?.handleSubmit((data) => {})}
							type="submit"
						>
							Créer
						</Button>
					)}
				</DialogFooter>
			</DialogContent>
		</Dialog>
	);
};

export default Planning;
