// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace Azure.Iot.Operations.Services.AssetAndDeviceRegistry.Models;

internal static class ProtocolConverter
{
    public static Generated.AdrBaseService.GetAssetRequestPayload ToProtocol(this GetAssetRequest source)
    {
        return new Generated.AdrBaseService.GetAssetRequestPayload
        {
            AssetName = source.AssetName
        };
    }

    public static Generated.DeviceDiscoveryService.DiscoveredDevice ToProtocol(this Models.DiscoveredDevice source)
    {
        return new()
        {
            Attributes = source.Attributes,
            Endpoints = source.Endpoints?.ToProtocol(),
            ExternalDeviceId = source.ExternalDeviceId,
            Manufacturer = source.Manufacturer,
            Model = source.Model,
            OperatingSystem = source.OperatingSystem,
            OperatingSystemVersion = source.OperatingSystemVersion,
        };
    }

    public static Generated.DeviceDiscoveryService.CreateOrUpdateDiscoveredDeviceRequestSchema ToProtocol(this Models.CreateOrUpdateDiscoveredDeviceRequestSchema source)
    {
        return new()
        {
            DiscoveredDevice = source.DiscoveredDevice.ToProtocol(),
            DiscoveredDeviceName = source.DiscoveredDeviceName,
        };
    }

    public static Generated.AdrBaseService.UpdateAssetStatusRequestPayload ToProtocol(this UpdateAssetStatusRequest source)
    {
        return new Generated.AdrBaseService.UpdateAssetStatusRequestPayload
        {
            AssetStatusUpdate = new Generated.AdrBaseService.UpdateAssetStatusRequestSchema
            {
                AssetName = source.AssetName,
                AssetStatus = source.AssetStatus.ToProtocol()
            }
        };
    }

    public static Generated.AdrBaseService.CreateOrUpdateDiscoveredAssetRequestPayload ToProtocol(this CreateOrUpdateDiscoveredAssetRequest source)
    {
        return new Generated.AdrBaseService.CreateOrUpdateDiscoveredAssetRequestPayload
        {
            DiscoveredAssetRequest = new Generated.AdrBaseService.CreateOrUpdateDiscoveredAssetRequestSchema
            {
                DiscoveredAsset = source.DiscoveredAsset.ToProtocol(),
                DiscoveredAssetName = source.DiscoveredAssetName
            }
        };
    }

    internal static Generated.AdrBaseService.DiscoveredAssetEventGroup ToProtocol(this DiscoveredAssetEventGroup source)
    {
        return new Generated.AdrBaseService.DiscoveredAssetEventGroup()
        {
            DataSource = source.DataSource,
            DefaultDestinations = source.DefaultDestinations?.Select(x => x.ToProtocol()).ToList(),
            EventGroupConfiguration = source.EventGroupConfiguration,
            Events = source.Events?.Select(x => x.ToProtocol()).ToList(),
            Name = source.Name,
            TypeRef = source.TypeRef,
        };
    }

    internal static Generated.AdrBaseService.DiscoveredAsset ToProtocol(this DiscoveredAsset source)
    {
        return new Generated.AdrBaseService.DiscoveredAsset
        {
            AssetTypeRefs = source.AssetTypeRefs,
            Attributes = source.Attributes,
            Datasets = source.Datasets?.Select(x => x.ToProtocol()).ToList(),
            DefaultDatasetsConfiguration = source.DefaultDatasetsConfiguration,
            DefaultDatasetsDestinations = source.DefaultDatasetsDestinations?.Select(x => x.ToProtocol()).ToList(),
            DefaultEventsConfiguration = source.DefaultEventsConfiguration,
            DefaultEventsDestinations = source.DefaultEventsDestinations?.Select(x => x.ToProtocol()).ToList(),
            DefaultManagementGroupsConfiguration = source.DefaultManagementGroupsConfiguration,
            DefaultStreamsConfiguration = source.DefaultStreamsConfiguration,
            DefaultStreamsDestinations = source.DefaultStreamsDestinations?.Select(x => x.ToProtocol()).ToList(),
            Description = source.Description,
            DeviceRef = source.DeviceRef.ToProtocol(),
            DisplayName = source.DisplayName,
            DocumentationUri = source.DocumentationUri,
            EventGroups = source.EventGroups?.Select(x => x.ToProtocol()).ToList(),
            ExternalAssetId = source.ExternalAssetId,
            HardwareRevision = source.HardwareRevision,
            ManagementGroups = source.ManagementGroups?.Select(x => x.ToProtocol()).ToList(),
            Manufacturer = source.Manufacturer,
            ManufacturerUri = source.ManufacturerUri,
            Model = source.Model,
            ProductCode = source.ProductCode,
            SerialNumber = source.SerialNumber,
            SoftwareRevision = source.SoftwareRevision,
            Streams = source.Streams?.Select(x => x.ToProtocol()).ToList(),
        };
    }

