"use server";

import { validateRequest } from "@/server/auth";
import { UserRole } from "@/server/auth/permissions";
import { db } from "@/server/db";
import { printJobs, users } from "@/server/db/schema";
import { PermissionError } from "@/utils/errors";
import { IS, guard } from "@/utils/guard";
import { type InferInsertModel, eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";

export async function createPrintJob(printJob: InferInsertModel<typeof printJobs>) {
	const { user } = await validateRequest();

	if (guard(user, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	const dbUser = await db.query.users.findFirst({
		// biome-ignore lint/style/noNonNullAssertion: guard already checks against null
		where: eq(users.id, user!.id),
	});

	if (guard(dbUser, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	try {
		const result = await db.insert(printJobs).values(printJob).returning({
			jobId: printJobs.id,
		});

		return result[0].jobId;
	} catch (error) {
		throw new Error("Druckauftrag konnte nicht hinzugefügt werden.");
	}
}

/* async function updatePrintJob(jobId: string, printJob: InferInsertModel<typeof printJobs>) {
	const { user } = await validateRequest();

	if (guard(user, is, UserRole.GUEST)) {
		throw new PermissionError();
	}

	const dbUser = await db.query.users.findFirst({
		// biome-ignore lint/style/noNonNullAssertion: guard already checks against null
		where: eq(users.id, user!.id),
	});

	if (guard(dbUser, is, UserRole.GUEST)) {
		throw new PermissionError();
	}

	await db.update(printJobs).set(printJob).where(eq(printJobs.id, jobId));
} */

export async function abortPrintJob(jobId: string, reason: string) {
	const { user } = await validateRequest();

	if (guard(user, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	const dbUser = await db.query.users.findFirst({
		// biome-ignore lint/style/noNonNullAssertion: guard already checks against null
		where: eq(users.id, user!.id),
	});

	if (guard(dbUser, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	// Get the print job
	const printJob = await db.query.printJobs.findFirst({
		where: eq(printJobs.id, jobId),
	});

	if (!printJob) {
		throw new Error("Druckauftrag nicht gefunden");
	}

	// Check if the print job is already aborted or completed
	if (printJob.aborted) {
		throw new Error("Druckauftrag wurde bereits abgebrochen");
	}

	if (new Date(printJob.startAt).getTime() + printJob.durationInMinutes * 60 * 1000 < Date.now()) {
		throw new Error("Druckauftrag ist bereits abgeschlossen");
	}

	// Check if user is the owner of the print job
	// biome-ignore lint/style/noNonNullAssertion:  guard already checks against null
	if (printJob.userId !== dbUser!.id || dbUser!.role !== UserRole.ADMIN) {
		throw new PermissionError();
	}

	// Get duration in minutes since startAt
	const duration = Math.floor((Date.now() - new Date(printJob.startAt).getTime()) / 1000 / 60);

	await db
		.update(printJobs)
		.set({
			aborted: true,
			abortReason: reason,
			durationInMinutes: duration,
			comments: `${printJob.comments}\n\n---${dbUser?.username}: Druckauftrag abgebrochen`,
		})
		.where(eq(printJobs.id, jobId));

	revalidatePath("/");
}

export async function earlyFinishPrintJob(jobId: string) {
	const { user } = await validateRequest();

	if (guard(user, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	const dbUser = await db.query.users.findFirst({
		// biome-ignore lint/style/noNonNullAssertion: guard already checks against null
		where: eq(users.id, user!.id),
	});

	if (guard(dbUser, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	// Get the print job
	const printJob = await db.query.printJobs.findFirst({
		where: eq(printJobs.id, jobId),
	});

	if (!printJob) {
		throw new Error("Druckauftrag nicht gefunden");
	}

	// Check if the print job is already aborted or completed
	if (printJob.aborted) {
		throw new Error("Druckauftrag wurde bereits abgebrochen");
	}

	if (new Date(printJob.startAt).getTime() + printJob.durationInMinutes * 60 * 1000 < Date.now()) {
		throw new Error("Druckauftrag ist bereits abgeschlossen");
	}

	// Check if user is the owner of the print job
	// biome-ignore lint/style/noNonNullAssertion:  guard already checks against null
	if (printJob.userId !== dbUser!.id || dbUser!.role !== UserRole.ADMIN) {
		throw new PermissionError();
	}

	// Get duration in minutes since startAt
	const duration = Math.floor((Date.now() - new Date(printJob.startAt).getTime()) / 1000 / 60);

	await db
		.update(printJobs)
		.set({
			durationInMinutes: duration,
			comments: `${printJob.comments}\n\n---${dbUser?.username}: Druckauftrag vorzeitig abgeschlossen`,
		})
		.where(eq(printJobs.id, jobId));

	revalidatePath("/");
}

export async function extendPrintJob(jobId: string, minutes: number, hours: number) {
	const { user } = await validateRequest();

	if (guard(user, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	const dbUser = await db.query.users.findFirst({
		// biome-ignore lint/style/noNonNullAssertion: guard already checks against null
		where: eq(users.id, user!.id),
	});

	if (guard(dbUser, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	// Get the print job
	const printJob = await db.query.printJobs.findFirst({
		where: eq(printJobs.id, jobId),
	});

	if (!printJob) {
		throw new Error("Druckauftrag nicht gefunden");
	}

	// Check if the print job is already aborted or completed
	if (printJob.aborted) {
		throw new Error("Druckauftrag wurde bereits abgebrochen");
	}

	if (new Date(printJob.startAt).getTime() + printJob.durationInMinutes * 60 * 1000 < Date.now()) {
		throw new Error("Druckauftrag ist bereits abgeschlossen");
	}

	// Check if user is the owner of the print job
	// biome-ignore lint/style/noNonNullAssertion:  guard already checks against null
	if (printJob.userId !== dbUser!.id || dbUser!.role !== UserRole.ADMIN) {
		throw new PermissionError();
	}

	const duration = minutes + hours * 60;

	await db
		.update(printJobs)
		.set({
			durationInMinutes: printJob.durationInMinutes + duration,
			comments: `${printJob.comments}\n\n---${dbUser?.username}: Verlängert um ${hours} Stunden und ${minutes} Minuten`,
		})
		.where(eq(printJobs.id, jobId));

	revalidatePath("/");
}

export async function updatePrintComments(jobId: string, comments: string) {
	const { user } = await validateRequest();

	if (guard(user, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	const dbUser = await db.query.users.findFirst({
		// biome-ignore lint/style/noNonNullAssertion: guard already checks against null
		where: eq(users.id, user!.id),
	});

	if (guard(dbUser, IS, UserRole.GUEST)) {
		throw new PermissionError();
	}

	// Get the print job
	const printJob = await db.query.printJobs.findFirst({
		where: eq(printJobs.id, jobId),
	});

	if (!printJob) {
		throw new Error("Druckauftrag nicht gefunden");
	}

	// Check if the print job is already aborted or completed
	if (printJob.aborted) {
		throw new Error("Druckauftrag wurde bereits abgebrochen");
	}

	if (new Date(printJob.startAt).getTime() + printJob.durationInMinutes * 60 * 1000 < Date.now()) {
		throw new Error("Druckauftrag ist bereits abgeschlossen");
	}

	// Check if user is the owner of the print job
	// biome-ignore lint/style/noNonNullAssertion:  guard already checks against null
	if (printJob.userId !== dbUser!.id || dbUser!.role !== UserRole.ADMIN) {
		throw new PermissionError();
	}

	await db
		.update(printJobs)
		.set({
			comments,
		})
		.where(eq(printJobs.id, jobId));

	revalidatePath("/");
}
