import { TRPCError } from "@trpc/server";
import { format } from "date-fns";
import { z } from "zod/v4";
import type { EmailsIdEmail } from "~/schemas/public/Emails";
import type { EventQueueUpdate } from "~/schemas/public/EventQueue";
import type { TestiEStringheStingaId } from "~/schemas/public/TestiEStringhe";
import {
	adminProcedure,
	createTRPCRouter,
	protectedProcedure,
	publicProcedure,
} from "~/server/api/trpc";
import {
	addEventToQueue,
	clearUserEmailQueue,
	removeEventFromQueue,
	updateEvent,
	userEmailQueue,
} from "~/server/controllers/event_queue.controller";
import { UtenteInteressatoAdAnnuncioEmail } from "~/server/controllers/servizio.controller";
import { db } from "~/server/db";
import {
	deleteAllUserEmails,
	deleteEmail,
	getEmails,
} from "~/server/services/email.service";
import type { MailsTemplates } from "~/server/services/mail-templates";
import { NewMail } from "~/server/services/mailer";
import { CONDIZIONI_DEFAULT } from "~/server/services/prezziario.service";
import { zEventId, zOrdineId, zUserId } from "~/server/utils/zod_types";

export const comunicazioniRouter = createTRPCRouter({
	getEmails: protectedProcedure
		.input(z.object({ userId: zUserId }))
		.query(async ({ input }) => {
			return await getEmails({
				userId: input.userId,
			});
		}),
	deleteEmail: adminProcedure
		.input(
			z.object({
				id_email: z.custom<EmailsIdEmail>(),
			}),
		)
		.mutation(async ({ input }) => {
			return await deleteEmail({
				id_email: input.id_email,
			});
		}),
	deleteAllUserEmails: adminProcedure
		.input(z.object({ userId: zUserId }))
		.mutation(async ({ input }) => {
			return await deleteAllUserEmails({
				userId: input.userId,
			});
		}),
	sendEmailContatto: publicProcedure
		.input(
			z.object({
				cognome: z.string(),
				email: z.email(),
				messaggio: z.string(),
				nome: z.string(),
				telefono: z.string(),
			}),
		)
		.mutation(async ({ input }) => {
			await NewMail({
				template: {
					mailType: "contattoAdminEmail",
					props: {
						cognome: input.cognome,
						email: input.email,
						messaggio: input.messaggio,
						nome: input.nome,
						telefono: input.telefono,
					},
				},
				mail: {
					subject: `Richiesta di contatto da ${input.nome}`,
					to: "web@infoalloggi.it",
				},
			});
			return { success: true };
		}),

	sendUtenteInteressatoAdAnnuncioEmail: publicProcedure
		.input(
			z.object({
				codice: z.string(),
				email: z.string(),
				messaggio: z.string(),
				nome: z.string(),
				telefono: z.string(),
			}),
		)
		.mutation(async ({ input }) => {
			return await UtenteInteressatoAdAnnuncioEmail({
				...input,
			});
		}),
	sendRicevutaECondizioniEmail: adminProcedure
		.input(
			z.object({
				ordineId: zOrdineId,
			}),
		)
		.mutation(async ({ input }) => {
			try {
				const ordine = await db
					.selectFrom("ordini")
					.selectAll("ordini")
					.innerJoin("users", "users.id", "ordini.userid")
					.select(["users.email", "users.username"])
					.innerJoin("prezziario", "prezziario.idprezziario", "ordini.packid")
					.select(["prezziario.testo_condizioni"])
					.where("ordine_id", "=", input.ordineId)
					.executeTakeFirstOrThrow(() => {
						throw new Error(`Ordine not found - ordineId: ${input.ordineId}`);
					});

				const condizioniFilename = `condizioni_contrattuali_${ordine.created_at.toISOString()}.pdf`;
				const ricevutaFilename = `ricevuta_cortesia_${ordine.username.replace(/\s+/g, "-")}-${format(ordine.created_at, "dd-MM-yyyy")}.pdf`;
				const lock_expires = new Date(Date.now() + 3000); // Lock for 30 sec

				await addEventToQueue({
					data: {
						tipo: "email",
						data: {
							template: {
								mailType: "servizioAttivato",
							},
							mail: {
								subject: "Pagamento Confermato - Acconto Infoalloggi.it",
								to: ordine.email,
								attachments: [
									{
										filename: condizioniFilename,
										generate: {
											type: "condizioni",
											stringId: (ordine.testo_condizioni ||
												CONDIZIONI_DEFAULT) as TestiEStringheStingaId,
										},
										encoding: "base64",
										contentType: "application/pdf",
									},
									{
										filename: ricevutaFilename,

										generate: {
											type: "ricevuta_cortesia",
											ordineId: ordine.ordine_id,
										},
										encoding: "base64",
										contentType: "application/pdf",
									},
								],
							},
							userId: ordine.userid,
						},
					},
					lock_expires,
				});
				await addEventToQueue({
					data: {
						tipo: "email",
						data: {
							template: {
								mailType: "generic",
								props: {
									title: "Nuovo pagamento ricevuto",
									testo: `È stato ricevuto un nuovo pagamento.`,
								},
							},
							mail: {
								subject: "Ric pagamento",
								to: "web@infoalloggi.it",
								attachments: [
									{
										filename: ricevutaFilename,

										generate: {
											type: "ricevuta_cortesia",
											ordineId: ordine.ordine_id,
										},
										encoding: "base64",
										contentType: "application/pdf",
									},
									{
										filename: condizioniFilename,
										generate: {
											type: "condizioni",
											stringId: (ordine.testo_condizioni ||
												CONDIZIONI_DEFAULT) as TestiEStringheStingaId,
										},
										encoding: "base64",
										contentType: "application/pdf",
									},
								],
							},
						},
					},
					lock_expires,
				});
			} catch (e) {
				throw new TRPCError({
					code: "INTERNAL_SERVER_ERROR",
					message: `Errore nell'aggiunta dell'email alla coda: ${(e as Error).message}`,
					cause: e instanceof Error ? e : undefined,
				});
			}
		}),
	getUserQueuedEmails: protectedProcedure
		.input(z.object({ userId: zUserId }))
		.query(async ({ input }) => {
			return await userEmailQueue(input.userId);
		}),
	addToUserEmailQueue: adminProcedure
		.input(
			z.object({
				lock_expires: z.date(),
				userId: zUserId,
				template: z.custom<MailsTemplates>(),
				subject: z.string(),
			}),
		)
		.mutation(async ({ input }) => {
			try {
				const user = await db
					.selectFrom("users")
					.selectAll()
					.where("id", "=", input.userId)
					.executeTakeFirstOrThrow(() => {
						throw new Error(`User with id ${input.userId} not found`);
					});
				await addEventToQueue({
					data: {
						tipo: "email",
						data: {
							template: input.template,
							mail: {
								to: user.email,
								subject: input.subject,
							},
							userId: input.userId,
						},
					},
					lock_expires: input.lock_expires,
				});
				return { success: true };
			} catch (error) {
				throw new TRPCError({
					code: "INTERNAL_SERVER_ERROR",
					message: `Errore nell'aggiunta dell'email alla coda: ${
						error instanceof Error ? error.message : "Errore sconosciuto"
					}`,
					cause: error instanceof Error ? error : undefined,
				});
			}
		}),

	removeFromUserEmailQueue: adminProcedure
		.input(
			z.object({
				eventId: zEventId,
			}),
		)
		.mutation(async ({ input }) => {
			return await removeEventFromQueue(input.eventId);
		}),

	clearUserEmailQueue: adminProcedure
		.input(z.object({ userId: zUserId }))
		.mutation(async ({ input }) => {
			return await clearUserEmailQueue(input.userId);
		}),
	updateEvent: adminProcedure
		.input(
			z.object({
				eventId: zEventId,
				data: z.custom<EventQueueUpdate>(),
			}),
		)
		.mutation(async ({ input }) => {
			return await updateEvent(input.eventId, input.data);
		}),
});
