import {
	getAusweisartFromUUID,
	UUidWithPrefix,
} from "#components/Ausweis/types.js";
import {
	adminMiddleware,
	authorizationHeaders,
} from "#lib/middleware/authorization.js";
import {
	BedarfsausweisWohnen,
	Enums,
	VerbrauchsausweisGewerbe,
	VerbrauchsausweisWohnen,
} from "#lib/server/prisma.js";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import moment from "moment";
import { z } from "zod";
import soap from "soap";
import { getPrismaAusweisAdapter } from "#lib/server/ausweis.js";

export const GET = defineApiRoute({
	input: z.object({
		uid: UUidWithPrefix,
	}),
	headers: authorizationHeaders,
	middleware: adminMiddleware,
	async fetch({ uid }, context, user) {
		const ausweisart = getAusweisartFromUUID(uid);
		const adapter = getPrismaAusweisAdapter(
			uid
		) as typeof prisma.verbrauchsausweisWohnen;

		if (!adapter) {
			throw new APIError({
				code: "BAD_REQUEST",
				message: "UID ist ungültig.",
			});
		}

		const ausweis = await adapter.findUnique({
			where: {
				uid,
			},
			include: {
				aufnahme: {
					include: {
						objekt: true,
					},
				},
			},
		});

		if (!ausweis) {
			throw new APIError({
				code: "NOT_FOUND",
				message: "Ausweis existiert nicht.",
			});
		}

		if (ausweis.registriernummer) {
			throw new APIError({
				code: "PRECONDITION_FAILED",
				message: `Ausweis hat bereits eine Registriernummer: (${ausweis.registriernummer})`,
			});
		}

		if (!ausweis.aufnahme.objekt.plz) {
			throw new APIError({
				code: "PRECONDITION_FAILED",
				message: "Ausweis Gebäude hat keine Postleitzahl",
			});
		}

		const postleitzahl = await prisma.postleitzahlen.findFirst({
			where: {
				plz: ausweis.aufnahme.objekt.plz,
			},
		});

		if (!postleitzahl) {
			throw new APIError({
				code: "PRECONDITION_FAILED",
				message: `Bundesland konnte nicht gefunden werden für PLZ ${ausweis.aufnahme.objekt.plz}`,
			});
		}

		/* Authentifizierung */
		const Aussteller_ID_DIBT = "jens.cornelsen@ib-cornelsen.de";
		const Aussteller_PWD_DIBT = "62465E79F6A61F31C4DCA9E2AF788DD3";
		/* EnEV-Nachweis */
		const Ausstellungsdatum = moment(
			ausweis.aufnahme.erstellungsdatum
		).format("DD.MM.YYYY");
		const Gesetzesgrundlage = "GEG-2024";

		/* EnergieausweisDaten */
		let gebaeudeart: string = "";
		if (
			ausweisart == Enums.Ausweisart.VerbrauchsausweisGewerbe &&
			ausweis.aufnahme.gebaeudeteil == "Gewerbe"
		) {
			gebaeudeart = "Nichtwohnteil gemischt genutztes Gebäude";
		} else if (
			(ausweisart == Enums.Ausweisart.VerbrauchsausweisWohnen ||
				ausweisart == Enums.Ausweisart.BedarfsausweisWohnen) &&
			ausweis.aufnahme.gebaeudeteil == "Wohnen"
		) {
			gebaeudeart = "Wohnteil gemischt genutztes Gebäude";
		} else if (
			(ausweisart == Enums.Ausweisart.VerbrauchsausweisWohnen ||
				ausweisart == Enums.Ausweisart.BedarfsausweisWohnen) &&
			ausweis.aufnahme.gebaeudeteil == "Gesamtgebäude"
		) {
			gebaeudeart = "Wohngebäude";
		} else if (
			ausweisart == Enums.Ausweisart.VerbrauchsausweisGewerbe &&
			ausweis.aufnahme.gebaeudeteil == "Gesamtgebäude"
		) {
			gebaeudeart = "Nichtwohngebäude";
		}

		const art: string =
			ausweisart == Enums.Ausweisart.BedarfsausweisWohnen
				? "Energiebedarfsausweis"
				: "Energieverbrauchsausweis";

		const body = `<Datenregistratur xmlns="http://energieausweis.dibt.de/WebServiceEnergie/DibtEnergieAusweisService">
						<doc>
						<root>
						<Authentifizierung>
							<Aussteller_ID_DIBT>${Aussteller_ID_DIBT}</Aussteller_ID_DIBT>
							<Aussteller_PWD_DIBT>${Aussteller_PWD_DIBT}</Aussteller_PWD_DIBT>
						</Authentifizierung>
						<EnEV-Nachweis>
							<Ausstellungsdatum>${Ausstellungsdatum}</Ausstellungsdatum>
							<Bundesland>${postleitzahl.bundesland}</Bundesland>
							<Postleitzahl>${postleitzahl.plz}</Postleitzahl>
							<Gesetzesgrundlage>${Gesetzesgrundlage}</Gesetzesgrundlage>
						</EnEV-Nachweis>
						<Energieausweis-Daten>
							<Gebaeudeart>${gebaeudeart}</Gebaeudeart>
							<Art>${art}</Art>
							<Neubau>${
								ausweis.ausstellgrund ===
								Enums.Ausstellgrund.Neubau
									? "1"
									: "0"
							}</Neubau>
						</Energieausweis-Daten>
				</root>
			</doc>
		</Datenregistratur>`;

		return await new Promise(async (resolve, reject) => {
			soap.createClient(
				"https://energieausweis.dibt.de/published/WebServiceEnergieausweis/DibtEnergieAusweisServiceEx01.wsdl",
				{},
				function (err, client) {
					if (err !== null) {
						throw new APIError({
							code: "INTERNAL_SERVER_ERROR",
							message: err,
						});
					}

					client.Datenregistratur(
						body,
						async function (
							err: any,
							result: {
								DatenregistraturResult: {
									WEB_Service_Antwort: {
										Rueckgabewert?: null;
										Registriernummer: string;
										Datendatei: any;
									};
								};
							}
						) {
							if (err !== null) {
								reject({
									code: "INTERNAL_SERVER_ERROR",
									message: err,
								});
							}

							if (
								result.DatenregistraturResult
									.WEB_Service_Antwort.Registriernummer
							) {
								await (
									adapter as typeof prisma.verbrauchsausweisWohnen
								).update({
									where: {
										uid,
									},
									data: {
										registriernummer:
											result.DatenregistraturResult
												.WEB_Service_Antwort
												.Registriernummer,
										kontrolldatei_angefragt: result
											.DatenregistraturResult
											.WEB_Service_Antwort.Datendatei
											? true
											: false,
									},
								});

								resolve(
									result.DatenregistraturResult
										.WEB_Service_Antwort.Registriernummer
								);
							} else {
								reject({
									code: "INTERNAL_SERVER_ERROR",
									message: "Unerwarteter Rückgabewert.",
								});
							}
						}
					);
				}
			);
		}).catch((reason) => {
			throw new APIError(reason);
		});
	},
});
