import { format } from "date-fns";
import {
	CircleAlert,
	CircleCheck,
	ClipboardPaste,
	FlaskConical,
	Pen,
	Trash2,
	Wrench,
} from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import toast from "react-hot-toast";
import { useDebounce } from "react-use";
import z from "zod";
import { it } from "~/i18n/it";
import { handleConsegna } from "~/lib/annuncio_details";
import { formatCurrency } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider";
import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
import type { UsersStorageUserStorageId } from "~/schemas/public/UsersStorage";
import { api } from "~/utils/api";
import { Confirm } from "../confirm";
import { Counter } from "../counter";
import {
	Credenza,
	CredenzaBody,
	CredenzaClose,
	CredenzaContent,
	CredenzaDescription,
	CredenzaFooter,
	CredenzaHeader,
	CredenzaTitle,
	CredenzaTrigger,
} from "../custom_ui/credenza";
import { NumberInput } from "../custom_ui/InputNumber";
import {
	type ListOption,
	MultiSelect,
	UnpackOptions,
} from "../custom_ui/multiselect";
import { LoadingPage } from "../loading";
import { Button } from "../ui/button";
import {
	Card,
	CardContent,
	CardDescription,
	CardFooter,
	CardHeader,
	CardTitle,
} from "../ui/card";
import { Label } from "../ui/label";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { Switch } from "../ui/switch";
import { UploadModal } from "../upload_modal";
import { ServizioPacksInfos } from "./servizio_actions";
import { DocCombo, DocInfo } from "./shared";

export const AdminLavoraConferma = () => {
	const { servizio } = useServizio();
	const { data } = useServizioAnnuncio();

	return (
		<Credenza>
			<CredenzaTrigger asChild>
				<Button
					aria-label="Open Lavora Conferma Section"
					className="w-fit"
					size="sm"
					variant={data.hasConfermaAdmin ? "success" : "orange"}
				>
					{data.hasConfermaAdmin ? <CircleCheck /> : <Wrench />}
					<span>Conferma</span>
				</Button>
			</CredenzaTrigger>
			<CredenzaContent className="max-h-[90vh] w-full px-3 sm:max-w-6xl">
				<CredenzaHeader>
					<CredenzaTitle>Lavorazione conferma</CredenzaTitle>
					<CredenzaDescription className="sr-only">
						Consegna status modal
					</CredenzaDescription>
				</CredenzaHeader>
				<CredenzaBody className="max-h-[80vh] w-full overflow-y-auto pb-5">
					<div className="flex flex-col gap-4">
						<DocSection />
						<Caparra />
						{servizio.tipologia === TipologiaPosizioneEnum.Transitorio && (
							<MotivazioneSection />
						)}
						<SendConferma />
					</div>
				</CredenzaBody>

				<CredenzaFooter>
					<DebugActions />
					<CredenzaClose asChild>
						<Button aria-label="Close Credenza" variant="outline">
							Chiudi
						</Button>
					</CredenzaClose>
				</CredenzaFooter>
			</CredenzaContent>
		</Credenza>
	);
};

const DebugActions = () => {
	const { servizioId, userId } = useServizio();
	const { annuncioId } = useServizioAnnuncio();
	const utils = api.useUtils();
	const { mutate } = api.servizio.updateServizioAnnunci.useMutation({
		onError: (error) => {
			toast.error(error.message);
		},
		onSuccess: async () => {
			await utils.servizio.getAllServizioAnnunci.invalidate({
				userId: userId,
			});
			await utils.servizio.getServizio.invalidate({
				servizioId,
			});

			toast.success("Dati salvati con successo");
		},
	});

	return (
		<Popover>
			<PopoverTrigger asChild>
				<Button>
					<FlaskConical />
					<span>Debug</span>
				</Button>
			</PopoverTrigger>
			<PopoverContent
				align="end"
				className="flex w-fit flex-col items-center gap-4"
			>
				<Confirm
					description="Sei sicuro di voler eliminare l'annuncio?"
					onConfirm={() => {
						mutate({
							annuncioId,
							servizioId,
							data: {
								user_confirmed_at: null,
							},
						});
					}}
					title="Elimina annuncio"
				>
					<Button
						aria-label="Delete Annuncio"
						className="w-full"
						size="sm"
						variant="destructive"
					>
						<Trash2 />
						<span>Elimina Conferma</span>
					</Button>
				</Confirm>
			</PopoverContent>
		</Popover>
	);
};

