import { TRPCError } from "@trpc/server";
import type { Nullable } from "kysely";
import type {
	NewPotenziali,
	Potenziali,
	PotenzialiId,
	PotenzialiUpdate,
} from "~/schemas/public/Potenziali";
import type {
	NewPotenzialiGroups,
	PotenzialiGroups,
	PotenzialiGroupsId,
} from "~/schemas/public/PotenzialiGroups";
import type { Users } from "~/schemas/public/Users";
import { db } from "../db";

export type PotenzialeData = Omit<Potenziali, "potenziali_group_id"> & {
	column: string;
} & Nullable<Pick<Users, "username">>;

export const getPotenziali = async (): Promise<PotenzialeData[]> => {
	try {
		const potenziali = await db
			.selectFrom("potenziali")
			.select([
				"potenziali.id",
				"potenziali.name",
				"potenziali.created_at",
				"potenziali.descrizione",
				"potenziali.userid",
				"potenziali.potenziali_group_id as column",
			])
			.innerJoin(
				"potenziali_groups",
				"potenziali.potenziali_group_id",
				"potenziali_groups.id",
			)
			.leftJoin("users", "potenziali.userid", "users.id")
			.select("users.username")
			.orderBy("potenziali_groups.name", "asc")
			.orderBy("potenziali.created_at", "asc")
			.execute();

		return potenziali.map((data) => ({
			...data,
			created_at: new Date(data.created_at),
		}));
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to fetch potenziali, error: ${(e as Error).message}`,
		});
	}
};

export const getPotenzialiGroups = async (): Promise<PotenzialiGroups[]> => {
	try {
		return await db.selectFrom("potenziali_groups").selectAll().execute();
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to fetch potenziali groups, error: ${(e as Error).message}`,
		});
	}
};

export const addPotenzialeGroup = async (data: NewPotenzialiGroups) => {
	try {
		await db.insertInto("potenziali_groups").values(data).execute();
		return { status: "success" };
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to add potenziale group, error: ${(e as Error).message}`,
		});
	}
};

export const deletePotenzialeGroup = async (id: PotenzialiGroupsId) => {
	try {
		await db.deleteFrom("potenziali_groups").where("id", "=", id).execute();
		return { status: "success" };
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to delete potenziale group, error: ${(e as Error).message}`,
		});
	}
};

export const addPotenziale = async (data: NewPotenziali) => {
	try {
		await db.insertInto("potenziali").values(data).execute();
		return { status: "success" };
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to add potenziale, error: ${(e as Error).message}`,
		});
	}
};

export const deletePotenziale = async (id: PotenzialiId) => {
	try {
		await db.deleteFrom("potenziali").where("id", "=", id).execute();
		return { status: "success" };
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to delete potenziale, error: ${(e as Error).message}`,
		});
	}
};

export const updatePotenziale = async (
	id: PotenzialiId,
	data: PotenzialiUpdate,
) => {
	try {
		await db.updateTable("potenziali").set(data).where("id", "=", id).execute();
		return { status: "success" };
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to update potenziale, error: ${(e as Error).message}`,
		});
	}
};

export const updatePotenziali = async (data: PotenzialeData[]) => {
	try {
		const db_mappings = await db
			.selectFrom("potenziali")
			.select(["id", "potenziali_group_id"])
			.execute();

		const updates = data
			.map((item) => {
				const db_item = db_mappings.find((db_item) => db_item.id === item.id);
				if (db_item && db_item.potenziali_group_id !== item.column) {
					const { column, username: _username, ...rest } = item;
					return {
						...rest,
						potenziali_group_id: column as PotenzialiGroupsId,
					};
				}
				return null;
			})
			.filter((item) => item !== null);

		for (const item of updates) {
			await db
				.updateTable("potenziali")
				.set(item)
				.where("id", "=", item.id)
				.execute();
		}
		return { status: "success" };
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to update potenziali, error: ${(e as Error).message}`,
		});
	}
};
