import { createResolver, t } from "@tailor-platform/sdk";
import { createContext } from "@tailor-platform/erp-kit/app";
import { getDB } from "@/generated/kysely-tailordb";
import { umModules, auditModules } from "@/modules";

export default createResolver({
  name: "createRole",
  operation: "mutation",
  input: {
    name: t.string().description("Role name"),
    description: t.string({ optional: true }).description("Role description"),
  },
  body: async (context) => {
    const db = getDB("main-db");
    const result = await db.transaction().execute(async (trx) => {
      const cmdResult = await umModules.commands.createRole(
        trx,
        {
          name: context.input.name,
          description: context.input.description ?? undefined,
        },
        createContext(context),
      );
      if (!cmdResult.ok) {
        switch (cmdResult.error.code) {
          case "USER_MANAGEMENT_DUPLICATE_ROLE_NAME":
            throw new Error(`A role with name "${context.input.name}" already exists`);
          case "USER_MANAGEMENT_MISSING_REQUIRED_FIELD":
            throw new Error("Role name is required");
          case "INSUFFICIENT_PERMISSION":
            throw cmdResult.error;
        }
      }

      // Auto-assign permissions that every role needs
      const autoAssignKeys = ["audit:logAuditEvent", "user-management:updateOwnProfile"];
      const autoAssignPerms = await trx
        .selectFrom("Permission")
        .select("id")
        .where("key", "in", autoAssignKeys)
        .execute();

      for (const perm of autoAssignPerms) {
        await umModules.commands.assignPermissionToRole(
          trx,
          {
            roleId: cmdResult.value.role.id,
            permissionId: perm.id,
          },
          createContext(context),
        );
      }

      return {
        id: cmdResult.value.role.id,
        name: cmdResult.value.role.name,
        description: cmdResult.value.role.description ?? "",
      };
    });

    await db
      .transaction()
      .execute(async (trx) => {
        await auditModules.commands.logAuditEvent(
          trx,
          {
            eventId: crypto.randomUUID(),
            actorType: "USER",
            actorId: context.user.id,
            entityType: "Role",
            entityId: result.id,
            operationType: "CREATE",
            changes: [
              { fieldName: "name", newValue: result.name },
              { fieldName: "description", newValue: result.description },
            ],
          },
          createContext(context),
        );
      })
      .catch(() => undefined);

    return result;
  },
  output: t
    .object({
      id: t.string().description("Role ID"),
      name: t.string().description("Role name"),
      description: t.string().description("Role description"),
    })
    .description("Created role"),
});
