import z from "zod";
import type { NewOrdini, OrdiniUpdate } from "~/schemas/public/Ordini";
import type {
	NewRinnovi,
	Rinnovi,
	RinnoviUpdate,
} from "~/schemas/public/Rinnovi";
import type { NewServizio, ServizioUpdate } from "~/schemas/public/Servizio";
import type { ServizioAnnunciUpdate } from "~/schemas/public/ServizioAnnunci";
import type { Users } from "~/schemas/public/Users";
import type { UsersAnagraficaUpdate } from "~/schemas/public/UsersAnagrafica";
import {
	adminProcedure,
	createTRPCRouter,
	protectedProcedure,
} from "~/server/api/trpc";
import { getPacksPerServizio } from "~/server/controllers/pagamenti.controller";
import {
	AdminAttivaServizio_Ufficio,
	addServizioAnnunci,
	attivaServizio_SaltaPagamentoAcconto,
	getAllServizioAnnunci,
	getAnnunciAvailableToAdd,
	getCompatibileAnnunci,
	getDataPerAcquisto,
	getRichieste,
	getServizioDataById,
	InteractionLogicTipologia,
	interruzioneServizio,
	processServizioOnboard,
	SbloccaContatti,
	type ServizioData,
} from "~/server/controllers/servizio.controller";
import {
	createOrdine,
	getOrdineById,
	getOrdini,
	removeOrder,
	updateOrder,
} from "~/server/services/ordini.service";
import {
	createRinnovo,
	deleteRinnovo,
	getRinnoviUser,
	getRinnovoData,
	updateRinnovo,
} from "~/server/services/rinnovi.service";
import {
	addServizio,
	deleteServizio,
	deleteServizioAnnuncio,
	getServizioAnnuncio,
	getServizioById,
	updateServizio,
	updateServizioAnnuncio,
} from "~/server/services/servizio.service";
import {
	zAnnuncioId,
	zOrdineId,
	zRinnovoId,
	zServizioId,
	zUserId,
} from "~/server/utils/zod_types";