const DocSection = () => {
	const { userId } = useServizio();
	const { data, updateServizioAnnunci } = useServizioAnnuncio();

	const utils = api.useUtils();

	const { data: files, isLoading } = api.storage.getAll.useQuery();

	const { mutate: setUserStorage } =
		api.storage.addUserStorageEntry.useMutation({
			onSuccess: async () => {
				await utils.storage.retrieveUserFileData.invalidate({
					userId,
				});
				await utils.storage.getAll.invalidate();
			},
		});

	if (isLoading) return <LoadingPage />;
	if (files === undefined) {
		return <p>Errore nel caricamento dei documenti</p>;
	}
	return (
		<Card>
			<CardHeader>
				<CardTitle>Documento di Conferma</CardTitle>
				<CardDescription>
					documento che l&apos;utente vedra alla conferma
				</CardDescription>
			</CardHeader>
			<CardContent className="space-y-4">
				{data.doc_conferma_ref && (
					<div className="flex flex-wrap items-start gap-3">
						<DocInfo storageId={data.doc_conferma_ref}>
							<Button
								aria-label="Reset Conferma"
								className="flex items-center gap-3"
								onClick={async () => {
									await updateServizioAnnunci({
										doc_conferma_added: false,
										doc_conferma_ref: null,
									});
								}}
								variant="destructive"
							>
								<Trash2 />
							</Button>
						</DocInfo>
					</div>
				)}
				<div className="flex flex-wrap items-center gap-3">
					<DocCombo
						current={data.doc_conferma_ref}
						files={files}
						onSelect={async (f) => {
							await updateServizioAnnunci({
								doc_conferma_added: true,
								doc_conferma_ref: f.id,
							});

							setUserStorage({
								storageId: f.id,
								userId,
							});
						}}
					/>
					<UploadModal
						cb_onUpload={async ({ storageIds }) => {
							if (storageIds.length === 1 && storageIds[0]) {
								await updateServizioAnnunci({
									doc_conferma_added: true,
									doc_conferma_ref: storageIds[0],
								});
							}
						}}
						isAdmin
						userId={userId}
					/>
				</div>
			</CardContent>
		</Card>
	);
};

const CaparraSchema = z.object({
	caparra_causale: z.string().nullable(),
	caparra_iban: z.string().nullable(),
	caparra_importo: z.string().nullable(),
	caparra_intestazione: z.string().nullable(),
});

type CaparraObj = z.infer<typeof CaparraSchema>;

const parseCaparra = (ingest: string) => {
	let parsedJson: unknown;
	try {
		parsedJson = JSON.parse(ingest);
	} catch {
		toast.error(
			'Stringa non valida, clicca "copia stringa" nel gestionale e poi questo pulsante',
		);
		return undefined;
	}
	const parsed = CaparraSchema.safeParse(parsedJson);
	if (parsed.success) {
		return parsed.data;
	}
	console.error("Invalid caparra format:", parsed.error);
	return undefined;
};

