import type { Prisma, PrismaClient } from "@capakraken/db";
import {
  CreateManagementLevelGroupSchema,
  CreateManagementLevelSchema,
  UpdateManagementLevelGroupSchema,
  UpdateManagementLevelSchema,
} from "@capakraken/shared";
import { TRPCError } from "@trpc/server";
import { z } from "zod";

type ManagementLevelGroupDb = Pick<PrismaClient, "managementLevelGroup">;
type ManagementLevelDb = Pick<PrismaClient, "managementLevel">;

type ManagementLevelDeleteRecord = {
  _count: {
    resources: number;
  };
};

type CreateManagementLevelGroupInput = z.infer<typeof CreateManagementLevelGroupSchema>;
type UpdateManagementLevelGroupInput = z.infer<typeof UpdateManagementLevelGroupSchema>;
type CreateManagementLevelInput = z.infer<typeof CreateManagementLevelSchema>;
type UpdateManagementLevelInput = z.infer<typeof UpdateManagementLevelSchema>;

export async function assertManagementLevelGroupNameAvailable(
  db: ManagementLevelGroupDb,
  name: string,
  ignoreId?: string,
): Promise<void> {
  const existing = await db.managementLevelGroup.findUnique({ where: { name } });
  if (existing && existing.id !== ignoreId) {
    throw new TRPCError({
      code: "CONFLICT",
      message: `Group "${name}" already exists`,
    });
  }
}

export async function assertManagementLevelNameAvailable(
  db: ManagementLevelDb,
  name: string,
  ignoreId?: string,
): Promise<void> {
  const existing = await db.managementLevel.findUnique({ where: { name } });
  if (existing && existing.id !== ignoreId) {
    throw new TRPCError({
      code: "CONFLICT",
      message: `Level "${name}" already exists`,
    });
  }
}

export function buildManagementLevelGroupCreateData(
  input: CreateManagementLevelGroupInput,
): Prisma.ManagementLevelGroupUncheckedCreateInput {
  return {
    name: input.name,
    targetPercentage: input.targetPercentage,
    sortOrder: input.sortOrder,
  };
}

export function buildManagementLevelGroupUpdateData(
  input: UpdateManagementLevelGroupInput,
): Prisma.ManagementLevelGroupUncheckedUpdateInput {
  return {
    ...(input.name !== undefined ? { name: input.name } : {}),
    ...(input.targetPercentage !== undefined ? { targetPercentage: input.targetPercentage } : {}),
    ...(input.sortOrder !== undefined ? { sortOrder: input.sortOrder } : {}),
  };
}

export function buildManagementLevelCreateData(
  input: CreateManagementLevelInput,
): Prisma.ManagementLevelUncheckedCreateInput {
  return {
    name: input.name,
    groupId: input.groupId,
  };
}

export function buildManagementLevelUpdateData(
  input: UpdateManagementLevelInput,
): Prisma.ManagementLevelUncheckedUpdateInput {
  return {
    ...(input.name !== undefined ? { name: input.name } : {}),
    ...(input.groupId !== undefined ? { groupId: input.groupId } : {}),
  };
}

export function assertManagementLevelDeletable(
  level: ManagementLevelDeleteRecord,
): void {
  if (level._count.resources > 0) {
    throw new TRPCError({
      code: "PRECONDITION_FAILED",
      message: `Cannot delete level assigned to ${level._count.resources} resource(s)`,
    });
  }
}
