import { add } from "date-fns";
import {
	Bug,
	CalendarClock,
	ChevronDown,
	ChevronUp,
	ClockAlert,
	Cog,
	Info,
	Plus,
	SlidersHorizontal,
	UserCircle,
} 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 { cn, formatCurrency } from "~/lib/utils";
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";
import { Progress } from "../ui/progress";

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

	return (
		<div className="flex w-full flex-col flex-wrap justify-between gap-3">
			{isAdmin && (
				<div className="flex items-center gap-3">
					<span className="font-semibold">Azioni Admin:</span>
					<AddAnnuncio servizioId={servizio.servizio_id} userId={userId} />
					<EditServizioAdmin />
				</div>
			)}
			<ServizioInfos />
		</div>
	);
};

const ServizioInfos = () => {
	const { servizio } = useServizio();
	const [open, setOpen] = useState(false);

	const openContattiAnnunci = servizio.annunci.filter(
		(a) => a.open_contatti_at !== null,
	);

	if (!servizio.decorrenza) return null;
	const dec_txt = new Date(servizio.decorrenza).toLocaleDateString("it-IT");
	const end_txt = new Date(
		add(servizio.decorrenza, { days: 60 }),
	).toLocaleDateString("it-IT");
	return (
		<Collapsible className="space-y-2" onOpenChange={setOpen} open={open}>
			<CollapsibleTrigger asChild>
				{open ? (
					<Button
						className="w-full justify-between data-[state=open]:bg-accent dark:data-[state=open]:bg-input/50"
						variant="outline"
					>
						<span className="flex items-center gap-2">
							<Info />
							<span>Informazioni servizio</span>
						</span>
						<span>
							<ChevronUp />
						</span>
					</Button>
				) : (
					<Button className="w-full justify-between" variant="outline">
						<div className="flex items-center gap-6">
							<span className="flex items-center gap-2">
								<UserCircle className="size-4 text-primary" />
								<span>{openContattiAnnunci.length} / 10</span>
							</span>
							<span className="flex items-center gap-2">
								<CalendarClock className="size-4 text-primary" />
								<span>{end_txt}</span>
							</span>
						</div>

						<div className="flex items-center gap-2">
							<span>Dettagli</span>
							<ChevronDown />
						</div>
					</Button>
				)}
			</CollapsibleTrigger>
			<CollapsibleContent className="mb-4 flex w-full flex-col gap-8 rounded-md border bg-card p-2 sm:items-start sm:gap-4">
				<ServizioBasicActions />
				<div className="flex w-full flex-col gap-8 sm:flex-row sm:items-start">
					<div className="flex flex-2 flex-col gap-2 sm:w-1/2">
						<div className="flex items-center justify-between">
							<div className="flex items-center gap-2">
								<UserCircle className="text-primary" />
								<span className="font-medium">Contatti sbloccati</span>
							</div>
							<span className="text-sm">{openContattiAnnunci.length} / 10</span>
						</div>
						<Progress className="h-2" value={openContattiAnnunci.length * 10} />
					</div>
					<div className="flex flex-col flex-wrap gap-2 sm:w-1/2 sm:flex-row sm:items-center">
						<div className="flex items-center gap-2">
							<CalendarClock className="text-primary" />
							<span className="font-medium">Durata servizio:</span>
						</div>
						<span>
							{dec_txt} - {end_txt}
						</span>
					</div>
				</div>
				<ServizioPacksInfos />
			</CollapsibleContent>
		</Collapsible>
	);
};

const ServizioBasicActions = ({ className }: { className?: string }) => {
	const { servizio, isAdmin } = useServizio();

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

	if (isAdmin || canUserEdit) {
		return (
			<div className={cn("flex flex-wrap items-center gap-3", className)}>
				<EditParametri />
				<InterruzioneServizio />
			</div>
		);
	}
	return null;
};

