import { and, eq } from "drizzle-orm";
import { db } from "../../db/db";
import { backupSchedulesTable, backupScheduleMirrorsTable } from "../../db/schema";

type BackupStatusType = "in_progress" | "success" | "warning" | "error";
type MirrorStatusType = "in_progress" | "success" | "error";

type MirrorStatusUpdate = {
	lastCopyAt?: number | null;
	lastCopyStatus?: MirrorStatusType;
	lastCopyError?: string | null;
};

export const scheduleQueries = {
	findById: async (scheduleId: number, organizationId: string) => {
		return db.query.backupSchedulesTable.findFirst({
			where: { AND: [{ id: scheduleId }, { organizationId }] },
			with: { volume: true, repository: true },
		});
	},

	findExecutable: async (organizationId: string) => {
		const now = Date.now();
		const schedules = await db.query.backupSchedulesTable.findMany({
			where: {
				AND: [
					{ enabled: true },
					{ OR: [{ lastBackupStatus: { ne: "in_progress" } }, { lastBackupStatus: { isNull: true } }] },
					{ organizationId },
				],
			},
		});

		return schedules.filter((s) => !s.nextBackupAt || s.nextBackupAt <= now).map((s) => s.id);
	},

	updateStatus: async (
		scheduleId: number,
		organizationId: string,
		status: {
			lastBackupStatus?: BackupStatusType;
			lastBackupAt?: number;
			lastBackupError?: string | null;
			nextBackupAt?: number | null;
			failureRetryCount?: number;
		},
	) => {
		return db
			.update(backupSchedulesTable)
			.set({ ...status, updatedAt: Date.now() })
			.where(and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)));
	},
};

export const mirrorQueries = {
	findEnabledBySchedule: async (scheduleId: number) => {
		return db.query.backupScheduleMirrorsTable.findMany({
			where: { scheduleId, enabled: true },
			with: { repository: true },
		});
	},

	findByScheduleAndRepository: async (scheduleId: number, repositoryId: string) => {
		return db.query.backupScheduleMirrorsTable.findFirst({
			where: { scheduleId, repositoryId },
			with: { repository: true },
		});
	},

	updateStatus: async (scheduleId: number, repositoryId: string, status: MirrorStatusUpdate) => {
		return db
			.update(backupScheduleMirrorsTable)
			.set(status)
			.where(
				and(
					eq(backupScheduleMirrorsTable.scheduleId, scheduleId),
					eq(backupScheduleMirrorsTable.repositoryId, repositoryId),
				),
			);
	},
};

export const repositoryQueries = {
	findById: async (repositoryId: string, organizationId: string) => {
		return db.query.repositoriesTable.findFirst({
			where: { AND: [{ id: repositoryId }, { organizationId }] },
		});
	},
};
