/* Code generated by Azure.Iot.Operations.ProtocolCompilerLib v1.0.0.0; DO NOT EDIT. */

#nullable enable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Azure.Iot.Operations.Protocol.Models;
using Azure.Iot.Operations.Protocol;
using Azure.Iot.Operations.Protocol.RPC;
using Azure.Iot.Operations.Protocol.Telemetry;
using Azure.Iot.Operations.Services.EdgeRegistry.Generated.Common;

namespace Azure.Iot.Operations.Services.EdgeRegistry.Generated
{
    [System.CodeDom.Compiler.GeneratedCode("Azure.Iot.Operations.ProtocolCompilerLib", "1.0.0.0")]
    public static partial class EdgeRegistryThingDescriptionExtensions
    {
        public abstract partial class Client : IAsyncDisposable
        {
            private ApplicationContext applicationContext;
            private IMqttPubSubClient mqttClient;
            private readonly GetThingDescriptionVersionActionInvoker getThingDescriptionVersionActionInvoker;
            private readonly CreateThingDescriptionVersionActionInvoker createThingDescriptionVersionActionInvoker;
            private readonly ListThingDescriptionVersionsActionInvoker listThingDescriptionVersionsActionInvoker;
            private readonly DeleteThingDescriptionVersionActionInvoker deleteThingDescriptionVersionActionInvoker;

            /// <summary>
            /// Construct a new instance of this client.
            /// </summary>
            /// <param name="applicationContext">The shared context for your application.</param>
            /// <param name="mqttClient">The MQTT client to use.</param>
            /// <param name="topicTokenMap">
            /// The topic token replacement map to use for all operations by default. Generally, this will include the token values
            /// for topic tokens that should be the same for the duration of this client's lifetime.
            /// </param>
            public Client(ApplicationContext applicationContext, IMqttPubSubClient mqttClient, Dictionary<string, string>? topicTokenMap = null)
            {
                this.applicationContext = applicationContext;
                this.mqttClient = mqttClient;

                this.getThingDescriptionVersionActionInvoker = new GetThingDescriptionVersionActionInvoker(applicationContext, mqttClient);
                this.createThingDescriptionVersionActionInvoker = new CreateThingDescriptionVersionActionInvoker(applicationContext, mqttClient);
                this.listThingDescriptionVersionsActionInvoker = new ListThingDescriptionVersionsActionInvoker(applicationContext, mqttClient);
                this.deleteThingDescriptionVersionActionInvoker = new DeleteThingDescriptionVersionActionInvoker(applicationContext, mqttClient);

                if (topicTokenMap != null)
                {
                    foreach (string topicTokenKey in topicTokenMap.Keys)
                    {
                        this.getThingDescriptionVersionActionInvoker.TopicTokenMap.TryAdd("ex:" + topicTokenKey, topicTokenMap[topicTokenKey]);
                        this.createThingDescriptionVersionActionInvoker.TopicTokenMap.TryAdd("ex:" + topicTokenKey, topicTokenMap[topicTokenKey]);
                        this.listThingDescriptionVersionsActionInvoker.TopicTokenMap.TryAdd("ex:" + topicTokenKey, topicTokenMap[topicTokenKey]);
                        this.deleteThingDescriptionVersionActionInvoker.TopicTokenMap.TryAdd("ex:" + topicTokenKey, topicTokenMap[topicTokenKey]);
                    }
                }
            }

            public GetThingDescriptionVersionActionInvoker GetThingDescriptionVersionActionInvoker { get => this.getThingDescriptionVersionActionInvoker; }

            public CreateThingDescriptionVersionActionInvoker CreateThingDescriptionVersionActionInvoker { get => this.createThingDescriptionVersionActionInvoker; }

            public ListThingDescriptionVersionsActionInvoker ListThingDescriptionVersionsActionInvoker { get => this.listThingDescriptionVersionsActionInvoker; }

            public DeleteThingDescriptionVersionActionInvoker DeleteThingDescriptionVersionActionInvoker { get => this.deleteThingDescriptionVersionActionInvoker; }

