import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { env } from "~/env";
import {
	adminProcedure,
	createTRPCRouter,
	publicProcedure,
} from "~/server/api/trpc";
import {
	consumeInviteToken,
	createInviteToken,
	sendInvitoEmail,
	verifyInviteToken,
} from "~/server/controllers/invites.controller";
import { editAccountHandler } from "~/server/controllers/user.controller";
import { db } from "~/server/db";
import { generateSalt, hashPassword } from "~/server/services/password.service";
import { findUser_byEmail, getUser } from "~/server/services/user.service";
import { zUserId } from "~/server/utils/zod_types";

export const inviteRouter = createTRPCRouter({
	// Admin sends invite
	sendInvite: adminProcedure
		.input(
			z.object({
				id: zUserId,
			}),
		)
		.mutation(async ({ input }) => {
			const user = await getUser({ userId: input.id, db });
			const token = await createInviteToken(user.email);

			const inviteUrl = `${env.BASE_URL}/auth/accetta-invito/${token}`;

			await sendInvitoEmail({
				userId: input.id,
				email: user.email,
				nome: user.nome,
				inviteUrl,
			});

			return { success: true };
		}),

	// Verify invite token (public - user clicking the link)
	verifyInvite: publicProcedure
		.input(z.object({ token: z.string() }))
		.query(async ({ input }) => {
			const invite = await verifyInviteToken(input.token);

			if (!invite) {
				return { valid: false, email: null };
			}

			return { valid: true, email: invite.email };
		}),

	// Accept invite and set password
	acceptInvite: publicProcedure
		.input(
			z.object({
				email: z.email(),
				token: z.string(),
				password: z.string().min(8),
			}),
		)
		.mutation(async ({ input }) => {
			const user = await findUser_byEmail({ email: input.email });
			if (!user) {
				throw new TRPCError({
					code: "NOT_FOUND",
					message: "Utente non trovato",
				});
			}
			const invite = await verifyInviteToken(input.token);

			if (!invite) {
				throw new TRPCError({
					code: "NOT_FOUND",
					message: "Invito non valido o scaduto",
				});
			}

			// Create user with password
			const salt = generateSalt();
			const hashedPassword = await hashPassword(input.password, salt);

			await editAccountHandler({
				id: user.id,
				data: {
					password: hashedPassword,
					salt,
				},
			});

			// Mark invite as used
			await consumeInviteToken(input.token);

			return { success: true };
		}),
});
