import { TRPCError } from "@trpc/server";
import type { Insertable } from "kysely";
import { parseDBComune, parseDBNazione } from "~/lib/catasto";
import { Capitalize } from "~/lib/utils";
import type OrdiniTable from "~/schemas/public/Ordini";
import type {
	Ordini,
	OrdiniOrdineId,
	OrdiniUpdate,
} from "~/schemas/public/Ordini";
import type { Users, UsersId } from "~/schemas/public/Users";
import { getComuni, getNazioni } from "~/server/controllers/catasto.controller";
import { db } from "~/server/db";

export type ServizioOrdiniTable = Omit<OrdiniTable, "rinnovo_id">;
//export type ServizioOrdini = Selectable<ServizioOrdiniTable>;
export type NewServizioOrdini = Insertable<ServizioOrdiniTable>;
//export type ServizioOrdiniUpdate = Updateable<ServizioOrdiniTable>;
export type RinnovoOrdiniTable = Omit<OrdiniTable, "servizio_id">;
//export type RinnovoOrdini = Selectable<RinnovoOrdiniTable>;
export type NewRinnovoOrdini = Insertable<RinnovoOrdiniTable>;
//export type RinnovoOrdiniUpdate = Updateable<RinnovoOrdiniTable>;

export type Ordini_w_Utente = Ordini & Pick<Users, "username">;
export const getOrdini = async (
	userId: UsersId | undefined,
): Promise<Ordini_w_Utente[]> => {
	try {
		let qry = db
			.selectFrom("ordini")
			.selectAll("ordini")
			.innerJoin("users", "users.id", "ordini.userid")
			.select("users.username");

		if (userId) {
			qry = qry.where("ordini.userid", "=", userId);
		}
		return await qry.orderBy("created_at", "desc").execute();
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Error fetching ordini by user ID: ${(e as Error).message}`,
		});
	}
};

export const getOrdineById = async (ordineId: OrdiniOrdineId) => {
	try {
		const data = await db
			.selectFrom("ordini")
			.selectAll("ordini")
			.innerJoin("users", "users.id", "ordini.userid")
			.select("users.username")
			.innerJoin("users_anagrafica", "users_anagrafica.userid", "users.id")
			.select([
				"users_anagrafica.codice_fiscale",
				"users_anagrafica.via_residenza",
				"users_anagrafica.civico_residenza",
				"users_anagrafica.comune_residenza",
				"users_anagrafica.provincia_residenza",
				"users_anagrafica.cap_residenza",
				"users_anagrafica.nazione_residenza",
			])
			.where("ordini.ordine_id", "=", ordineId)
			.orderBy("created_at", "desc")
			.executeTakeFirstOrThrow(
				() => new Error(`Ordine not found - ordineId: ${ordineId}`),
			);
		const comuni = await getComuni();
		const nazioni = await getNazioni();

		const parsedComune = parseDBComune(data.comune_residenza, comuni);
		const parsedNazione = parseDBNazione(data.nazione_residenza, nazioni);

		return {
			...data,
			indirizzo: `${data.via_residenza} ${data.civico_residenza}, ${Capitalize(parsedComune?.nome)} (${data.provincia_residenza}) ${data.cap_residenza}, ${Capitalize(parsedNazione?.nome)}`,
		};
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Error fetching ordini by user ID: ${(e as Error).message}`,
		});
	}
};

export const createOrdine = async (
	data: NewServizioOrdini | NewRinnovoOrdini,
) => {
	try {
		return await db
			.insertInto("ordini")
			.values(data)
			.returningAll()
			.executeTakeFirstOrThrow(() => new Error("Failed to create ordine"));
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Error creating ordine: ${(e as Error).message}`,
		});
	}
};

export const removeOrder = async (ordineId: OrdiniOrdineId) => {
	try {
		await db.deleteFrom("ordini").where("ordine_id", "=", ordineId).execute();
		return true;
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Error removing order: ${(e as Error).message}`,
		});
	}
};

export const updateOrder = async ({
	ordineId,
	data,
}: {
	ordineId: OrdiniOrdineId;
	data: OrdiniUpdate;
}) => {
	try {
		const updated = await db
			.updateTable("ordini")
			.set(data)
			.where("ordine_id", "=", ordineId)
			.returningAll()
			.executeTakeFirstOrThrow(
				() => new Error(`Failed to update ordine - ordineId: ${ordineId}`),
			);
		return updated;
	} catch (e) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Error updating order: ${(e as Error).message}`,
		});
	}
};