const Caparra = () => {
	const { data, updateServizioAnnunci } = useServizioAnnuncio();
	const initialCaparra = {
		caparra_causale: data.caparra_causale,
		caparra_iban: data.caparra_iban,
		caparra_importo: data.caparra_importo,
		caparra_intestazione: data.caparra_intestazione,
	};

	const [caparra, setCaparra] = useState<CaparraObj | undefined>(
		initialCaparra,
	);
	const handleSave = async () => {
		await updateServizioAnnunci({
			caparra_causale: caparra?.caparra_causale || null,
			caparra_iban: caparra?.caparra_iban || null,
			caparra_importo: caparra?.caparra_importo || null,
			caparra_intestazione: caparra?.caparra_intestazione || null,
		});
	};
	return (
		<Card>
			<CardHeader>
				<CardTitle>Dati Pagamento Caparra</CardTitle>
				<CardDescription>
					dati per il pagamento della caparra, da mostrare all&apos;utente
				</CardDescription>
			</CardHeader>
			<CardContent className="space-y-4">
				<div className="flex flex-wrap items-center gap-3">
					<Button
						aria-label="Import Caparra"
						onClick={async () => {
							const clipboardText = await navigator.clipboard.readText();

							setCaparra(parseCaparra(clipboardText));
						}}
						variant="info"
					>
						<ClipboardPaste className="size-4" />
						Dal gestionale
					</Button>
					<Button
						aria-label="Reset Caparra"
						onClick={async () => {
							setCaparra({
								caparra_causale: null,
								caparra_iban: null,
								caparra_importo: null,
								caparra_intestazione: null,
							});
						}}
						variant="destructive"
					>
						<Trash2 className="size-4" />
					</Button>
				</div>
				{caparra ? (
					<div className="flex flex-col gap-2">
						<p>
							<span className="font-semibold">Intestazione: </span>
							{caparra.caparra_intestazione}{" "}
							<Button
								aria-label="Edit Intestazione"
								className="h-6 px-1.5 [&_svg]:size-4"
								onClick={() => {
									const newValue = prompt(
										"Modifica l'intestazione della caparra:",
										caparra.caparra_intestazione || "",
									);
									if (newValue !== null) {
										setCaparra((prev) =>
											prev
												? { ...prev, caparra_intestazione: newValue }
												: undefined,
										);
									}
								}}
								size="sm"
							>
								<Pen />
							</Button>
						</p>
						<p>
							<span className="font-semibold">IBAN: </span>
							{caparra.caparra_iban}{" "}
							<Button
								aria-label="Edit IBAN"
								className="h-6 px-1.5 [&_svg]:size-4"
								onClick={() => {
									const newValue = prompt(
										"Modifica l'IBAN della caparra:",
										caparra.caparra_iban || "",
									);
									if (newValue !== null) {
										setCaparra((prev) =>
											prev ? { ...prev, caparra_iban: newValue } : undefined,
										);
									}
								}}
								size="sm"
							>
								<Pen />
							</Button>
						</p>
						<p>
							<span className="font-semibold">Importo: </span>
							{caparra.caparra_importo}{" "}
							<Button
								aria-label="Edit Importo"
								className="h-6 px-1.5 [&_svg]:size-4"
								onClick={() => {
									const newValue = prompt(
										"Modifica l'importo della caparra:",
										caparra.caparra_importo || "",
									);
									if (newValue !== null) {
										setCaparra((prev) =>
											prev ? { ...prev, caparra_importo: newValue } : undefined,
										);
									}
								}}
								size="sm"
							>
								<Pen />
							</Button>
						</p>
						<p>
							<span className="font-semibold">Causale: </span>
							{caparra.caparra_causale}{" "}
							<Button
								aria-label="Edit Causale"
								className="h-6 px-1.5 [&_svg]:size-4"
								onClick={() => {
									const newValue = prompt(
										"Modifica la causale della caparra:",
										caparra.caparra_causale || "",
									);
									if (newValue !== null) {
										setCaparra((prev) =>
											prev ? { ...prev, caparra_causale: newValue } : undefined,
										);
									}
								}}
								size="sm"
							>
								<Pen />
							</Button>
						</p>
					</div>
				) : (
					<p>Inserisci la stringa dal gestionale e elabora</p>
				)}
			</CardContent>
			<CardFooter className="gap-4">
				<Button
					aria-label="Save Caparra"
					disabled={JSON.stringify(caparra) === JSON.stringify(initialCaparra)}
					onClick={async () => {
						await handleSave();
					}}
					variant="success"
				>
					Salva
				</Button>
				{JSON.stringify(caparra) !== JSON.stringify(initialCaparra) ? (
					<div className="flex items-center gap-2">
						<CircleAlert className="size-5 text-orange-500" />
						<span className="text-orange-500">Salva modifiche</span>
					</div>
				) : (
					Object.values(initialCaparra).every((v) => v !== null) && (
						<div className="flex items-center gap-2">
							<CircleCheck className="size-5 text-green-500" />
							<span className="text-green-500">Dati salvati</span>
						</div>
					)
				)}
			</CardFooter>
		</Card>
	);
};