            /// <summary>
            /// Invoke a command.
            /// </summary>
            /// <param name="request">The data for this command request.</param>
            /// <param name="requestMetadata">The metadata for this command request.</param>
            /// <param name="additionalTopicTokenMap">
            /// The topic token replacement map to use in addition to the topic tokens specified in the constructor. If this map
            /// contains any keys that the topic tokens specified in the constructor also has, then values specified in this map will take precedence.
            /// </param>
            /// <param name="commandTimeout">How long the command will be available on the broker for an executor to receive.</param>
            /// <param name="cancellationToken">Cancellation token.</param>
            /// <returns>The command response.</returns>
            public RpcCallAsync<GetThingDescriptionVersionOutputArguments> GetThingDescriptionVersionAsync(GetThingDescriptionVersionInputArguments request, CommandRequestMetadata? requestMetadata = null, Dictionary<string, string>? additionalTopicTokenMap = null, TimeSpan? commandTimeout = default, CancellationToken cancellationToken = default)
            {
                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException("No MQTT client Id configured. Must connect to MQTT broker before invoking command.");
                }

                CommandRequestMetadata metadata = requestMetadata ?? new CommandRequestMetadata();
                additionalTopicTokenMap ??= new();

                Dictionary<string, string> prefixedAdditionalTopicTokenMap = new();
                foreach (string key in additionalTopicTokenMap.Keys)
                {
                    prefixedAdditionalTopicTokenMap["ex:" + key] = additionalTopicTokenMap[key];
                }

                prefixedAdditionalTopicTokenMap["invokerClientId"] = clientId;

                return new RpcCallAsync<GetThingDescriptionVersionOutputArguments>(this.GetThingDescriptionVersionInt(request, metadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken), metadata.CorrelationId);
            }

            /// <summary>
            /// Invoke a command.
            /// </summary>
            /// <param name="request">The data for this command request.</param>
            /// <param name="requestMetadata">The metadata for this command request.</param>
            /// <param name="additionalTopicTokenMap">
            /// The topic token replacement map to use in addition to the topic tokens specified in the constructor. If this map
            /// contains any keys that the topic tokens specified in the constructor also has, then values specified in this map will take precedence.
            /// </param>
            /// <param name="commandTimeout">How long the command will be available on the broker for an executor to receive.</param>
            /// <param name="cancellationToken">Cancellation token.</param>
            /// <returns>The command response.</returns>
            public RpcCallAsync<CreateThingDescriptionVersionOutputArguments> CreateThingDescriptionVersionAsync(CreateThingDescriptionVersionInputArguments request, CommandRequestMetadata? requestMetadata = null, Dictionary<string, string>? additionalTopicTokenMap = null, TimeSpan? commandTimeout = default, CancellationToken cancellationToken = default)
            {
                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException("No MQTT client Id configured. Must connect to MQTT broker before invoking command.");
                }

                CommandRequestMetadata metadata = requestMetadata ?? new CommandRequestMetadata();
                additionalTopicTokenMap ??= new();

                Dictionary<string, string> prefixedAdditionalTopicTokenMap = new();
                foreach (string key in additionalTopicTokenMap.Keys)
                {
                    prefixedAdditionalTopicTokenMap["ex:" + key] = additionalTopicTokenMap[key];
                }

                prefixedAdditionalTopicTokenMap["invokerClientId"] = clientId;

                return new RpcCallAsync<CreateThingDescriptionVersionOutputArguments>(this.CreateThingDescriptionVersionInt(request, metadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken), metadata.CorrelationId);
            }

            /// <summary>
            /// Invoke a command.
            /// </summary>
            /// <param name="request">The data for this command request.</param>
            /// <param name="requestMetadata">The metadata for this command request.</param>
            /// <param name="additionalTopicTokenMap">
            /// The topic token replacement map to use in addition to the topic tokens specified in the constructor. If this map
            /// contains any keys that the topic tokens specified in the constructor also has, then values specified in this map will take precedence.
            /// </param>
            /// <param name="commandTimeout">How long the command will be available on the broker for an executor to receive.</param>
            /// <param name="cancellationToken">Cancellation token.</param>
            /// <returns>The command response.</returns>
            public RpcCallAsync<ListThingDescriptionVersionsOutputArguments> ListThingDescriptionVersionsAsync(ListThingDescriptionVersionsInputArguments request, CommandRequestMetadata? requestMetadata = null, Dictionary<string, string>? additionalTopicTokenMap = null, TimeSpan? commandTimeout = default, CancellationToken cancellationToken = default)
            {
                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException("No MQTT client Id configured. Must connect to MQTT broker before invoking command.");
                }

