/// <summary>
 ///     Set single website property
 /// </summary>
 /// <param name="websiteId">The Website Id</param>
 /// <param name="name">The property name</param>
 /// <param name="value">The property value.  If set to null and the property exists, it will be removed.</param>
 /// <param name="mode">How to set the property.
 /// If you are unsure, use CreateOrUpdate (the default).  As this checks to see if the property is set first, this option is slower.
 /// If you know that the property is already set and you want to change the value, use Update.
 /// If you know that the property is already set and you want to delete the value, use Delete (value must also be set to null).
 /// If you know that the property is NOT already set and you want to set the value, use Create.
 /// </param>
 /// <param name="cancellationToken">The cancellation token</param>
 /// <returns></returns>
 public Task SetWebsiteCustomPropertyAsync(
     int websiteId,
     string name,
     string value,
     SetPropertyMode mode = SetPropertyMode.Automatic,
     CancellationToken cancellationToken = default)
 =>
 SetWebsiteOrWebsiteGroupPropertyAsync <Website>(websiteId, name, value, mode, cancellationToken);
 /// <summary>
 ///     Set single deviceGroup property
 /// </summary>
 /// <param name="deviceGroupId">The DeviceGroup Id</param>
 /// <param name="name">The property name</param>
 /// <param name="value">The property value.  If set to null and the property exists, it will be removed.</param>
 /// <param name="mode">How to set the property.
 /// If you are unsure, use CreateOrUpdate (the default).  As this checks to see if the property is set first, this option is slower.
 /// If you know that the property is already set and you want to change the value, use Update.
 /// If you know that the property is already set and you want to delete the value, use Delete (value must also be set to null).
 /// If you know that the property is NOT already set and you want to set the value, use Create.
 /// </param>
 /// <param name="cancellationToken">The cancellation token</param>
 /// <returns></returns>
 public Task SetDeviceGroupCustomPropertyAsync(
     int deviceGroupId,
     string name,
     string value,
     SetPropertyMode mode = SetPropertyMode.Automatic,
     CancellationToken cancellationToken = default)
 =>
 SetCustomPropertyAsync(
     deviceGroupId,
     name,
     value,
     mode,
     $"device/groups",
     cancellationToken);
        private async Task SetWebsiteOrWebsiteGroupPropertyAsync <T>(
            int id,
            string name,
            string value,
            SetPropertyMode mode,
            CancellationToken cancellationToken) where T : IdentifiedItem, IHasEndpoint, IHasCustomProperties, new()
        {
            // Input checking
            switch (typeof(T).Name)
            {
            case nameof(WebsiteGroup):
            case nameof(Website):
                // OK
                break;

            default:
                throw new InvalidOperationException($"Only to be used for {nameof(Website)} and {nameof(WebsiteGroup)}.");
            }
            switch (mode)
            {
            case SetPropertyMode.Create:
            case SetPropertyMode.Update:
                if (value == null)
                {
                    throw new InvalidOperationException("Value cannot be null if the mode is create or update.");
                }
                break;

            case SetPropertyMode.Delete:
                if (value != null)
                {
                    throw new ArgumentException("If mode is delete, value must be set to null", nameof(value));
                }
                break;
            }

            // NB it is not yet possible to do the following:
            //return SetCustomPropertyAsync(
            //		  websiteId,
            //		  name,
            //		  value,
            //		  mode,
            //		  "website/websites",
            //		  cancellationToken);

            var websiteOrGroup = await GetAsync <T>(id, cancellationToken : cancellationToken)
                                 .ConfigureAwait(false);

            var existingCustomProperty = websiteOrGroup.CustomProperties.SingleOrDefault(cp => cp.Name == name);

            if (existingCustomProperty != null)
            {
                switch (value)
                {
                case null:
                    websiteOrGroup.CustomProperties.Remove(existingCustomProperty);
                    break;

                default:
                    existingCustomProperty.Value = value;
                    break;
                }
            }
            else
            {
                switch (mode)
                {
                case SetPropertyMode.Delete:
                    throw new LogicMonitorApiException("Can't delete a custom property that is not there.");
                }

                switch (value)
                {
                case null:
                    break;

                default:
                    websiteOrGroup.CustomProperties.Add(new Property
                    {
                        Name  = name,
                        Value = value
                    });
                    break;
                }
            }
            await PutAsync <T>(websiteOrGroup, cancellationToken).ConfigureAwait(false);
        }