import { add } from "date-fns";
import { Bug, Calculator, ClockAlert, Plus, Wrench } from "lucide-react";
import { useState } from "react";
import toast from "react-hot-toast";
import {
	Credenza,
	CredenzaBody,
	CredenzaContent,
	CredenzaDescription,
	CredenzaHeader,
	CredenzaTitle,
	CredenzaTrigger,
} from "~/components/custom_ui/credenza";
import { MultiSelect } from "~/components/custom_ui/multiselect";
import { LoadingPage } from "~/components/loading";
import {
	AlertDialog,
	AlertDialogAction,
	AlertDialogCancel,
	AlertDialogContent,
	AlertDialogDescription,
	AlertDialogFooter,
	AlertDialogHeader,
	AlertDialogTitle,
	AlertDialogTrigger,
} from "~/components/ui/alert-dialog";
import { Button } from "~/components/ui/button";
import {
	Collapsible,
	CollapsibleContent,
	CollapsibleTrigger,
} from "~/components/ui/collapsible";
import {
	Dialog,
	DialogContent,
	DialogDescription,
	DialogFooter,
	DialogHeader,
	DialogTitle,
	DialogTrigger,
} from "~/components/ui/dialog";
import {
	type FormValues as EditFormValues,
	FormEditServizio,
} from "~/forms/FormEditServizioAdmin";
import { FormNewServizio, type FormValues } from "~/forms/FormNewServizio";
import { useServizio } from "~/providers/ServizioProvider";
import type { AnnunciId } from "~/schemas/public/Annunci";
import type { ServizioServizioId } from "~/schemas/public/Servizio";
import type { UsersId } from "~/schemas/public/Users";
import { api } from "~/utils/api";

export const ServizioActions = () => {
	const { servizio, isAdmin, userId } = useServizio();

	const canUserEdit =
		servizio.isOkAcconto &&
		servizio.decorrenza !== null &&
		!servizio.annunci.some((a) => a.user_confirmed_at !== null);

	if (!isAdmin && !canUserEdit) {
		return null; // If the user is not an admin and cannot edit, do not render the actions
	}
	return (
		<div className="flex w-full flex-wrap justify-start gap-3 sm:justify-end">
			{(isAdmin || canUserEdit) && (
				<>
					<EditPreferenze />
					<InterruzioneServizio />
				</>
			)}
			{isAdmin && (
				<>
					<AddAnnuncio servizioId={servizio.servizio_id} userId={userId} />
					<EditServizioAdmin />
				</>
			)}
		</div>
	);
};