                CommandRequestMetadata metadata = requestMetadata ?? new CommandRequestMetadata();
                additionalTopicTokenMap ??= new();

                Dictionary<string, string> prefixedAdditionalTopicTokenMap = new();
                foreach (string key in additionalTopicTokenMap.Keys)
                {
                    prefixedAdditionalTopicTokenMap["ex:" + key] = additionalTopicTokenMap[key];
                }

                prefixedAdditionalTopicTokenMap["invokerClientId"] = clientId;

                return new RpcCallAsync<ListThingDescriptionVersionsOutputArguments>(this.ListThingDescriptionVersionsInt(request, metadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken), metadata.CorrelationId);
            }

            /// <summary>
            /// Invoke a command.
            /// </summary>
            /// <param name="request">The data for this command request.</param>
            /// <param name="requestMetadata">The metadata for this command request.</param>
            /// <param name="additionalTopicTokenMap">
            /// The topic token replacement map to use in addition to the topic tokens specified in the constructor. If this map
            /// contains any keys that the topic tokens specified in the constructor also has, then values specified in this map will take precedence.
            /// </param>
            /// <param name="commandTimeout">How long the command will be available on the broker for an executor to receive.</param>
            /// <param name="cancellationToken">Cancellation token.</param>
            /// <returns>The command response.</returns>
            public RpcCallAsync<EmptyJson> DeleteThingDescriptionVersionAsync(DeleteThingDescriptionVersionInputArguments request, CommandRequestMetadata? requestMetadata = null, Dictionary<string, string>? additionalTopicTokenMap = null, TimeSpan? commandTimeout = default, CancellationToken cancellationToken = default)
            {
                string? clientId = this.mqttClient.ClientId;
                if (string.IsNullOrEmpty(clientId))
                {
                    throw new InvalidOperationException("No MQTT client Id configured. Must connect to MQTT broker before invoking command.");
                }

                CommandRequestMetadata metadata = requestMetadata ?? new CommandRequestMetadata();
                additionalTopicTokenMap ??= new();

                Dictionary<string, string> prefixedAdditionalTopicTokenMap = new();
                foreach (string key in additionalTopicTokenMap.Keys)
                {
                    prefixedAdditionalTopicTokenMap["ex:" + key] = additionalTopicTokenMap[key];
                }

                prefixedAdditionalTopicTokenMap["invokerClientId"] = clientId;

                return new RpcCallAsync<EmptyJson>(this.DeleteThingDescriptionVersionInt(request, metadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken), metadata.CorrelationId);
            }

            /// <summary>
            /// Stop accepting telemetry for all telemetry receivers and make all command invokers unsubscribe from command topics.
            /// </summary>
            /// <param name="cancellationToken">Cancellation token.</param>
            public async Task StopAsync(CancellationToken cancellationToken = default)
            {
                await Task.WhenAll(
                    this.getThingDescriptionVersionActionInvoker.StopAsync(cancellationToken),
                    this.createThingDescriptionVersionActionInvoker.StopAsync(cancellationToken),
                    this.listThingDescriptionVersionsActionInvoker.StopAsync(cancellationToken),
                    this.deleteThingDescriptionVersionActionInvoker.StopAsync(cancellationToken)).ConfigureAwait(false);
            }

            private async Task<ExtendedResponse<GetThingDescriptionVersionOutputArguments>> GetThingDescriptionVersionInt(GetThingDescriptionVersionInputArguments request, CommandRequestMetadata? requestMetadata, Dictionary<string, string>? prefixedAdditionalTopicTokenMap, TimeSpan? commandTimeout, CancellationToken cancellationToken)
            {
                ExtendedResponse<GetThingDescriptionVersionResponseSchema> extended = await this.getThingDescriptionVersionActionInvoker.InvokeCommandAsync(request, requestMetadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken);

                if (extended.Response.Error != null)
                {
                    ThingDescriptionExtensionErrorException thingDescriptionExtensionErrorException = new ThingDescriptionExtensionErrorException(extended.Response.Error);
                    throw thingDescriptionExtensionErrorException;
                }
                else
                {
                    return new ExtendedResponse<GetThingDescriptionVersionOutputArguments>
                    {
                        Response = extended.Response.Output!,
                        ResponseMetadata = extended.ResponseMetadata,
                    };
                }
            }

            private async Task<ExtendedResponse<CreateThingDescriptionVersionOutputArguments>> CreateThingDescriptionVersionInt(CreateThingDescriptionVersionInputArguments request, CommandRequestMetadata? requestMetadata, Dictionary<string, string>? prefixedAdditionalTopicTokenMap, TimeSpan? commandTimeout, CancellationToken cancellationToken)
            {
                ExtendedResponse<CreateThingDescriptionVersionResponseSchema> extended = await this.createThingDescriptionVersionActionInvoker.InvokeCommandAsync(request, requestMetadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken);

                if (extended.Response.Error != null)
                {
                    ThingDescriptionExtensionErrorException thingDescriptionExtensionErrorException = new ThingDescriptionExtensionErrorException(extended.Response.Error);
                    throw thingDescriptionExtensionErrorException;
                }
                else
                {
                    return new ExtendedResponse<CreateThingDescriptionVersionOutputArguments>
                    {
                        Response = extended.Response.Output!,
                        ResponseMetadata = extended.ResponseMetadata,
                    };
                }
            }

            private async Task<ExtendedResponse<ListThingDescriptionVersionsOutputArguments>> ListThingDescriptionVersionsInt(ListThingDescriptionVersionsInputArguments request, CommandRequestMetadata? requestMetadata, Dictionary<string, string>? prefixedAdditionalTopicTokenMap, TimeSpan? commandTimeout, CancellationToken cancellationToken)
            {
                ExtendedResponse<ListThingDescriptionVersionsResponseSchema> extended = await this.listThingDescriptionVersionsActionInvoker.InvokeCommandAsync(request, requestMetadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken);

                if (extended.Response.Error != null)
                {
                    ThingDescriptionExtensionErrorException thingDescriptionExtensionErrorException = new ThingDescriptionExtensionErrorException(extended.Response.Error);
                    throw thingDescriptionExtensionErrorException;
                }
                else
                {
                    return new ExtendedResponse<ListThingDescriptionVersionsOutputArguments>
                    {
                        Response = extended.Response.Output!,
                        ResponseMetadata = extended.ResponseMetadata,
                    };
                }
            }

            private async Task<ExtendedResponse<EmptyJson>> DeleteThingDescriptionVersionInt(DeleteThingDescriptionVersionInputArguments request, CommandRequestMetadata? requestMetadata, Dictionary<string, string>? prefixedAdditionalTopicTokenMap, TimeSpan? commandTimeout, CancellationToken cancellationToken)
            {
                ExtendedResponse<DeleteThingDescriptionVersionResponseSchema> extended = await this.deleteThingDescriptionVersionActionInvoker.InvokeCommandAsync(request, requestMetadata, prefixedAdditionalTopicTokenMap, commandTimeout, cancellationToken);

                if (extended.Response.Error != null)
                {
                    ThingDescriptionExtensionErrorException thingDescriptionExtensionErrorException = new ThingDescriptionExtensionErrorException(extended.Response.Error);
                    throw thingDescriptionExtensionErrorException;
                }
                else
                {
                    return new ExtendedResponse<EmptyJson>
                    {
                        Response = new EmptyJson
                        {
                        },
                        ResponseMetadata = extended.ResponseMetadata,
                    };
                }
            }

            public async ValueTask DisposeAsync()
            {
                await this.getThingDescriptionVersionActionInvoker.DisposeAsync().ConfigureAwait(false);
                await this.createThingDescriptionVersionActionInvoker.DisposeAsync().ConfigureAwait(false);
                await this.listThingDescriptionVersionsActionInvoker.DisposeAsync().ConfigureAwait(false);
                await this.deleteThingDescriptionVersionActionInvoker.DisposeAsync().ConfigureAwait(false);
            }

            public async ValueTask DisposeAsync(bool disposing, CancellationToken cancellationToken = default)
            {
                await this.getThingDescriptionVersionActionInvoker.DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);
                await this.createThingDescriptionVersionActionInvoker.DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);
                await this.listThingDescriptionVersionsActionInvoker.DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);
                await this.deleteThingDescriptionVersionActionInvoker.DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);
            }
        }
    }
}
