/********* START OF METHOD LOGIC *********/
/**
  * load old {{capitalize ENTITY_NAMING.entityWords}} and check if it exists
  */
const old = await this.{{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}}Model.findById(id);
if (!old) throw new exceptions.ItemNotFoundException("{{capitalize ENTITY_NAMING.entityWords}} not found");
if (old.is_deleted)
  throw new exceptions.UnauthorizedException("{{capitalize ENTITY_NAMING.entityWords}} is deleted");

/**
  * detect changes
  */
const updates = new ObjectUpdatedProperties(old.toObject() as typeof data, data, true);
scenario.set({updates: updates.asArray});

const updateObject: Jsm.Core.Utils.Entity.General.IItemUpdate = {
  updated_by_system: !authData?.current?.user,
  updated_by: getUserSnapshot(authData?.current?.user),
  date: new Date(),
  action: "updated",
  updates: updates.asArray,
};

/**
  * Auto-fill system data
  */
{{#if ENTITY_META.is_creatable}}
data.app = authData?.current?.app?._id
  ? authData?.current?.app?._id
  : opt?.bypassAuthorization ||
      (authData?.current?.service?.name &&
        !authData?.current?.service?.is_external)
    ? data.app
    : undefined;
{{/if}}


/**
  * Check if the user can update the {{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}}
  */
{{#if ENTITY_META.is_creatable}}
if (
  authData?.current?.app?._id &&
  authData?.current?.app?._id !== data.app
)
  throw new exceptions.UnauthorizedException(
    "You are not allowed to update this {{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}} on this app"
  );
{{/if}}

const userGranted = await userCan.updateObject(this.ENTITY, old, data, authData);
if (!userGranted){
  throw new exceptions.UnauthorizedException(
    "You are not allowed to update this {{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}}"
  );
}

/**
  * Update data {{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}}
  */
const docObject: Partial<EntityAlias> = {
  ...data,
};

{{#if HAS_TRACKING_ID_PROPERTY}}
/**
  * Create tracking ID
  */
if(!old.tracking_id){
  docObject.tracking_id = await createTrackingId(
    this.ENTITY,
    ITEM_SHORTCUTS,
    this.{{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}}Model as any
    );
}
{{/if}}

{{#if ENTITY_META.has_slug}}
{{#ifEntityHasNameOrTitle .}}
/**
  * Create slug
  */
  if(!old.slug && !data.slug) {
    docObject.slug = await this._generateSlug(
      {{#if ENTITY_META.has_name}}data.name{{else}}data.title{{/if}} || {{#if ENTITY_META.has_name}}old.name{{else}}old.title{{/if}},
      null,
    ) as any;
  } else if (old.slug && !data.slug) {
    docObject.slug = old.slug;
  } else {
    docObject.slug = await this._generateSlug(
      {{#if ENTITY_META.has_name}}data.name{{else}}data.title{{/if}} || {{#if ENTITY_META.has_name}}old.name{{else}}old.title{{/if}},
      data.slug,
    ) as any;
  }
{{/ifEntityHasNameOrTitle}}
{{/if}}

{{#if ENTITY_META.has_snapshots}}
/**
  * Create snapshots
  */
docObject.snapshots = await this._generateSnapshotsObject(
  docObject,
  null,
  authData
);
{{/if}}

{{#if HAS_SEARCH_META_PROPERTY}}
/**
  * Create search meta
  */
docObject.search_meta = this._generateSearchMeta(docObject, null);
{{/if}}


/**
  * Update the {{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}} on DB
  */
const doc = await this.{{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}}Model.findByIdAndUpdate(
  id, 
  { $set: { ...docObject }, $push: { updates: updateObject } }, 
  { new: true }
);

if (!doc)
  throw new exceptions.InternalServerError(
    "Failed to update the {{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}}"
  );


/**
  * Return the updated {{SUB_MODULE_ENTITY_CAMELCASED_SINGULAR}}
  */
result = {
  data: mapDocumentToExposed(doc),
};
/********* END OF METHOD LOGIC *********/