import { type TailorAnyDBField } from "@tailor-platform/sdk";
import { createUser } from "./command/createUser.generated";
import { createRole } from "./command/createRole.generated";
import { createPermission } from "./command/createPermission.generated";
import { activateUser } from "./command/activateUser.generated";
import { deactivateUser } from "./command/deactivateUser.generated";
import { reactivateUser } from "./command/reactivateUser.generated";
import { assignPermissionToRole } from "./command/assignPermissionToRole.generated";
import { revokePermissionFromRole } from "./command/revokePermissionFromRole.generated";
import { assignRoleToUser } from "./command/assignRoleToUser.generated";
import { revokeRoleFromUser } from "./command/revokeRoleFromUser.generated";
import { updateUser } from "./command/updateUser.generated";
import { updateOwnProfile } from "./command/updateOwnProfile.generated";
import { createPermissionType, CreatePermissionTypeParams } from "./db/permission";
import { createRoleType, CreateRoleTypeParams } from "./db/role";
import { createRolePermissionType, CreateRolePermissionTypeParams } from "./db/rolePermission";
import { createUserType, CreateUserTypeParams } from "./db/user";
import { createUserRoleType, CreateUserRoleTypeParams } from "./db/userRole";
import {
  recomputeOnRolePermissionCreated,
  recomputeOnRolePermissionDeleted,
} from "./executor/recomputeOnRolePermissionChange";
import { type EmptyFields, type FieldsToInsertable } from "@tailor-platform/erp-kit/module";

export interface DefineModuleParams<
  UF extends Record<string, TailorAnyDBField>,
  RF extends Record<string, TailorAnyDBField>,
  PF extends Record<string, TailorAnyDBField>,
> {
  dbNamespace: string;
  user?: CreateUserTypeParams<UF>;
  permission?: CreatePermissionTypeParams<PF>;
  role?: CreateRoleTypeParams<RF>;
  userRole?: CreateUserRoleTypeParams;
  rolePermission?: CreateRolePermissionTypeParams;
}

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

  const rolePermissionCreated = recomputeOnRolePermissionCreated({
    namespace: params.dbNamespace,
  });
  const rolePermissionDeleted = recomputeOnRolePermissionDeleted({
    namespace: params.dbNamespace,
  });

  return {
    db: { user, permission, role, userRole, rolePermission },
    executors: { rolePermissionCreated, rolePermissionDeleted },
    commands: {
      createUser: createUser<FieldsToInsertable<UF>>(),
      createRole: createRole<FieldsToInsertable<RF>>(),
      createPermission: createPermission<FieldsToInsertable<PF>>(),
      activateUser: activateUser(),
      deactivateUser: deactivateUser(),
      reactivateUser: reactivateUser(),
      assignPermissionToRole: assignPermissionToRole(),
      revokePermissionFromRole: revokePermissionFromRole(),
      assignRoleToUser: assignRoleToUser(),
      revokeRoleFromUser: revokeRoleFromUser(),
      updateUser: updateUser<FieldsToInsertable<UF>>(),
      updateOwnProfile: updateOwnProfile<FieldsToInsertable<UF>>(),
    },
  };
};