const MotivazioneSection = () => {
	const { servizioId } = useServizio();
	const { t } = useTranslation();

	const { data: servizio } = api.servizio.getServizio.useQuery({ servizioId });

	if (!servizio) return null;
	return (
		<Card>
			<CardHeader>
				<CardTitle>Motivazione di transitorietà</CardTitle>
				<CardDescription>
					Informazioni relative alla motivazione di transitorietà inserite
					dall&apos;utente
				</CardDescription>
			</CardHeader>
			<CardContent className="space-y-4">
				<div className="flex flex-col gap-2">
					<p>
						<span className="font-semibold">Motivazione specificata: </span>
						{servizio.motivazione_transitorio ? (
							<span>
								{
									t.parametri.motivazioni_mappings.find(
										(m) => m.id === servizio.motivazione_transitorio,
									)?.title
								}
							</span>
						) : (
							<span className="text-red-500 italic">Non inserita</span>
						)}
					</p>
					<p>
						<span className="font-semibold">
							Data scadenza motivazione inserita:{" "}
						</span>
						{servizio.scadenza_motivazione_transitoria ? (
							format(servizio.scadenza_motivazione_transitoria, "dd/MM/yyyy")
						) : (
							<span className="text-red-500 italic">Non inserita</span>
						)}
					</p>
					{!servizio.skipDocMotivazione && (
						<p>
							<span className="font-semibold">Documento caricato: </span>
							{servizio.doc_motivazione_ref ? (
								<FileLink userStorageId={servizio.doc_motivazione_ref} />
							) : (
								<span className="text-red-500 italic">Non caricato</span>
							)}
						</p>
					)}
				</div>
			</CardContent>
		</Card>
	);
};

const FileLink = ({
	userStorageId,
}: {
	userStorageId: UsersStorageUserStorageId;
}) => {
	const { data: storageId } =
		api.storage.getStorageIdFromUserStorageId.useQuery({
			userStorageId,
		});
	if (!storageId) return null;
	return (
		<Link
			className="underline hover:text-primary"
			href={`/area-riservata/allegato-view/${storageId}`}
			rel="noreferrer"
			target="_blank"
		>
			Vedi documento
		</Link>
	);
};

const TransitorioSection = () => {
	const { servizio } = useServizio();
	const { data } = useServizioAnnuncio();
	const { t } = useTranslation();
	const { servizioId, userId } = useServizio();
	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.getUserServizi.invalidate();
			await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
			await utils.servizio.getPacksSolution.invalidate({ servizioId });
		},
	});

	const handlePermanenzaChange = (value: ListOption) => {
		update({
			servizioId,
			data: {
				permanenza: value.value !== "" ? parseInt(value.value) : null,
			},
		});
	};
	const preferenzeDescrizione = data.desc_it?.match(/Permanenza:.*$/m);

	const permanenzaAnnuncio = data.permanenza
		? `${data.permanenza.join(" - ")} mesi`
		: (preferenzeDescrizione?.[0] ??
			"errore: testo non trovato in descrizione");

	return (
		<div className="flex flex-col items-start gap-4 rounded-md border border-border bg-muted p-2 sm:flex-row">
			<div className="w-full">
				<Label className="text-base" htmlFor="permanenza">
					Permanenza (da parametri servizio):
				</Label>

				<MultiSelect
					defaultValue={
						servizio.permanenza
							? {
									label: t.parametri.permanenza[servizio.permanenza] || "",
									value: servizio.permanenza.toString(),
								}
							: undefined
					}
					elementId="permanenza"
					elementName="permanenza"
					isMulti={false}
					onValueChange={handlePermanenzaChange}
					options={UnpackOptions({
						options: t.parametri.permanenza,
					})}
					placeholder="Seleziona..."
				/>
			</div>
			<div className="w-full space-y-2">
				<p className="font-medium">Permanenza in annuncio:</p>
				<p>{permanenzaAnnuncio}</p>
			</div>
		</div>
	);
};

