import { type EmptyFields, type FieldsToInsertable } from "@tailor-platform/erp-kit/core";
import { type TailorAnyDBField } from "@tailor-platform/sdk";
import { activateUser } from "./command/activateUser.generated";
import { assignRoleToUser } from "./command/assignRoleToUser.generated";
import { createRole } from "./command/createRole.generated";
import { createUser } from "./command/createUser.generated";
import { deactivateRole } from "./command/deactivateRole.generated";
import { deactivateUser } from "./command/deactivateUser.generated";
import { grantPermissionToRole } from "./command/grantPermissionToRole.generated";
import { reactivateRole } from "./command/reactivateRole.generated";
import { reactivateUser } from "./command/reactivateUser.generated";
import { revokePermissionFromRole } from "./command/revokePermissionFromRole.generated";
import { revokeRoleFromUser } from "./command/revokeRoleFromUser.generated";
import { updateOwnProfile } from "./command/updateOwnProfile.generated";
import { updateRole } from "./command/updateRole.generated";
import { updateUser } from "./command/updateUser.generated";
import { createRoleType, CreateRoleTypeParams } from "./db/role";
import { createUserType, CreateUserTypeParams } from "./db/user";
import { createUserRoleType } from "./db/userRole";
import { recomputeOnRolePermissionsUpdated } from "./executor/recomputeOnRolePermissionChange";
import { listRoles } from "./query/listRoles.generated";
import { listUserRolesByRole } from "./query/listUserRolesByRole.generated";
import { listUserRolesByUser } from "./query/listUserRolesByUser.generated";
import { listUsersByRole } from "./query/listUsersByRole.generated";

export interface DefineModuleParams<
  UF extends Record<string, TailorAnyDBField>,
  RF extends Record<string, TailorAnyDBField>,
> {
  dbNamespace: string;
  user?: CreateUserTypeParams<UF>;
  role?: CreateRoleTypeParams<RF>;
}

/* @__NO_SIDE_EFFECTS__ */
export const defineModule = <
  const UF extends Record<string, TailorAnyDBField> = EmptyFields,
  const RF extends Record<string, TailorAnyDBField> = EmptyFields,
>(
  params: DefineModuleParams<UF, RF>,
) => {
  const user = createUserType(params.user ?? {});
  const role = createRoleType(params.role ?? {});
  const userRole = createUserRoleType();

  const rolePermissionsUpdated = recomputeOnRolePermissionsUpdated({
    namespace: params.dbNamespace,
  });

  return {
    db: { user, role, userRole },
    executors: { rolePermissionsUpdated },
    commands: {
      createUser: createUser<FieldsToInsertable<UF>>(),
      createRole: createRole<FieldsToInsertable<RF>>(),
      activateUser: activateUser(),
      deactivateUser: deactivateUser(),
      reactivateUser: reactivateUser(),
      grantPermissionToRole: grantPermissionToRole(),
      revokePermissionFromRole: revokePermissionFromRole(),
      assignRoleToUser: assignRoleToUser(),
      revokeRoleFromUser: revokeRoleFromUser(),
      updateUser: updateUser<FieldsToInsertable<UF>>(),
      updateOwnProfile: updateOwnProfile<FieldsToInsertable<UF>>(),
      updateRole: updateRole<FieldsToInsertable<RF>>(),
      deactivateRole: deactivateRole(),
      reactivateRole: reactivateRole(),
    },
    queries: {
      listRoles,
      listUserRolesByRole,
      listUserRolesByUser,
      listUsersByRole,
    },
  };
};
