import { OptionalNullable, UUidWithPrefix, VerbrauchsausweisGewerbeClient, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { Enums, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { VerbrauchsausweisGewerbeSchema } from "src/generated/zod/verbrauchsausweisgewerbe.js";
import { z } from "zod";

export const PATCH = defineApiRoute({
	input: VerbrauchsausweisGewerbeSchema.omit({
		uid: true,
		id: true,
		benutzer_id: true,
		aufnahme_id: true,
		updated_at: true,
		created_at: true
	}).merge(z.object({
		startdatum: z.coerce.date()
	})),
	output: z.void(),
	headers: {
		"Authorization": z.string()
	},
	middleware: authorizationMiddleware,
	async fetch(input, ctx, user) {
		const objekt = await prisma.verbrauchsausweisGewerbe.findUnique({
			where: {
				uid: ctx.params.uid,
				benutzer: {
					id: user.id
				}
			}
		})

		if (!objekt) {
			throw new APIError({
				code: "NOT_FOUND",
				message: "Ausweis konnte nicht gefunden werden oder gehört einem anderen Benutzer."
			})
		}

		await prisma.verbrauchsausweisGewerbe.update({
			where: {
				uid: ctx.params.uid
			},
			data: input
		})
	},
})

export const DELETE = defineApiRoute({
	meta: {
		description: "Storniert einen Ausweis"
	},
	headers: authorizationHeaders,
	middleware: authorizationMiddleware,
	async fetch(input, ctx, user) {
		const { uid } = ctx.params;

		if (!UUidWithPrefix.safeParse(uid).success) {
			throw new APIError({
				code: "BAD_REQUEST",
				message: "UID konnte nicht verifiziert werden."
			})
		}

		// Wir holen uns den Verbrauchsausweis
		// Dieser MUSS mit dem Nutzer verknüpft sein.
		const ausweis = await prisma.verbrauchsausweisGewerbe.findUnique({
			where: {
				uid,
			}
		});

		if (!ausweis) {
			// Falls wir den Ausweis nicht finden können, werfen wir einen Fehler
			throw new APIError({
				code: "NOT_FOUND",
				message: "Ausweis konnte nicht gefunden werden.",
			});
		}

		// Wir dürfen den Ausweis nur stornieren, wenn er noch nicht ausgestellt wurde
		// Außerdem müssen wir schauen, ob wir Admin oder der Besitzer des Ausweises sind.
		if ((ausweis.benutzer_id !== user.id) && user.rolle !== "ADMIN") {
			// Falls der Ausweis nicht dem Nutzer gehört, werfen wir einen Fehler
			throw new APIError({
				code: "FORBIDDEN",
				message: "Ausweis gehört nicht dem Nutzer.",
			});
		}

		// if (ausweis.erledigt) {
		// 	// Falls der Ausweis bereits ausgestellt wurde, werfen wir einen Fehler
		// 	throw new TRPCError({
		// 		code: "BAD_REQUEST",
		// 		message: "Ausweis wurde bereits ausgestellt.",
		// 	});
		// }

		if (ausweis.storniert) {
			// Falls der Ausweis bereits storniert ist, werfen wir einen Fehler
			throw new APIError({
				code: "BAD_REQUEST",
				message: "Ausweis wurde bereits storniert.",
			});
		}

		await prisma.verbrauchsausweisGewerbe.update({
			where: {
				uid
			},
			data: {
				storniert: true
			}
		})

		// Wir erstellen ein Event, dass der Ausweis storniert wurde
		// Dann können wir das in der Historie anzeigen
		await prisma.event.create({
			data: {
				title: "Ausweis storniert",
				description: ((user.rolle === "ADMIN") && (ausweis.benutzer_id !== user.id)) ? "Ausweis wurde von einem Administrator storniert." : "Ausweis wurde vom Besitzer storniert.",
				benutzer: {
					connect: {
						id: user.id
					}
				},
				aufnahme: {
					connect: {
						id: ausweis.aufnahme_id
					}
				}
			}
		})
	},
})

export const GET = defineApiRoute({
	meta: {
		description: "Gibt ein spezifisches Gebäude des Benutzers zurück.",
		tags: ["Gebäude"],
		headers: {
			"Authorization": {
				description: "Ein gültiger Authentifizierungstoken",
				required: true,
				allowEmptyValue: false,
				examples: {
					Bearer: {
						value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
					}
				}
			}
		}
	},
	output: ZodOverlap<OptionalNullable<VerbrauchsausweisGewerbeClient>>(VerbrauchsausweisGewerbeSchema.merge(z.object({
		uid_aufnahme: UUidWithPrefix,
		uid_objekt: UUidWithPrefix,
		uid_benutzer: UUidWithPrefix.optional()
	})).omit({
		id: true,
		aufnahme_id: true,
		benutzer_id: true
	})),
	middleware: authorizationMiddleware,
	async fetch(input, context, user) {
		const { uid } = context.params;

		if (!uid) {
			throw new APIError({
				code: "BAD_REQUEST",
				message: "Missing uid in request params"
			})
		}

		const ausweis = await prisma.verbrauchsausweisGewerbe.findUnique({
			where: user.rolle === Enums.BenutzerRolle.USER ? {
				uid,
				benutzer_id: user.id
			} : { uid },
			include: {
				benutzer: {
					select: {
						uid: true
					}
				},
				aufnahme: {
					select: {
						uid: true,
						objekt: {
							select: {
								uid: true
							}
						}
					}
				}
			}
		});

		if (!ausweis) {
			// Falls wir den Ausweis nicht finden können, werfen wir einen Fehler
			throw new APIError({
				code: "NOT_FOUND",
				message: "Ausweis konnte nicht gefunden werden.",
			});
		}

		return {
			uid_aufnahme: ausweis.aufnahme.uid,
			uid_objekt: ausweis.aufnahme.objekt.uid,
			uid_benutzer: ausweis.benutzer?.uid,
			...exclude(ausweis, ["id", "aufnahme_id", "benutzer_id", "aufnahme"])
		}
	},
});