const StabileSection = () => {
	const { servizio, servizioId, userId } = useServizio();
	const { data } = useServizioAnnuncio();
	const [value, setValue] = useState(servizio.budget);
	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.getUserServizi.invalidate();
			await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
			await utils.servizio.getPacksSolution.invalidate({ servizioId });
		},
	});

	useDebounce(
		() => {
			if (value === servizio.budget) return;
			update({
				servizioId,
				data: {
					budget: value,
				},
			});
		},
		1000,
		[value],
	);

	return (
		<div className="flex flex-col gap-2 rounded-md border border-border bg-muted p-2 sm:flex-row">
			<div className="flex w-full flex-col gap-2">
				<span className="font-semibold">Budget (da preferenze servizio):</span>
				<NumberInput
					allowNegative={false}
					defaultValue={value}
					min={0}
					onValueChange={(val) => {
						if (val !== undefined) {
							setValue(val);
						}
					}}
					stepper={50}
					suffix=" €"
				/>
			</div>
			<div className="w-full space-y-2">
				<p className="font-medium">Prezzo in descrizione:</p>
				<p>{formatCurrency(data.prezzo / 100)}</p>
			</div>
		</div>
	);
};

const GeneralSection = () => {
	const { data } = useServizioAnnuncio();
	const { t } = useTranslation();

	const { servizio, servizioId, userId } = useServizio();
	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.getUserServizi.invalidate();
			await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
			await utils.servizio.getPacksSolution.invalidate({ servizioId });
		},
	});

	const handleDisponibilitàChange = (value: ListOption) => {
		update({
			servizioId,
			data: {
				entromese: value.value !== "" ? parseInt(value.value) : null,
			},
		});
	};

	const handleAdultiChange = (value: number) => {
		update({
			servizioId,
			data: {
				n_adulti: value,
			},
		});
	};
	const handleMinoriChange = (value: number) => {
		update({
			servizioId,
			data: {
				n_minori: value,
			},
		});
	};

	const personeDescrizione = data.desc_it?.match(/Preferenza:.*$/m);

	const personeAnnuncio = data.persone
		? data.persone.join(", ").toUpperCase()
		: (personeDescrizione?.[0] ?? "errore: testo non trovato in descrizione");

	const dispAnnuncio = data.disponibile_da
		? format(new Date(data.disponibile_da), "dd/MM/yyyy")
		: handleConsegna({
				consegna: data.consegna,
				aggiornamento: it.card.in_aggiornamento,

				consegna_da: it.card.consegna_da,
				mesi: it.parametri.mesi,
				subito: it.card.consegna_subito,
			});

	return (
		<>
			<div className="flex flex-col gap-x-4 gap-y-2 rounded-md border border-border bg-muted p-2 sm:flex-row">
				<div className="w-full space-y-2">
					<span className="font-semibold">Persone:</span>
					<div className="flex w-full gap-4">
						<div className="flex w-1/2 flex-col gap-2">
							<Label htmlFor="n_adulti">{t.parametri.nadulti_label}</Label>
							<Counter
								name="n_adulti"
								onlyPositive
								setValue={(v) => handleAdultiChange(Number(v))}
								value={servizio.n_adulti || 0}
							/>
						</div>

						<div className="flex w-1/2 flex-col gap-2">
							<Label htmlFor="n_minori">{t.parametri.nminori_label}</Label>
							<Counter
								name="n_minori"
								onlyPositive
								setValue={(v) => handleMinoriChange(Number(v))}
								value={servizio.n_minori || 0}
							/>
						</div>
					</div>
				</div>
				<div className="w-full space-y-2">
					<p className="font-medium">Persone in annuncio:</p>
					<p>{personeAnnuncio}</p>
				</div>
			</div>
			<div className="flex flex-col gap-x-4 gap-y-2 rounded-md border border-border bg-muted p-2 sm:flex-row">
				<div className="w-full">
					<Label className="text-base" htmlFor="select-mesi">
						Entro mese (da parametri servizio):
					</Label>
					<MultiSelect
						defaultValue={
							servizio.entromese !== null
								? {
										// biome-ignore lint/style/noNonNullAssertion: <known size>
										label: t.parametri.mesi[servizio.entromese]!,
										value: String(servizio.entromese),
									}
								: undefined
						}
						elementId="select-mesi"
						elementName="entro_mese"
						isMulti={false}
						onValueChange={handleDisponibilitàChange}
						options={UnpackOptions({
							options: t.parametri.mesi,
						})}
						placeholder="Seleziona..."
					/>
				</div>
				<div className="w-full space-y-2">
					<p className="font-medium">Disponibilità in annuncio:</p>
					<p>{dispAnnuncio}</p>
				</div>
			</div>
		</>
	);
};