    internal static Generated.AdrBaseService.DiscoveredAssetEvent ToProtocol(this DiscoveredAssetEvent source)
    {
        return new Generated.AdrBaseService.DiscoveredAssetEvent
        {
            Destinations = source.Destinations?.Select(x => x.ToProtocol()).ToList(),
            EventConfiguration = source.EventConfiguration,
            DataSource = source.DataSource,
            LastUpdatedOn = source.LastUpdatedOn,
            Name = source.Name,
            TypeRef = source.TypeRef,
        };
    }

    internal static Generated.AdrBaseService.DiscoveredAssetDataset ToProtocol(this DiscoveredAssetDataset source)
    {
        return new Generated.AdrBaseService.DiscoveredAssetDataset
        {
            Name = source.Name,
            DatasetConfiguration = source.DataSetConfiguration,
            LastUpdatedOn = source.LastUpdatedOn,
            Destinations = source.Destinations?.Select(x => x.ToProtocol()).ToList(),
            DataPoints = source.DataPoints?.Select(x => x.ToProtocol()).ToList(),
            DataSource = source.DataSource,
            TypeRef = source.TypeRef,
        };
    }

    internal static Generated.AdrBaseService.DiscoveredAssetDatasetDataPoint ToProtocol(this DiscoveredAssetDatasetDataPoint source)
    {
        return new Generated.AdrBaseService.DiscoveredAssetDatasetDataPoint
        {
            Name = source.Name,
            DataPointConfiguration = source.DataPointConfiguration,
            LastUpdatedOn = source.LastUpdatedOn,
            TypeRef = source.TypeRef,
            DataSource = source.DataSource
        };
    }

    internal static Generated.AdrBaseService.NotificationPreference ToProtocol(this NotificationPreference source)
    {
        switch (source)
        {
            case NotificationPreference.On:
                return Generated.AdrBaseService.NotificationPreference.On;
            case NotificationPreference.Off:
                return Generated.AdrBaseService.NotificationPreference.Off;
            default:
                throw new ArgumentException("Unknown notification preference type");
        }
    }

    internal static Generated.AdrBaseService.DiscoveredAssetStream ToProtocol(this DiscoveredAssetStream source)
    {
        return new Generated.AdrBaseService.DiscoveredAssetStream
        {
            Destinations = source.Destinations?.Select(x => x.ToProtocol()).ToList(),
            LastUpdatedOn = source.LastUpdatedOn,
            Name = source.Name,
            TypeRef = source.TypeRef,
            StreamConfiguration = source.StreamConfiguration,
        };
    }

    internal static Generated.AdrBaseService.DiscoveredAssetManagementGroup ToProtocol(this DiscoveredAssetManagementGroup source)
    {
        return new Generated.AdrBaseService.DiscoveredAssetManagementGroup
        {
            Actions = source.Actions?.Select(x => x.ToProtocol()).ToList(),
            DataSource = source.DataSource,
            DefaultTimeoutInSeconds = source.DefaultTimeoutInSeconds,
            DefaultTopic = source.DefaultTopic,
            LastUpdatedOn = source.LastUpdatedOn,
            ManagementGroupConfiguration = source.ManagementGroupConfiguration,
            Name = source.Name,
            TypeRef = source.TypeRef,
        };
    }