export const ServizioActions2 = () => {
	const { servizio, isAdmin, userId } = useServizio();

	const canUserEdit =
		servizio.isOkAcconto &&
		servizio.decorrenza !== null &&
		!servizio.annunci.some((a) => a.user_confirmed_at !== null);

	if (!isAdmin && !canUserEdit) {
		return null; // If the user is not an admin and cannot edit, do not render the actions
	}
	return (
		<div className="flex w-full flex-col flex-wrap justify-between gap-3 sm:flex-row">
			{(isAdmin || canUserEdit) && (
				<div className="flex items-center gap-3">
					<span className="hidden sm:block">Azioni: </span>
					<EditPreferenze />
					<InterruzioneServizio />
				</div>
			)}
			{isAdmin && (
				<div className="flex items-center gap-3">
					<AddAnnuncio servizioId={servizio.servizio_id} userId={userId} />
					<EditServizioAdmin />
				</div>
			)}
		</div>
	);
};
export const AddAnnuncio = ({
	servizioId,
	userId,
}: {
	servizioId: ServizioServizioId;
	userId: UsersId;
}) => {
	const { data: codici, isLoading: loading } =
		api.servizio.getAnnunciAvailableToAdd.useQuery({
			servizioId,
		});

	const [selectedAnnunci, setSelectedAnnunci] = useState<
		{ value: AnnunciId; label: string }[]
	>([]);

	const [openModal, setOpenModal] = useState(false);

	const utils = api.useUtils();
	const { mutate } = api.servizio.addServizioAnnunci.useMutation({
		onSuccess: async () => {
			await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
			await utils.servizio.getAnnunciAvailableToAdd.invalidate({
				servizioId,
			});
			await utils.servizio.getCompatibileAnnunci.invalidate({
				servizioId,
			});
			await utils.servizio.getUserServizi.invalidate({ userId });
			toast.success("Annuncio aggiunto");
			setOpenModal(false);
			setSelectedAnnunci([]);
		},
		onError: (error) => {
			console.error(error);
			toast.error("Errore durante l'aggiunta dell'annuncio");
		},
	});

	return (
		<Dialog open={openModal} onOpenChange={setOpenModal}>
			<DialogTrigger asChild>
				<Button
					aria-label="Add Annuncio"
					variant="outline"
					onClick={() => {
						setSelectedAnnunci([]);
					}}
					className="items-center gap-2"
				>
					<Plus />
					Annuncio
				</Button>
			</DialogTrigger>
			<DialogContent
				className="sm:max-w-[425px]"
				onInteractOutside={(e) => {
					if (selectedAnnunci.length !== 0) {
						e.preventDefault(); // Prevent closing the dialog if there are selected announcements
					}
				}}
			>
				<DialogHeader>
					<DialogTitle>Aggiungi annuncio</DialogTitle>
					<DialogDescription>
						Salva un annuncio nella ricerca dell&apos;utente
					</DialogDescription>
				</DialogHeader>
				<div className="grid gap-4 py-4">
					{loading ? (
						<LoadingPage />
					) : (
						<MultiSelect
							elementId="select-annuncio"
							elementName="annuncio"
							isMulti={true}
							placeholder=""
							defaultValue={undefined}
							options={
								codici?.map((cod) => ({
									label: cod.codice,
									value: cod.id.toString(),
								})) || []
							}
							onValueChange={(value) => {
								setSelectedAnnunci(
									value.map((v) => ({
										value: parseInt(v.value) as AnnunciId,
										label: v.label,
									})),
								);
							}}
						/>
					)}
				</div>
				<DialogFooter>
					<Button
						aria-label="Cancel Add Annuncio"
						type="button"
						onClick={() => {
							if (!selectedAnnunci.length) return;
							mutate({
								servizioId,
								annunci: selectedAnnunci.map((annuncio) => annuncio.value),
							});
						}}
						disabled={!selectedAnnunci.length}
					>
						Aggiungi
					</Button>
				</DialogFooter>
			</DialogContent>
		</Dialog>
	);
};

const InterruzioneServizio = () => {
	const { servizio, userId } = useServizio();

	const beforeInterruzioneLimit =
		servizio.decorrenza != null &&
		new Date() <=
			add(servizio.decorrenza, {
				days: 14,
			});

	const utils = api.useUtils();
	const { mutate } = api.servizio.interruzioneServizio.useMutation({
		onSuccess: async () => {
			await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
			toast.success("Interruzione richiesta");
		},
		onError: (error) => {
			console.error(error);
			toast.error("Errore durante la richiesta di interruzione");
		},
	});

	return (
		<AlertDialog>
			<AlertDialogTrigger asChild>
				<Button
					aria-label="Request Interruzione"
					variant="outline"
					className="items-center gap-2"
					disabled={!beforeInterruzioneLimit}
				>
					<ClockAlert /> <span>Interruzione</span>
				</Button>
			</AlertDialogTrigger>
			<AlertDialogContent>
				<AlertDialogHeader>
					<AlertDialogTitle>
						Sei sicuro di voler richiedere l&apos;interruzione?
					</AlertDialogTitle>
					<AlertDialogDescription>
						Questa azione è irreversibile e comporta la disattivazione dei
						servizi attivati. Confermando l&apos;azione recedi dal servizio
						secondo le condizioni contrattuali. Verrai notificato via email
						della conferma dell&apos;avvenuta interruzione.
					</AlertDialogDescription>
				</AlertDialogHeader>
				<AlertDialogFooter>
					<AlertDialogCancel>Annulla</AlertDialogCancel>
					<AlertDialogAction
						aria-label="Confirm Interruzione"
						onClick={() => mutate({ servizioId: servizio.servizio_id })}
					>
						Continua
					</AlertDialogAction>
				</AlertDialogFooter>
			</AlertDialogContent>
		</AlertDialog>
	);
};