const ServizioPacksInfos = () => {
	const { servizio } = useServizio();
	const { data: packs } = api.servizio.getPacksSolution.useQuery({
		servizioId: servizio.servizio_id,
	});
	if (!packs) return null;
	return (
		<div className="w-full space-y-2">
			<h3 className="font-semibold text-lg">Prezzi:</h3>
			<div className="flex w-full flex-col gap-4 md:flex-row">
				<div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2">
					{packs.acconto.success ? (
						<>
							<span className="font-medium">{packs.acconto.pack.nome_it}</span>
							<span className="text-muted-foreground text-sm">
								{packs.acconto.pack.desc_it}
							</span>
							<span className="font-semibold text-lg">
								{formatCurrency(packs.acconto.pack.prezzo_cent / 100)}
							</span>
							<span className="text-muted-foreground text-sm">
								COD: {packs.acconto.pack.idprezziario}
							</span>
						</>
					) : (
						<span className="font-medium">{packs.acconto.message}</span>
					)}
				</div>

				<div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2">
					{packs.saldo.success ? (
						<>
							<span className="font-medium">{packs.saldo.pack.nome_it}</span>
							<span className="text-muted-foreground text-sm">
								{packs.saldo.pack.desc_it}
							</span>
							<span className="font-semibold text-lg">
								{formatCurrency(packs.saldo.pack.prezzo_cent / 100)}
							</span>
							<span className="text-muted-foreground text-sm">
								COD: {packs.saldo.pack.idprezziario}
							</span>
						</>
					) : (
						<span className="font-medium">{packs.saldo.message}</span>
					)}
				</div>
			</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({
		onError: (error) => {
			console.error(error);
			toast.error("Errore durante l'aggiunta dell'annuncio");
		},
		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([]);
		},
	});

	return (
		<Dialog onOpenChange={setOpenModal} open={openModal}>
			<DialogTrigger asChild>
				<Button
					aria-label="Add Annuncio"
					className=""
					onClick={() => {
						setSelectedAnnunci([]);
					}}
					variant="outline"
				>
					<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
							defaultValue={undefined}
							elementId="select-annuncio"
							elementName="annuncio"
							isMulti={true}
							onValueChange={(value) => {
								setSelectedAnnunci(
									value.map((v) => ({
										label: v.label,
										value: parseInt(v.value) as AnnunciId,
									})),
								);
							}}
							options={
								codici?.map((cod) => ({
									label: cod.codice,
									value: cod.id.toString(),
								})) || []
							}
							placeholder=""
						/>
					)}
				</div>
				<DialogFooter>
					<Button
						aria-label="Cancel Add Annuncio"
						disabled={!selectedAnnunci.length}
						onClick={() => {
							if (!selectedAnnunci.length) return;
							mutate({
								annunci: selectedAnnunci.map((annuncio) => annuncio.value),
								servizioId,
							});
						}}
						type="button"
					>
						Aggiungi
					</Button>
				</DialogFooter>
			</DialogContent>
		</Dialog>
	);
};

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

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

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

	return (
		<AlertDialog>
			<AlertDialogTrigger asChild>
				<Button
					aria-label="Request Interruzione"
					className=""
					disabled={
						!isAdmin &&
						(!beforeInterruzioneLimit ||
							servizio.isInterrotto ||
							servizio.annunci.some((a) => a.user_confirmed_at !== null))
					}
				>
					<ClockAlert /> <span>Richiedi 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 EditParametri = () => {
	const { servizioId, userId, isAdmin, servizio } = useServizio();
	const [openEditParametri, setOpenEditParametri] = useState(false);
	const { data, isLoading } = api.servizio.getServizio.useQuery({ servizioId });
	const utils = api.useUtils();

	const { mutate: update } = api.servizio.updateServizio.useMutation({
		onError: (error) => {
			toast.error(error.message);
		},
		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,
			});
			await utils.servizio.getPacksSolution.invalidate({ servizioId });
			setOpenEditParametri(false);
		},
	});

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

	return (
		<Credenza onOpenChange={setOpenEditParametri} open={openEditParametri}>
			<CredenzaTrigger asChild>
				<Button
					aria-label="Parametri di ricerca"
					className=""
					disabled={
						!isAdmin &&
						(servizio.isInterrotto ||
							servizio.annunci.some((a) => a.hasConfermaAdmin))
					}
					variant="secondary"
				>
					<SlidersHorizontal />
					Parametri
				</Button>
			</CredenzaTrigger>
			<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">
				<CredenzaHeader>
					<CredenzaTitle>Parametri di ricerca</CredenzaTitle>
					<CredenzaDescription className="sr-only">
						Parametri
					</CredenzaDescription>
				</CredenzaHeader>
				<CredenzaBody className="max-h-[80vh] w-full max-w-3xl overflow-y-auto pb-5 sm:max-w-5xl">
					{isLoading ? (
						<LoadingPage />
					) : (
						<FormNewServizio
							initialData={data}
							isLimited={!isAdmin}
							onSubmit={onSubmit}
						/>
					)}
				</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({
		onError: (error) => {
			toast.error(error.message);
		},
		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,
			});
			await utils.servizio.getPacksSolution.invalidate({ servizioId });
			setOpen(false);
		},
	});

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

	return (
		<Credenza onOpenChange={setOpen} open={open}>
			<CredenzaTrigger asChild>
				<Button aria-label="Modifica Servizio Admin">
					<Cog />
					Modifica
				</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">
								<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>
	);
};