const SendConferma = () => {
	const { servizio } = useServizio();
	const { data } = useServizioAnnuncio();
	const utils = api.useUtils();
	const { mutate: handleUpdate } =
		api.servizio.adminUpdateConfermaStatus.useMutation({
			onSuccess: async () => {
				await utils.servizio.getAllServizioAnnunci.invalidate();
				await utils.servizio.getServizio.invalidate({
					servizioId: servizio.servizio_id,
				});
				toast.success("Status aggiornato con successo");
			},
			onError: (error) => {
				toast.error(`Errore durante l'aggiornamento: ${error.message}`);
			},
		});

	const docOk = data.doc_conferma_added && data.doc_conferma_ref;
	const caparraOk =
		data.caparra_iban &&
		data.caparra_importo &&
		data.caparra_intestazione &&
		data.caparra_causale;

	return (
		<Card>
			<CardHeader>
				<CardTitle>Lavorazione Conferma</CardTitle>
				<CardDescription>
					controlla i parametri di ricerca prima!
				</CardDescription>
			</CardHeader>
			<CardContent className="space-y-10">
				<div className="flex flex-col gap-4">
					<p>
						<span className="font-semibold">Tipologia servizio: </span>
						{servizio.tipologia}
					</p>
					{servizio.tipologia === TipologiaPosizioneEnum.Transitorio ? (
						<TransitorioSection />
					) : (
						<StabileSection />
					)}
					<GeneralSection />
					<ServizioPacksInfos />
				</div>
				<div className="space-y-2">
					{!docOk && (
						<p className="text-red-500">
							Attenzione: il documento di conferma non è stato ancora caricato
						</p>
					)}
					{!caparraOk && (
						<p className="text-red-500">
							Attenzione: i dati per il pagamento della caparra non sono
							completi
						</p>
					)}

					<div className="mt-4 flex items-center gap-3">
						<Switch
							aria-label="Conferma Lavorata"
							checked={data.hasConfermaAdmin}
							disabled={!docOk || !caparraOk}
							id="conferma"
							onCheckedChange={(c) => {
								handleUpdate({
									servizioId: servizio.servizio_id,
									annuncioId: data.id,
									status: c,
								});
							}}
						/>
						<Label className="text-base" htmlFor="conferma">
							Imposta Conferma come Lavorata
						</Label>
					</div>
				</div>
			</CardContent>
		</Card>
	);
};