const EditPreferenze = () => {
	const { servizioId, userId, isAdmin } = useServizio();
	const [openEditPreferenze, setOpenEditPreferenze] = useState(false);
	const { data, isLoading } = api.servizio.getServizio.useQuery({ servizioId });
	const utils = api.useUtils();

	const { mutate: update } = api.servizio.updateServizio.useMutation({
		onSuccess: async () => {
			toast.success("Servizio modificato con successo");
			await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
			await utils.servizio.getServizio.invalidate({ servizioId });
			await utils.servizio.getCompatibileAnnunci.invalidate({
				servizioId,
			});
			setOpenEditPreferenze(false);
		},
		onError: (error) => {
			toast.error(error.message);
		},
	});

	function onSubmit(fields: FormValues) {
		update({
			servizioId,
			data: {
				...fields,
			},
		});
	}

	return (
		<Credenza open={openEditPreferenze} onOpenChange={setOpenEditPreferenze}>
			<CredenzaTrigger asChild>
				<Button
					aria-label="Preferenze di ricerca"
					className="items-center gap-2"
				>
					<Calculator />
					Preferenze
				</Button>
			</CredenzaTrigger>
			<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">
				<CredenzaHeader>
					<CredenzaTitle>Preferenze di ricerca</CredenzaTitle>
					<CredenzaDescription className="sr-only">
						Preferenze
					</CredenzaDescription>
				</CredenzaHeader>
				<CredenzaBody className="max-h-[80vh] w-full overflow-y-auto pb-5">
					{isLoading ? (
						<LoadingPage />
					) : (
						<FormNewServizio
							initialData={data}
							onSubmit={onSubmit}
							isLimited={!isAdmin}
						/>
					)}
				</CredenzaBody>
			</CredenzaContent>
		</Credenza>
	);
};

const EditServizioAdmin = () => {
	const { servizioId, userId, servizio } = useServizio();
	const [open, setOpen] = useState(false);
	const { data, isLoading } = api.servizio.getServizio.useQuery({ servizioId });
	const utils = api.useUtils();

	const { mutate: update } = api.servizio.updateServizio.useMutation({
		onSuccess: async () => {
			toast.success("Servizio modificato con successo");
			await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
			await utils.servizio.getServizio.invalidate({ servizioId });
			await utils.servizio.getCompatibileAnnunci.invalidate({
				servizioId,
			});
			setOpen(false);
		},
		onError: (error) => {
			toast.error(error.message);
		},
	});

	function onSubmit(fields: EditFormValues) {
		update({
			servizioId,
			data: {
				...fields,
			},
		});
	}

	return (
		<Credenza open={open} onOpenChange={setOpen}>
			<CredenzaTrigger asChild>
				<Button
					aria-label="Modifica Servizio Admin"
					className="items-center gap-2"
				>
					<Wrench />
					Admin
				</Button>
			</CredenzaTrigger>
			<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">
				<CredenzaHeader>
					<CredenzaTitle>Modifica Servizio Admin</CredenzaTitle>
					<CredenzaDescription className="sr-only">
						Modifica
					</CredenzaDescription>
				</CredenzaHeader>
				<CredenzaBody className="max-h-[80vh] w-full space-y-2 overflow-y-auto pb-5">
					{isLoading ? (
						<LoadingPage />
					) : (
						<FormEditServizio initialData={data} onSubmit={onSubmit} />
					)}
					<Collapsible>
						<CollapsibleTrigger asChild>
							<Button variant="warning" className="items-center gap-2">
								<Bug /> Debug Info Servizio
							</Button>
						</CollapsibleTrigger>
						<CollapsibleContent>
							{(() => {
								// biome-ignore lint/correctness/noUnusedVariables: <need to extract>
								const { annunci, ...rest } = servizio;
								return <pre>{JSON.stringify(rest, null, 2)}</pre>;
							})()}
						</CollapsibleContent>
					</Collapsible>
				</CredenzaBody>
			</CredenzaContent>
		</Credenza>
	);
};
