import { TRPCError } from "@trpc/server";
import { jsonObjectFrom } from "kysely/helpers/postgres";
import type { NewUsers, UsersId } from "~/schemas/public/Users";
import type { Session } from "~/server/api/trpc";
import { db, type Querier } from "~/server/db";

export const findUser_byId = async ({ id }: { id: string }) => {
	try {
		return await db
			.selectFrom("users")
			.selectAll()
			.where("id", "=", id as UsersId)
			.executeTakeFirst();
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Errore findUser_byId - id: ${id}: ${(e as Error).message}`,
		});
	}
};
export const findUser_byEmail = async ({ email }: { email: string }) => {
	try {
		return await db
			.selectFrom("users")
			.selectAll()
			.where("email", "=", email)
			.executeTakeFirst();
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Errore findUser_byEmail - email: ${email}: ${(e as Error).message}`,
		});
	}
};
export const findUser_byId_MINI = async ({
	userId,
}: {
	userId: UsersId;
}): Promise<Session | undefined> => {
	try {
		return await db
			.selectFrom("users")
			.select([
				"id",
				"username",
				"nome",
				"email",
				"isAdmin",
				"isBlocked",
				"mustChangePassword",
			])
			.where("id", "=", userId)
			.executeTakeFirst();
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `errore findUser_byId_MINI - userId: ${userId}: ${(e as Error).message}`,
		});
	}
};

export const getUser = async ({
	db,
	userId,
}: {
	db: Querier;
	userId: UsersId;
}) => {
	try {
		return await db
			.selectFrom("users")
			.selectAll()
			.where("id", "=", userId)
			.executeTakeFirstOrThrow(
				() => new Error(`User not found - userId: ${userId}`),
			);
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `errore getUser - userId: ${userId}: ${(e as Error).message}`,
		});
	}
};

export const addUser = async ({
	db,
	data,
}: {
	db: Querier;
	data: NewUsers;
}) => {
	try {
		const user = await db
			.insertInto("users")
			.values({
				...data,
			})
			.onConflict((oc) => oc.column("email").doNothing())
			.returningAll()
			.executeTakeFirst();

		return user;
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Errore addUser - email: ${data.email}: ${(e as Error).message}`,
		});
	}
};

export type CompleteUserData = Awaited<ReturnType<typeof getClientProfilo>>;
export const getClientProfilo = async ({
	db,
	userId,
}: {
	db: Querier;
	userId: UsersId;
}) => {
	try {
		return await db
			.selectFrom("users")
			.select([
				"id",
				"nome",
				"cognome",
				"email",
				"telefono",
				"extra_telefono_numero",
				"extra_telefono_titolo",
				"created_at",
				"isAdmin",
				"isBlocked",
				"isAdminMade",
				"mustChangePassword",
			])
			.where("id", "=", userId)
			.leftJoin("users_anagrafica", "users_anagrafica.userid", "users.id")
			.selectAll("users_anagrafica")
			.select((eb) => [
				jsonObjectFrom(
					eb
						.selectFrom("users_storage")
						.select([
							"users_storage.storageId as storageId",
							"users_anagrafica.doc_personale_fronte_ref as ref",
						])
						.whereRef(
							"users_storage.user_storage_id",
							"=",
							"users_anagrafica.doc_personale_fronte_ref",
						),
				).as("doc_personale_fronte"),
				jsonObjectFrom(
					eb
						.selectFrom("users_storage")
						.select([
							"users_storage.storageId as storageId",
							"users_anagrafica.doc_personale_retro_ref as ref",
						])
						.whereRef(
							"users_storage.user_storage_id",
							"=",
							"users_anagrafica.doc_personale_retro_ref",
						),
				).as("doc_personale_retro"),
			])
			.executeTakeFirstOrThrow(
				() => new Error(`User not found - userId: ${userId}`),
			);
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Errore interno - userId: ${userId}: ${(e as Error).message}`,
		});
	}
};