    internal static Generated.AdrBaseService.DiscoveredAssetManagementGroupAction ToProtocol(this DiscoveredAssetManagementGroupAction source)
    {
        return new Generated.AdrBaseService.DiscoveredAssetManagementGroupAction
        {
            Name = source.Name,
            ActionConfiguration = source.ActionConfiguration,
            ActionType = source.ActionType.ToProtocol(),
            LastUpdatedOn = source.LastUpdatedOn,
            TypeRef = source.TypeRef,
            TargetUri = source.TargetUri,
            TimeoutInSeconds = source.TimeoutInSeconds,
            Topic = source.Topic,
        };
    }

    internal static Generated.AdrBaseService.AssetManagementGroupActionType ToProtocol(this AssetManagementGroupActionType source)
    {
        switch (source)
        {
            case AssetManagementGroupActionType.Call:
                return Generated.AdrBaseService.AssetManagementGroupActionType.Call;
            case AssetManagementGroupActionType.Write:
                return Generated.AdrBaseService.AssetManagementGroupActionType.Write;
            case AssetManagementGroupActionType.Read:
                return Generated.AdrBaseService.AssetManagementGroupActionType.Read;
            default:
                throw new ArgumentException("Unknown management group action type");
        }
    }

    internal static Generated.AdrBaseService.DatasetDestination ToProtocol(this DatasetDestination source)
    {
        return new Generated.AdrBaseService.DatasetDestination
        {
            Target = source.Target.ToProtocol(),
            Configuration = source.Configuration.ToProtocol()
        };
    }

    internal static Generated.AdrBaseService.DatasetTarget ToProtocol(this DatasetTarget source)
    {
        switch (source)
        {
            case DatasetTarget.Mqtt:
                return Generated.AdrBaseService.DatasetTarget.Mqtt;
            case DatasetTarget.Storage:
                return Generated.AdrBaseService.DatasetTarget.Storage;
            case DatasetTarget.BrokerStateStore:
                return Generated.AdrBaseService.DatasetTarget.BrokerStateStore;
            default:
                throw new ArgumentException("Unknown dataset target");
        }
    }

    internal static Generated.AdrBaseService.EventStreamDestination ToProtocol(this EventStreamDestination source)
    {
        return new Generated.AdrBaseService.EventStreamDestination
        {
            Configuration = source.Configuration.ToProtocol(),
            Target = source.Target.ToProtocol(),
        };
    }

    internal static Generated.AdrBaseService.EventStreamTarget ToProtocol(this EventStreamTarget source)
    {
        switch (source)
        {
            case EventStreamTarget.Mqtt:
                return Generated.AdrBaseService.EventStreamTarget.Mqtt;
            case EventStreamTarget.Storage:
                return Generated.AdrBaseService.EventStreamTarget.Storage;
            default:
                throw new ArgumentException("Unknown event stream target type");
        }
    }

    internal static Generated.AdrBaseService.DestinationConfiguration ToProtocol(this DestinationConfiguration source)
    {
        return new Generated.AdrBaseService.DestinationConfiguration
        {
            Key = source.Key,
            Path = source.Path,
            Topic = source.Topic,
            Qos = source.Qos?.ToProtocol(),
            Retain = source.Retain?.ToProtocol(),
            Ttl = source.Ttl
        };
    }

    internal static Generated.AdrBaseService.Qos ToProtocol(this QoS source)
    {
        switch (source)
        {
            case QoS.Qos0:
                return Generated.AdrBaseService.Qos.Qos0;
            case QoS.Qos1:
                return Generated.AdrBaseService.Qos.Qos1;
            default:
                throw new ArgumentException("Unknown QoS");
        }
    }

    internal static Generated.AdrBaseService.AssetDeviceRef ToProtocol(this AssetDeviceRef source)
    {
        return new Generated.AdrBaseService.AssetDeviceRef
        {
            DeviceName = source.DeviceName,
            EndpointName = source.EndpointName
        };
    }

    internal static Generated.DeviceDiscoveryService.DiscoveredDeviceEndpoints ToProtocol(this Models.DiscoveredDeviceEndpoints source)
    {
        return new Generated.DeviceDiscoveryService.DiscoveredDeviceEndpoints
        {
            Inbound = source.Inbound?.ToDictionary(x => x.Key, x => x.Value.ToProtocol()),
            Outbound = source.Outbound?.ToProtocol(),
        };
    }

