/* 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.Host.Generated.Common;

namespace Azure.Iot.Operations.Services.EdgeRegistry.Host.Generated
{
    [System.CodeDom.Compiler.GeneratedCode("Azure.Iot.Operations.ProtocolCompilerLib", "1.0.0.0")]
    public static partial class EdgeRegistryThingDescriptionExtensions
    {
        public abstract partial class Service : IAsyncDisposable
        {
            private ApplicationContext applicationContext;
            private IMqttPubSubClient mqttClient;
            private readonly GetThingDescriptionVersionActionExecutor getThingDescriptionVersionActionExecutor;
            private readonly CreateThingDescriptionVersionActionExecutor createThingDescriptionVersionActionExecutor;
            private readonly ListThingDescriptionVersionsActionExecutor listThingDescriptionVersionsActionExecutor;
            private readonly DeleteThingDescriptionVersionActionExecutor deleteThingDescriptionVersionActionExecutor;

            /// <summary>
            /// Construct a new instance of this service.
            /// </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 service's lifetime. Note that
            /// additional topic tokens can be specified per event message.
            /// </param>
            public Service(ApplicationContext applicationContext, IMqttPubSubClient mqttClient, Dictionary<string, string>? topicTokenMap = null)
            {
                this.applicationContext = applicationContext;
                this.mqttClient = mqttClient;

                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.");
                }

                this.getThingDescriptionVersionActionExecutor = new GetThingDescriptionVersionActionExecutor(applicationContext, mqttClient) { OnCommandReceived = GetThingDescriptionVersionInt };
                this.createThingDescriptionVersionActionExecutor = new CreateThingDescriptionVersionActionExecutor(applicationContext, mqttClient) { OnCommandReceived = CreateThingDescriptionVersionInt };
                this.listThingDescriptionVersionsActionExecutor = new ListThingDescriptionVersionsActionExecutor(applicationContext, mqttClient) { OnCommandReceived = ListThingDescriptionVersionsInt };
                this.deleteThingDescriptionVersionActionExecutor = new DeleteThingDescriptionVersionActionExecutor(applicationContext, mqttClient) { OnCommandReceived = DeleteThingDescriptionVersionInt };

                if (topicTokenMap != null)
                {
                    foreach (string topicTokenKey in topicTokenMap.Keys)
                    {
                        this.getThingDescriptionVersionActionExecutor.TopicTokenMap.TryAdd("ex:" + topicTokenKey, topicTokenMap[topicTokenKey]);
                        this.createThingDescriptionVersionActionExecutor.TopicTokenMap.TryAdd("ex:" + topicTokenKey, topicTokenMap[topicTokenKey]);
                        this.listThingDescriptionVersionsActionExecutor.TopicTokenMap.TryAdd("ex:" + topicTokenKey, topicTokenMap[topicTokenKey]);
                        this.deleteThingDescriptionVersionActionExecutor.TopicTokenMap.TryAdd("ex:" + topicTokenKey, topicTokenMap[topicTokenKey]);
                    }
                }

                this.getThingDescriptionVersionActionExecutor.TopicTokenMap.TryAdd("executorId", clientId);
                this.createThingDescriptionVersionActionExecutor.TopicTokenMap.TryAdd("executorId", clientId);
                this.listThingDescriptionVersionsActionExecutor.TopicTokenMap.TryAdd("executorId", clientId);
                this.deleteThingDescriptionVersionActionExecutor.TopicTokenMap.TryAdd("executorId", clientId);
            }

            public GetThingDescriptionVersionActionExecutor GetThingDescriptionVersionActionExecutor { get => this.getThingDescriptionVersionActionExecutor; }

            public CreateThingDescriptionVersionActionExecutor CreateThingDescriptionVersionActionExecutor { get => this.createThingDescriptionVersionActionExecutor; }

            public ListThingDescriptionVersionsActionExecutor ListThingDescriptionVersionsActionExecutor { get => this.listThingDescriptionVersionsActionExecutor; }

            public DeleteThingDescriptionVersionActionExecutor DeleteThingDescriptionVersionActionExecutor { get => this.deleteThingDescriptionVersionActionExecutor; }

            public abstract Task<ExtendedResponse<GetThingDescriptionVersionOutputArguments>> GetThingDescriptionVersionAsync(GetThingDescriptionVersionInputArguments request, CommandRequestMetadata requestMetadata, CancellationToken cancellationToken);

            public abstract Task<ExtendedResponse<CreateThingDescriptionVersionOutputArguments>> CreateThingDescriptionVersionAsync(CreateThingDescriptionVersionInputArguments request, CommandRequestMetadata requestMetadata, CancellationToken cancellationToken);

            public abstract Task<ExtendedResponse<ListThingDescriptionVersionsOutputArguments>> ListThingDescriptionVersionsAsync(ListThingDescriptionVersionsInputArguments request, CommandRequestMetadata requestMetadata, CancellationToken cancellationToken);

            public abstract Task<ExtendedResponse<EmptyJson>> DeleteThingDescriptionVersionAsync(DeleteThingDescriptionVersionInputArguments request, CommandRequestMetadata requestMetadata, CancellationToken cancellationToken);

            /// <summary>
            /// Begin accepting command invocations for all command executors.
            /// </summary>
            /// <param name="preferredDispatchConcurrency">The dispatch concurrency count for the command response cache to use.</param>
            /// <param name="cancellationToken">Cancellation token.</param>
            public async Task StartAsync(int? preferredDispatchConcurrency = null, 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 starting service.");
                }

                await Task.WhenAll(
                    this.getThingDescriptionVersionActionExecutor.StartAsync(preferredDispatchConcurrency, cancellationToken),
                    this.createThingDescriptionVersionActionExecutor.StartAsync(preferredDispatchConcurrency, cancellationToken),
                    this.listThingDescriptionVersionsActionExecutor.StartAsync(preferredDispatchConcurrency, cancellationToken),
                    this.deleteThingDescriptionVersionActionExecutor.StartAsync(preferredDispatchConcurrency, cancellationToken)).ConfigureAwait(false);
            }

            public async Task StopAsync(CancellationToken cancellationToken = default)
            {
                await Task.WhenAll(
                    this.getThingDescriptionVersionActionExecutor.StopAsync(cancellationToken),
                    this.createThingDescriptionVersionActionExecutor.StopAsync(cancellationToken),
                    this.listThingDescriptionVersionsActionExecutor.StopAsync(cancellationToken),
                    this.deleteThingDescriptionVersionActionExecutor.StopAsync(cancellationToken)).ConfigureAwait(false);
            }

            private async Task<ExtendedResponse<GetThingDescriptionVersionResponseSchema>> GetThingDescriptionVersionInt(ExtendedRequest<GetThingDescriptionVersionInputArguments> req, CancellationToken cancellationToken)
            {
                try
                {
                    ExtendedResponse<GetThingDescriptionVersionOutputArguments> extended = await this.GetThingDescriptionVersionAsync(req.Request!, req.RequestMetadata!, cancellationToken);

                    return new ExtendedResponse<GetThingDescriptionVersionResponseSchema>
                    {
                        Response = new GetThingDescriptionVersionResponseSchema
                        {
                            Output = extended.Response,
                        },
                        ResponseMetadata = extended.ResponseMetadata,
                    };
                }
                catch (ThingDescriptionExtensionErrorException intEx)
                {
                    ExtendedResponse<GetThingDescriptionVersionResponseSchema> extendedResponse = ExtendedResponse<GetThingDescriptionVersionResponseSchema>.CreateFromResponse(new GetThingDescriptionVersionResponseSchema { Error = intEx.ThingDescriptionExtensionError });
                    return extendedResponse;
                }
            }

            private async Task<ExtendedResponse<CreateThingDescriptionVersionResponseSchema>> CreateThingDescriptionVersionInt(ExtendedRequest<CreateThingDescriptionVersionInputArguments> req, CancellationToken cancellationToken)
            {
                try
                {
                    ExtendedResponse<CreateThingDescriptionVersionOutputArguments> extended = await this.CreateThingDescriptionVersionAsync(req.Request!, req.RequestMetadata!, cancellationToken);

                    return new ExtendedResponse<CreateThingDescriptionVersionResponseSchema>
                    {
                        Response = new CreateThingDescriptionVersionResponseSchema
                        {
                            Output = extended.Response,
                        },
                        ResponseMetadata = extended.ResponseMetadata,
                    };
                }
                catch (ThingDescriptionExtensionErrorException intEx)
                {
                    ExtendedResponse<CreateThingDescriptionVersionResponseSchema> extendedResponse = ExtendedResponse<CreateThingDescriptionVersionResponseSchema>.CreateFromResponse(new CreateThingDescriptionVersionResponseSchema { Error = intEx.ThingDescriptionExtensionError });
                    return extendedResponse;
                }
            }

            private async Task<ExtendedResponse<ListThingDescriptionVersionsResponseSchema>> ListThingDescriptionVersionsInt(ExtendedRequest<ListThingDescriptionVersionsInputArguments> req, CancellationToken cancellationToken)
            {
                try
                {
                    ExtendedResponse<ListThingDescriptionVersionsOutputArguments> extended = await this.ListThingDescriptionVersionsAsync(req.Request!, req.RequestMetadata!, cancellationToken);

                    return new ExtendedResponse<ListThingDescriptionVersionsResponseSchema>
                    {
                        Response = new ListThingDescriptionVersionsResponseSchema
                        {
                            Output = extended.Response,
                        },
                        ResponseMetadata = extended.ResponseMetadata,
                    };
                }
                catch (ThingDescriptionExtensionErrorException intEx)
                {
                    ExtendedResponse<ListThingDescriptionVersionsResponseSchema> extendedResponse = ExtendedResponse<ListThingDescriptionVersionsResponseSchema>.CreateFromResponse(new ListThingDescriptionVersionsResponseSchema { Error = intEx.ThingDescriptionExtensionError });
                    return extendedResponse;
                }
            }

            private async Task<ExtendedResponse<DeleteThingDescriptionVersionResponseSchema>> DeleteThingDescriptionVersionInt(ExtendedRequest<DeleteThingDescriptionVersionInputArguments> req, CancellationToken cancellationToken)
            {
                try
                {
                    ExtendedResponse<EmptyJson> extended = await this.DeleteThingDescriptionVersionAsync(req.Request!, req.RequestMetadata!, cancellationToken);

                    return new ExtendedResponse<DeleteThingDescriptionVersionResponseSchema>
                    {
                        Response = new DeleteThingDescriptionVersionResponseSchema
                        {
                        },
                        ResponseMetadata = extended.ResponseMetadata,
                    };
                }
                catch (ThingDescriptionExtensionErrorException intEx)
                {
                    ExtendedResponse<DeleteThingDescriptionVersionResponseSchema> extendedResponse = ExtendedResponse<DeleteThingDescriptionVersionResponseSchema>.CreateFromResponse(new DeleteThingDescriptionVersionResponseSchema { Error = intEx.ThingDescriptionExtensionError });
                    return extendedResponse;
                }
            }

            public async ValueTask DisposeAsync()
            {
                await this.getThingDescriptionVersionActionExecutor.DisposeAsync().ConfigureAwait(false);
                await this.createThingDescriptionVersionActionExecutor.DisposeAsync().ConfigureAwait(false);
                await this.listThingDescriptionVersionsActionExecutor.DisposeAsync().ConfigureAwait(false);
                await this.deleteThingDescriptionVersionActionExecutor.DisposeAsync().ConfigureAwait(false);
            }

            public async ValueTask DisposeAsync(bool disposing, CancellationToken cancellationToken = default)
            {
                await this.getThingDescriptionVersionActionExecutor.DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);
                await this.createThingDescriptionVersionActionExecutor.DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);
                await this.listThingDescriptionVersionsActionExecutor.DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);
                await this.deleteThingDescriptionVersionActionExecutor.DisposeAsync(disposing, cancellationToken).ConfigureAwait(false);
            }
        }
    }
}
