import type { Prisma, PrismaClient } from "@capakraken/db";
import {
  CreateBlueprintSchema,
  UpdateBlueprintSchema,
  type BlueprintFieldDefinition,
} from "@capakraken/shared";
import { TRPCError } from "@trpc/server";
import { z } from "zod";

type BlueprintIdentifierDb = Pick<PrismaClient, "blueprint">;

type BlueprintGlobalFieldDefinition = BlueprintFieldDefinition & {
  blueprintId: string;
  blueprintName: string;
};

type BlueprintFieldDefinitionSource = {
  id: string;
  name: string;
  fieldDefs: unknown;
};

type CreateBlueprintInput = z.infer<typeof CreateBlueprintSchema>;
type UpdateBlueprintInput = z.infer<typeof UpdateBlueprintSchema>;

export async function findBlueprintByIdentifier<TBlueprint>(
  db: BlueprintIdentifierDb,
  identifier: string,
  extraArgs: Record<string, unknown>,
): Promise<TBlueprint> {
  const normalizedIdentifier = identifier.trim();

  let blueprint = await db.blueprint.findUnique({
    where: { id: normalizedIdentifier },
    ...extraArgs,
  }) as TBlueprint | null;

  if (!blueprint) {
    blueprint = await db.blueprint.findFirst({
      where: { name: { equals: normalizedIdentifier, mode: "insensitive" } },
      ...extraArgs,
    }) as TBlueprint | null;
  }

  if (!blueprint) {
    blueprint = await db.blueprint.findFirst({
      where: { name: { contains: normalizedIdentifier, mode: "insensitive" } },
      ...extraArgs,
    }) as TBlueprint | null;
  }

  if (!blueprint) {
    throw new TRPCError({
      code: "NOT_FOUND",
      message: `Blueprint not found: ${normalizedIdentifier}`,
    });
  }

  return blueprint;
}

export function buildBlueprintCreateData(
  input: CreateBlueprintInput,
): Prisma.BlueprintUncheckedCreateInput {
  return {
    name: input.name,
    target: input.target,
    description: input.description ?? null,
    fieldDefs: input.fieldDefs as unknown as Prisma.InputJsonValue,
    defaults: input.defaults as unknown as Prisma.InputJsonValue,
    validationRules: input.validationRules as unknown as Prisma.InputJsonValue,
  };
}

export function buildBlueprintUpdateData(
  input: UpdateBlueprintInput,
): Prisma.BlueprintUncheckedUpdateInput {
  return {
    ...(input.name !== undefined ? { name: input.name } : {}),
    ...(input.description !== undefined ? { description: input.description } : {}),
    ...(input.fieldDefs !== undefined
      ? { fieldDefs: input.fieldDefs as unknown as Prisma.InputJsonValue }
      : {}),
    ...(input.defaults !== undefined
      ? { defaults: input.defaults as unknown as Prisma.InputJsonValue }
      : {}),
    ...(input.validationRules !== undefined
      ? { validationRules: input.validationRules as unknown as Prisma.InputJsonValue }
      : {}),
  };
}

export function buildBlueprintRolePresetsUpdateData(
  rolePresets: unknown[],
): Prisma.BlueprintUncheckedUpdateInput {
  return {
    rolePresets: rolePresets as unknown as Prisma.InputJsonValue,
  };
}

export function expandGlobalBlueprintFieldDefs(
  blueprints: BlueprintFieldDefinitionSource[],
): BlueprintGlobalFieldDefinition[] {
  return blueprints.flatMap((blueprint) =>
    (blueprint.fieldDefs as BlueprintFieldDefinition[]).map((fieldDef) => ({
      ...fieldDef,
      blueprintId: blueprint.id,
      blueprintName: blueprint.name,
    })),
  );
}