    internal static Generated.DeviceDiscoveryService.DiscoveredDeviceOutboundEndpointsSchema ToProtocol(this Models.DiscoveredDeviceOutboundEndpoints source)
    {
        return new Generated.DeviceDiscoveryService.DiscoveredDeviceOutboundEndpointsSchema
        {
            Assigned = source.Assigned.ToDictionary(x => x.Key, x => x.Value.ToProtocol())
        };
    }

    internal static Generated.DeviceDiscoveryService.DeviceOutboundEndpoint ToProtocol(this Models.DeviceOutboundEndpoint source)
    {
        return new Generated.DeviceDiscoveryService.DeviceOutboundEndpoint
        {
            Address = source.Address,
            EndpointType = source.EndpointType,
        };
    }

    internal static Generated.DeviceDiscoveryService.DiscoveredDeviceInboundEndpointSchema ToProtocol(this DiscoveredDeviceInboundEndpoint source)
    {
        return new Generated.DeviceDiscoveryService.DiscoveredDeviceInboundEndpointSchema
        {
            AdditionalConfiguration = source.AdditionalConfiguration,
            Address = source.Address,
            EndpointType = source.EndpointType,
            SupportedAuthenticationMethods = source.SupportedAuthenticationMethods,
            Version = source.Version
        };
    }

    public static Generated.AdrBaseService.DeviceStatus ToProtocol(this DeviceStatus source)
    {
        return new Generated.AdrBaseService.DeviceStatus
        {
            Config = source.Config?.ToProtocol(),
            Endpoints = source.Endpoints?.ToProtocol(),
        };
    }

    internal static Generated.AdrBaseService.ConfigStatus ToProtocol(this ConfigStatus source)
    {
        return new()
        {
            Error = source.Error?.ToProtocol(),
            LastTransitionTime = source.LastTransitionTime,
            Version = source.Version,
        };
    }

    internal static Generated.AdrBaseService.AssetStatus ToProtocol(this AssetStatus source)
    {
        return new Generated.AdrBaseService.AssetStatus
        {
            Config = source.Config?.ToProtocol(),
            Datasets = source.Datasets?.Select(x => x.ToProtocol()).ToList(),
            EventGroups = source.EventGroups?.Select(x => x.ToProtocol()).ToList(),
            ManagementGroups = source.ManagementGroups?.Select(x => x.ToProtocol()).ToList(),
            Streams = source.Streams?.Select(x => x.ToProtocol()).ToList()
        };
    }

    internal static Generated.AdrBaseService.AssetEventGroupStatusSchemaElementSchema ToProtocol(this AssetEventGroupStatus source)
    {
        return new Generated.AdrBaseService.AssetEventGroupStatusSchemaElementSchema
        {
            Events = source.Events?.Select(x => x.ToProtocol()).ToList(),
            Name = source.Name
        };
    }

    internal static Generated.AdrBaseService.AssetManagementGroupStatusSchemaElementSchema ToProtocol(this AssetManagementGroupStatus source)
    {
        return new Generated.AdrBaseService.AssetManagementGroupStatusSchemaElementSchema
        {
            Name = source.Name,
            Actions = source.Actions?.Select(x => x.ToProtocol()).ToList()
        };
    }

    internal static Generated.AdrBaseService.AssetManagementGroupActionStatusSchemaElementSchema ToProtocol(this AssetManagementGroupActionStatus source)
    {
        return new Generated.AdrBaseService.AssetManagementGroupActionStatusSchemaElementSchema
        {
            Error = source.Error?.ToProtocol(),
            Name = source.Name,
            RequestMessageSchemaReference = source.RequestMessageSchemaReference?.ToProtocol(),
            ResponseMessageSchemaReference = source.ResponseMessageSchemaReference?.ToProtocol()
        };
    }

    internal static Generated.AdrBaseService.AssetDatasetEventStreamStatus ToProtocol(this AssetDatasetEventStreamStatus source)
    {
        return new Generated.AdrBaseService.AssetDatasetEventStreamStatus
        {
            Error = source.Error?.ToProtocol(),
            Name = source.Name,
            MessageSchemaReference = source.MessageSchemaReference?.ToProtocol()
        };
    }

    internal static Generated.AdrBaseService.MessageSchemaReference ToProtocol(this MessageSchemaReference source)
    {
        return new Generated.AdrBaseService.MessageSchemaReference
        {
            SchemaName = source.SchemaName,
            SchemaRegistryNamespace = source.SchemaRegistryNamespace,
            SchemaVersion = source.SchemaVersion,
        };
    }

