import {
	CircleAlert,
	CircleCheck,
	ClipboardPaste,
	Pen,
	Trash2,
	Wrench,
} from "lucide-react";
import { useState } from "react";
import toast from "react-hot-toast";
import z from "zod";
import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
import { api } from "~/utils/api";
import {
	Credenza,
	CredenzaBody,
	CredenzaClose,
	CredenzaContent,
	CredenzaDescription,
	CredenzaFooter,
	CredenzaHeader,
	CredenzaTitle,
	CredenzaTrigger,
} from "../custom_ui/credenza";
import { LoadingPage } from "../loading";
import { Button } from "../ui/button";
import {
	Card,
	CardContent,
	CardDescription,
	CardFooter,
	CardHeader,
	CardTitle,
} from "../ui/card";
import { Separator } from "../ui/separator";
import { UploadModal } from "../upload_modal";
import { DocCombo, DocInfo } from "./shared";

export const AdminContratto = () => {
	const { data } = useServizioAnnuncio();

	return (
		<Credenza>
			<CredenzaTrigger asChild>
				<Button
					aria-label="Open Contratto Section"
					className="w-fit"
					size="sm"
					variant={data.doc_contratto_added ? "success" : "orange"}
				>
					{data.doc_contratto_added ? <CircleCheck /> : <Wrench />}
					Contratto
				</Button>
			</CredenzaTrigger>
			<CredenzaContent className="max-h-[90vh] max-w-4xl px-3 sm:max-w-5xl">
				<CredenzaHeader>
					<CredenzaTitle>Sezione Contratto</CredenzaTitle>
					<CredenzaDescription className="sr-only">
						Contratto modal
					</CredenzaDescription>
				</CredenzaHeader>
				<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
					<div className="flex flex-col gap-8">
						<ContrattoSection />
						<Separator />
						<ContrattoImport />
						<Separator />
						<RicevutaSection />
					</div>
				</CredenzaBody>

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

const ContrattoSection = () => {
	const { userId } = useServizio();
	const { data, updateServizioAnnunci } = useServizioAnnuncio();
	const initialDoc = data.doc_contratto_ref;
	const [selectedDoc, setSelectedDoc] = useState<string | null>(
		data.doc_contratto_ref,
	);

	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();
			},
		});

	const handleSave = async () => {
		await updateServizioAnnunci({
			doc_contratto_added: selectedDoc != null,
			doc_contratto_ref: selectedDoc,
		});
		if (selectedDoc) {
			setUserStorage({
				storageId: selectedDoc,
				userId,
			});
		}
	};

	if (isLoading) return <LoadingPage />;
	if (files === undefined) {
		return <p>Errore nel caricamento dei documenti</p>;
	}

	return (
		<Card>
			<CardHeader>
				<CardTitle>Documento del Contratto</CardTitle>
				<CardDescription>contratto di locazione</CardDescription>
			</CardHeader>
			<CardContent className="space-y-4">
				{selectedDoc && (
					<div className="flex flex-wrap items-center gap-3">
						<DocInfo storageId={selectedDoc}>
							<Button
								aria-label="Reset Contratto"
								className="flex items-center gap-3"
								onClick={async () => {
									await updateServizioAnnunci({
										doc_contratto_added: false,
										doc_contratto_ref: null,
									});
									setSelectedDoc(null);
								}}
								variant="destructive"
							>
								<Trash2 className="size-6" />
							</Button>
						</DocInfo>
					</div>
				)}
				<DocCombo
					current={selectedDoc}
					files={files}
					onSelect={(f) => {
						setSelectedDoc(f.id);
					}}
				/>
				<UploadModal
					cb_onUpload={({ storageIds }) => {
						if (storageIds.length === 1 && storageIds[0]) {
							setSelectedDoc(storageIds[0]);
						}
					}}
					isAdmin
					userId={userId}
				/>
			</CardContent>
			<CardFooter className="gap-4">
				<Button
					aria-label="Save Contratto"
					disabled={selectedDoc === initialDoc}
					onClick={async () => {
						await handleSave();
					}}
					variant="success"
				>
					Salva
				</Button>
				{selectedDoc !== initialDoc ? (
					<div className="flex items-center gap-2">
						<CircleAlert className="size-5 text-orange-500" />
						<span className="text-orange-500">Salva modifiche</span>
					</div>
				) : (
					initialDoc &&
					selectedDoc === initialDoc && (
						<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 ContrattoImportSchema = z.object({
	contratto_decorrenza: z.string().nullable(),
	contratto_scadenza: z.string().nullable(),
	contratto_tipo: z
		.enum([
			"Transitorio",
			"Agevolato",
			"4 + 4",
			"30 Giorni",
			"Transi.Age",
			"Foresteria",
			"Commerciale",
		])
		.nullable(),
	gestionale_id: z.number().nullable(),
});

interface ContrattoImportObj
	extends Omit<
		z.infer<typeof ContrattoImportSchema>,
		"contratto_decorrenza" | "contratto_scadenza"
	> {
	contratto_decorrenza: Date | null;
	contratto_scadenza: Date | null;
}

const parseContrattoImport = (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 = ContrattoImportSchema.safeParse(parsedJson);
	if (parsed.success) {
		return {
			...parsed.data,
			contratto_decorrenza: parsed.data.contratto_decorrenza
				? new Date(parsed.data.contratto_decorrenza)
				: null,
			contratto_scadenza: parsed.data.contratto_scadenza
				? new Date(parsed.data.contratto_scadenza)
				: null,
		};
	}
	console.error("Invalid format:", parsed.error);
	return undefined;
};

const ContrattoImport = () => {
	const { data, updateServizioAnnunci } = useServizioAnnuncio();
	const initialContratto = {
		contratto_decorrenza: data.contratto_decorrenza
			? new Date(data.contratto_decorrenza)
			: null,
		contratto_scadenza: data.contratto_scadenza
			? new Date(data.contratto_scadenza)
			: null,
		contratto_tipo: data.contratto_tipo as ContrattoImportObj["contratto_tipo"],
		gestionale_id: data.gestionale_id,
	};

	const [contratto, setContratto] = useState<ContrattoImportObj | undefined>(
		initialContratto,
	);
	const handleSave = async () => {
		await updateServizioAnnunci({
			contratto_decorrenza: contratto?.contratto_decorrenza || null,
			contratto_scadenza: contratto?.contratto_scadenza || null,
			contratto_tipo: contratto?.contratto_tipo || null,
			gestionale_id: contratto?.gestionale_id || null,
		});
	};
	return (
		<Card>
			<CardHeader>
				<CardTitle>Dati Contratto</CardTitle>
				<CardDescription className="sr-only">desc</CardDescription>
			</CardHeader>
			<CardContent className="space-y-4">
				<div className="flex flex-wrap items-center gap-3">
					<Button
						aria-label="Import Contratto"
						onClick={async () => {
							const clipboardText = await navigator.clipboard.readText();

							setContratto(parseContrattoImport(clipboardText));
						}}
						variant="info"
					>
						<ClipboardPaste className="size-4" />
						Incolla la stringa dal gestionale
					</Button>
					<Button
						aria-label="Reset Contratto"
						onClick={() => {
							setContratto({
								contratto_decorrenza: null,
								contratto_scadenza: null,
								contratto_tipo: null,
								gestionale_id: null,
							});
						}}
						variant="destructive"
					>
						<Trash2 className="size-4" />
						Reset
					</Button>
				</div>
				{contratto ? (
					<div className="flex flex-col gap-2">
						<p>
							<span className="font-semibold">ID Gestionale: </span>
							{contratto.gestionale_id}{" "}
							<Button
								aria-label="Edit Gestionale ID"
								className="h-6 px-1.5 [&_svg]:size-4"
								onClick={() => {
									const newValue = prompt(
										"Modifica l'ID gestionale del contratto:",
										contratto.gestionale_id?.toString() || "",
									);
									if (newValue !== null) {
										setContratto((prev) =>
											prev
												? { ...prev, gestionale_id: parseInt(newValue) }
												: undefined,
										);
									}
								}}
								size="sm"
							>
								<Pen />
							</Button>
						</p>
						<p>
							<span className="font-semibold">Decorrenza: </span>
							{contratto.contratto_decorrenza &&
								new Date(contratto.contratto_decorrenza).toLocaleDateString(
									"it-IT",
								)}{" "}
							<Button
								aria-label="Edit Decorrenza"
								className="h-6 px-1.5 [&_svg]:size-4"
								onClick={() => {
									const newValue = prompt(
										"Modifica la decorrenza del contratto (DD/MM/YYYY):",
										contratto.contratto_decorrenza
											? new Date(
													contratto.contratto_decorrenza,
												).toLocaleDateString("it-IT")
											: "",
									);
									if (newValue !== null) {
										setContratto((prev) =>
											prev
												? {
														...prev,
														contratto_decorrenza: new Date(newValue),
													}
												: undefined,
										);
									}
								}}
								size="sm"
							>
								<Pen />
							</Button>
						</p>
						<p>
							<span className="font-semibold">Scadenza: </span>
							{contratto.contratto_scadenza &&
								new Date(contratto.contratto_scadenza).toLocaleDateString(
									"it-IT",
								)}{" "}
							<Button
								aria-label="Edit Scadenza"
								className="h-6 px-1.5 [&_svg]:size-4"
								onClick={() => {
									const newValue = prompt(
										"Modifica la scadenza del contratto (DD/MM/YYYY):",
										contratto.contratto_scadenza
											? new Date(
													contratto.contratto_scadenza,
												).toLocaleDateString("it-IT")
											: "",
									);
									if (newValue !== null) {
										setContratto((prev) =>
											prev
												? {
														...prev,
														contratto_scadenza: new Date(newValue),
													}
												: undefined,
										);
									}
								}}
								size="sm"
							>
								<Pen />
							</Button>
						</p>
						<p>
							<span className="font-semibold">Tipo di contratto: </span>
							{contratto.contratto_tipo}{" "}
							<Button
								aria-label="Edit Tipo di contratto"
								className="h-6 px-1.5 [&_svg]:size-4"
								onClick={() => {
									const newValue = prompt(
										"Modifica il tipo di contratto:",
										contratto.contratto_tipo || "",
									);
									if (
										newValue !== null &&
										ContrattoImportSchema.shape.contratto_tipo.safeParse(
											newValue,
										).success
									) {
										setContratto((prev) =>
											prev
												? {
														...prev,
														contratto_tipo:
															newValue as ContrattoImportObj["contratto_tipo"],
													}
												: 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 Contratto"
					disabled={
						JSON.stringify(contratto) === JSON.stringify(initialContratto)
					}
					onClick={async () => {
						await handleSave();
					}}
					variant="success"
				>
					Salva
				</Button>
				{JSON.stringify(contratto) !== JSON.stringify(initialContratto) ? (
					<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(initialContratto).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 RicevutaSection = () => {
	const { userId } = useServizio();
	const { data, updateServizioAnnunci } = useServizioAnnuncio();
	const initialDoc = data.doc_registrazione_ref;
	const [selectedDoc, setSelectedDoc] = useState<string | null>(
		data.doc_registrazione_ref,
	);

	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();
			},
		});

	const handleSave = async () => {
		await updateServizioAnnunci({
			doc_registrazione_added: selectedDoc != null,
			doc_registrazione_ref: selectedDoc,
		});
		if (selectedDoc) {
			setUserStorage({
				storageId: selectedDoc,
				userId,
			});
		}
	};

	if (isLoading) return <LoadingPage />;
	if (files === undefined) {
		return <p>Errore nel caricamento dei documenti</p>;
	}

	return (
		<Card>
			<CardHeader>
				<CardTitle>Ricevuta di Registrazione</CardTitle>
				<CardDescription className="sr-only">desc</CardDescription>
			</CardHeader>
			<CardContent className="space-y-4">
				{selectedDoc && (
					<div className="flex flex-wrap items-center gap-3">
						<DocInfo storageId={selectedDoc}>
							<Button
								aria-label="Reset Ricevuta"
								className="flex items-center gap-3"
								onClick={async () => {
									await updateServizioAnnunci({
										doc_registrazione_added: false,
										doc_registrazione_ref: null,
									});
									setSelectedDoc(null);
								}}
								variant="destructive"
							>
								<Trash2 className="size-6" />
							</Button>
						</DocInfo>
					</div>
				)}
				<DocCombo
					current={selectedDoc}
					files={files}
					onSelect={(f) => {
						setSelectedDoc(f.id);
					}}
				/>
				<UploadModal
					cb_onUpload={({ storageIds }) => {
						if (storageIds.length === 1 && storageIds[0]) {
							setSelectedDoc(storageIds[0]);
						}
					}}
					isAdmin
					userId={userId}
				/>
			</CardContent>
			<CardFooter className="gap-4">
				<Button
					aria-label="Save Ricevuta"
					disabled={selectedDoc === initialDoc}
					onClick={async () => {
						await handleSave();
					}}
					variant="success"
				>
					Salva
				</Button>
				{selectedDoc !== initialDoc ? (
					<div className="flex items-center gap-2">
						<CircleAlert className="size-5 text-orange-500" />
						<span className="text-orange-500">Salva modifiche</span>
					</div>
				) : (
					initialDoc &&
					selectedDoc === initialDoc && (
						<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>
	);
};