export const servizioRouter = createTRPCRouter({
	AnnuncioServizioTipologiaMatch: protectedProcedure
		.input(
			z.object({
				annuncioId: zAnnuncioId,
				tipologia: z.string(),
				userId: zUserId,
			}),
		)
		.query(async ({ input }) => {
			return await InteractionLogicTipologia({
				annuncioId: input.annuncioId,
				tipologia: input.tipologia,
				userId: input.userId,
			});
		}),
	addServizio: adminProcedure
		.input(
			z.object({
				data: z.custom<NewServizio>(),
			}),
		)
		.mutation(async ({ input }) => {
			return await addServizio(input.data);
		}),
	addServizioAnnunci: adminProcedure
		.input(
			z.object({
				annunci: z.array(zAnnuncioId),
				servizioId: zServizioId,
			}),
		)
		.mutation(async ({ input }) => {
			return await addServizioAnnunci({
				annunci: input.annunci,
				servizioId: input.servizioId,
			});
		}),
	deleteServizio: adminProcedure
		.input(
			z.object({
				servizioId: zServizioId,
			}),
		)
		.mutation(async ({ input }) => {
			return await deleteServizio(input.servizioId);
		}),

	getAcquistoData: protectedProcedure
		.input(
			z.object({
				servizioId: zServizioId,
			}),
		)
		.query(async ({ input }) => {
			return await getDataPerAcquisto(input.servizioId);
		}),
	getRichieste: adminProcedure.query(async () => {
		return await getRichieste();
	}),
	getServizioData: protectedProcedure
		.input(
			z.object({
				servizioId: zServizioId,
			}),
		)
		.query(async ({ input }) => {
			return await getServizioDataById(input.servizioId);
		}),
	getAnnunciAvailableToAdd: adminProcedure
		.input(
			z.object({
				servizioId: zServizioId,
			}),
		)
		.query(async ({ input }) => {
			return await getAnnunciAvailableToAdd(input.servizioId);
		}),

	getCompatibileAnnunci: protectedProcedure
		.input(
			z.object({
				servizioId: zServizioId,
				adminOverride: z.boolean().optional(),
			}),
		)
		.query(async ({ input }) => {
			return await getCompatibileAnnunci({ ...input });
		}),
	getOrdineById: protectedProcedure
		.input(
			z.object({
				ordineId: zOrdineId,
			}),
		)
		.query(async ({ input }) => {
			return await getOrdineById(input.ordineId);
		}),

	getOrdini: protectedProcedure
		.input(
			z.object({
				userId: zUserId.optional(),
			}),
		)
		.query(async ({ input }) => {
			return await getOrdini(input.userId);
		}),

	isOnboardAvailable: protectedProcedure
		.input(
			z.object({
				servizioId: zServizioId,
			}),
		)
		.output(
			z.discriminatedUnion("available", [
				z.object({
					available: z.literal(true),
					userId: zUserId,
				}),
				z.object({
					available: z.literal(false),
					userId: z.null(),
				}),
			]),
		)
		.query(async ({ input }) => {
			const servizio = await getServizioById(input.servizioId);
			if (
				!servizio ||
				servizio.isOkAcconto ||
				servizio.isInterrotto ||
				servizio.decorrenza !== null
			) {
				return { available: false, userId: null };
			}
			return { available: true, userId: servizio.user_id };
		}),
	getServizioContratto: protectedProcedure
		.input(
			z.object({
				annuncioId: zAnnuncioId,
				servizioId: zServizioId,
			}),
		)
		.query(async ({ input }) => {
			const sa = await getServizioAnnuncio({
				annuncioId: input.annuncioId,
				servizioId: input.servizioId,
			});

			return sa.doc_contratto_ref;
		}),
	getServizioRegistrazione: protectedProcedure
		.input(
			z.object({
				annuncioId: zAnnuncioId,
				servizioId: zServizioId,
			}),
		)
		.query(async ({ input }) => {
			const sa = await getServizioAnnuncio({
				annuncioId: input.annuncioId,
				servizioId: input.servizioId,
			});

			return sa.doc_registrazione_ref;
		}),

	interruzioneServizio: protectedProcedure
		.input(
			z.object({
				servizioId: zServizioId,
				isAdmin: z.boolean(),
			}),
		)
		.mutation(async ({ input }) => {
			return await interruzioneServizio(input.servizioId, input.isAdmin);
		}),

	processServizioOnboard: protectedProcedure
		.input(
			z.object({
				anagrafica: z.custom<UsersAnagraficaUpdate>(),
				servizio: z.custom<ServizioUpdate>(),
				servizioId: zServizioId,
				user: z.custom<
					Pick<Users, "nome" | "cognome" | "email" | "telefono" | "username">
				>(),
				userId: zUserId,
			}),
		)
		.mutation(async ({ input }) => {
			return await processServizioOnboard({
				...input,
			});
		}),
	attivazioneSenzaPagamento: protectedProcedure
		.input(
			z.object({
				ordineId: zOrdineId,
			}),
		)
		.mutation(async ({ input }) => {
			return await attivaServizio_SaltaPagamentoAcconto(input.ordineId);
		}),
	AdminAttivaServizio_Ufficio: protectedProcedure
		.input(
			z.object({
				servizioId: zServizioId,
			}),
		)
		.mutation(async ({ input }) => {
			return await AdminAttivaServizio_Ufficio(input.servizioId);
		}),

	removeAnnuncioServizio: protectedProcedure
		.input(
			z.object({
				annuncioId: zAnnuncioId,
				servizioId: zServizioId,
			}),
		)
		.mutation(async ({ input }) => {
			return await deleteServizioAnnuncio(input.servizioId, input.annuncioId);
		}),
	removeOrder: adminProcedure
		.input(
			z.object({
				ordineId: zOrdineId,
			}),
		)
		.mutation(async ({ input }) => {
			return await removeOrder(input.ordineId);
		}),

	getPacksSolution: protectedProcedure
		.input(
			z.object({
				servizioId: zServizioId,
			}),
		)
		.query(async ({ input }) => {
			return await getPacksPerServizio(input.servizioId);
		}),
	unlockServizioContatti: protectedProcedure
		.input(
			z.object({
				annuncioId: zAnnuncioId,
				servizioId: zServizioId,
			}),
		)
		.mutation(async ({ input }) => {
			return await SbloccaContatti({
				annuncioId: input.annuncioId,
				servizioId: input.servizioId,
			});
		}),
	createOrdine: adminProcedure
		.input(
			z.object({
				data: z.custom<NewOrdini>(),
			}),
		)
		.mutation(async ({ input }) => {
			return await createOrdine(input.data);
		}),
	updateOrder: adminProcedure
		.input(
			z.object({
				data: z.custom<OrdiniUpdate>(),
				ordineId: zOrdineId,
			}),
		)
		.mutation(async ({ input }) => {
			return await updateOrder({
				data: input.data,
				ordineId: input.ordineId,
			});
		}),

	updateServizio: protectedProcedure
		.input(
			z.object({
				data: z.custom<ServizioUpdate>(),
				servizioId: zServizioId,
			}),
		)
		.mutation(async ({ input }) => {
			return await updateServizio({
				data: input.data,
				servizioId: input.servizioId,
			});
		}),
	updateServizioAnnunci: protectedProcedure
		.input(
			z.object({
				annuncioId: zAnnuncioId,
				data: z.custom<ServizioAnnunciUpdate>(),
				servizioId: zServizioId,
			}),
		)
		.mutation(async ({ input }) => {
			return await updateServizioAnnuncio({
				annuncioId: input.annuncioId,
				data: input.data,
				servizioId: input.servizioId,
			});
		}),

	getAllServiziData: protectedProcedure
		.input(
			z.object({
				userId: zUserId,
			}),
		)
		.query(async ({ input }) => {
			const data: (
				| { d: Date; type: "servizio"; data: ServizioData }
				| { d: Date; type: "rinnovo"; data: Rinnovi }
			)[] = [];

			const servizio = await getAllServizioAnnunci(input.userId);
			const rinnovi = await getRinnoviUser(input.userId);
			servizio.forEach((s) => {
				data.push({
					d: s.created_at,
					type: "servizio",
					data: s,
				});
			});
			rinnovi.forEach((r) => {
				data.push({
					d: r.decorrenza,
					type: "rinnovo",
					data: r,
				});
			});
			data.sort((a, b) => b.d.getTime() - a.d.getTime());
			return data;
		}),
	createRinnovo: adminProcedure
		.input(
			z.object({
				data: z.custom<NewRinnovi>(),
			}),
		)
		.mutation(async ({ input }) => {
			return await createRinnovo(input.data);
		}),
	updateRinnovo: adminProcedure
		.input(
			z.object({
				data: z.custom<RinnoviUpdate>(),
				rinnovoId: zRinnovoId,
			}),
		)
		.mutation(async ({ input }) => {
			return await updateRinnovo({
				rinnovoId: input.rinnovoId,
				data: input.data,
			});
		}),
	getRinnovo: protectedProcedure
		.input(
			z.object({
				rinnovoId: zRinnovoId,
			}),
		)
		.query(async ({ input }) => {
			return await getRinnovoData(input.rinnovoId);
		}),
	removeRinnovo: adminProcedure
		.input(
			z.object({
				rinnovoId: zRinnovoId,
			}),
		)
		.mutation(async ({ input }) => {
			return await deleteRinnovo(input.rinnovoId);
		}),
});