    internal static Generated.AdrBaseService.Retain ToProtocol(this Retain source)
    {
        switch (source)
        {
            case Retain.Never:
                return Generated.AdrBaseService.Retain.Never;
            case Retain.Keep:
                return Generated.AdrBaseService.Retain.Keep;
            default:
                throw new ArgumentException("Unknown retain value");
        }
    }

    internal static Generated.AdrBaseService.DeviceStatusEndpointSchema ToProtocol(this DeviceStatusEndpoint source)
    {
        return new Generated.AdrBaseService.DeviceStatusEndpointSchema
        {
            Inbound = new Dictionary<string, Generated.AdrBaseService.DeviceStatusInboundEndpointSchemaMapValueSchema>(
                source.Inbound?.Select(x => new KeyValuePair<string, Generated.AdrBaseService.DeviceStatusInboundEndpointSchemaMapValueSchema>(x.Key, x.Value.ToProtocol())) ??
                new Dictionary<string, Generated.AdrBaseService.DeviceStatusInboundEndpointSchemaMapValueSchema>())
        };
    }

    internal static Generated.AdrBaseService.DeviceStatusInboundEndpointSchemaMapValueSchema ToProtocol(this DeviceStatusInboundEndpointSchemaMapValue source)
    {
        return new Generated.AdrBaseService.DeviceStatusInboundEndpointSchemaMapValueSchema
        {
            Error = source.Error?.ToProtocol()
        };
    }

    internal static Generated.AdrBaseService.ConfigError ToProtocol(this ConfigError source)
    {
        return new Generated.AdrBaseService.ConfigError
        {
            Code = source.Code,
            Message = source.Message,
            Details = source.Details?.Select(x => x.ToProtocol()).ToList(),
        };
    }

    internal static Generated.AdrBaseService.DetailsSchemaElementSchema ToProtocol(this ConfigErrorDetails source)
    {
        return new Generated.AdrBaseService.DetailsSchemaElementSchema
        {
            Code = source.Code,
            Message = source.Message,
            CorrelationId = source.CorrelationId,
            Info = source.Info
        };
    }

    internal static Generated.AdrBaseService.DatasetsSchemaElementSchema ToProtocol(this DatasetsRuntimeHealthEvent source)
    {
        return new Generated.AdrBaseService.DatasetsSchemaElementSchema
        {
            DatasetName = source.DatasetName,
            RuntimeHealth = source.RuntimeHealth.ToProtocol(),
        };
    }

    internal static Generated.AdrBaseService.EventsSchemaElementSchema ToProtocol(this EventsRuntimeHealthEvent source)
    {
        return new Generated.AdrBaseService.EventsSchemaElementSchema
        {
            EventGroupName = source.EventGroupName,
            EventName = source.EventName,
            RuntimeHealth = source.RuntimeHealth.ToProtocol(),
        };
    }

    internal static Generated.AdrBaseService.ManagementActionsSchemaElementSchema ToProtocol(this ManagementActionsRuntimeHealthEvent source)
    {
        return new Generated.AdrBaseService.ManagementActionsSchemaElementSchema
        {
            ManagementActionName = source.ManagementActionName,
            ManagementGroupName = source.ManagementGroupName,
            RuntimeHealth = source.RuntimeHealth.ToProtocol(),
        };
    }

    internal static Generated.AdrBaseService.StreamsSchemaElementSchema ToProtocol(this StreamsRuntimeHealthEvent source)
    {
        return new Generated.AdrBaseService.StreamsSchemaElementSchema
        {
            StreamName = source.StreamName,
            RuntimeHealth = source.RuntimeHealth.ToProtocol(),
        };
    }

    internal static Generated.AdrBaseService.RuntimeHealth ToProtocol(this RuntimeHealth source)
    {
        return new Generated.AdrBaseService.RuntimeHealth
        {
            LastUpdateTime = source.LastUpdateTime,
            Message = source.Message,
            ReasonCode = source.ReasonCode,
            Status = (Generated.AdrBaseService.StatusSchema) ((int) source.Status),
            Version = source.Version,
        };
    }
}
