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


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

internal static class ModelsConverter
{
    internal static CreateOrUpdateDiscoveredAssetResponsePayload ToModel(this Generated.AdrBaseService.CreateOrUpdateDiscoveredAssetResponsePayload source)
    {
        return new()
        {
            DiscoveredAssetResponse = source.DiscoveredAssetResponse.ToModel()
        };
    }

    internal static DiscoveredAssetResponseSchema ToModel(this Generated.AdrBaseService.DiscoveredAssetResponseSchema source)
    {
        return new()
        {
            DiscoveryId = source.DiscoveryId,
            Version = source.Version,
        };
    }

    internal static DiscoveredDeviceResponseSchema ToModel(this Generated.DeviceDiscoveryService.DiscoveredDeviceResponseSchema source)
    {
        return new()
        {
            DiscoveryId = source.DiscoveryId,
            Version = source.Version,
        };
    }

    internal static CreateOrUpdateDiscoveredDeviceResponsePayload ToModel(this Generated.DeviceDiscoveryService.CreateOrUpdateDiscoveredDeviceResponsePayload source)
    {
        return new()
        {
            DiscoveredDeviceResponse = source.DiscoveredDeviceResponse.ToModel(),
        };
    }

    internal static SetNotificationPreferenceForAssetUpdatesResponsePayload ToModel(this Generated.AdrBaseService.SetNotificationPreferenceForAssetUpdatesResponsePayload source)
    {
        return new()
        {
            ResponsePayload = source.ResponsePayload
        };
    }

    internal static SetNotificationPreferenceForDeviceUpdatesResponsePayload ToModel(this Generated.AdrBaseService.SetNotificationPreferenceForDeviceUpdatesResponsePayload source)
    {
        return new()
        {
            ResponsePayload = source.ResponsePayload
        };
    }

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

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

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

    internal static Asset ToModel(this Generated.AdrBaseService.Asset source)
    {
        return new Asset
        {
            AssetTypeRefs = source.AssetTypeRefs,
            Attributes = source.Attributes,
            Datasets = source.Datasets?.Select(x => x.ToModel()).ToList(),
            DefaultDatasetsConfiguration = source.DefaultDatasetsConfiguration,
            DefaultDatasetsDestinations = source.DefaultDatasetsDestinations?.Select(x => x.ToModel()).ToList(),
            DefaultEventsConfiguration = source.DefaultEventsConfiguration,
            DefaultEventsDestinations = source.DefaultEventsDestinations?.Select(x => x.ToModel()).ToList(),
            DefaultManagementGroupsConfiguration = source.DefaultManagementGroupsConfiguration,
            DefaultStreamsConfiguration = source.DefaultStreamsConfiguration,
            DefaultStreamsDestinations = source.DefaultStreamsDestinations?.Select(x => x.ToModel()).ToList(),
            Description = source.Description,
            DeviceRef = source.DeviceRef.ToModel(),
            DiscoveredAssetRefs = source.DiscoveredAssetRefs,
            DisplayName = source.DisplayName,
            DocumentationUri = source.DocumentationUri,
            Enabled = source.Enabled,
            EventGroups = source.EventGroups?.Select(x => x.ToModel()).ToList(),
            ExternalAssetId = source.ExternalAssetId,
            HardwareRevision = source.HardwareRevision,
            LastTransitionTime = source.LastTransitionTime,
            ManagementGroups = source.ManagementGroups?.Select(x => x.ToModel()).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.ToModel()).ToList(),
            Uuid = source.Uuid,
            Version = source.Version,
        };
    }

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

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

    internal static Models.AkriServiceError ToModel(this Generated.AdrBaseService.AkriServiceError source)
    {
        return new Models.AkriServiceError
        {
            Code = source.Code.ToModel(),
            Message = source.Message,
            Timestamp = source.Timestamp,
        };
    }

    internal static Models.Code ToModel(this Generated.AdrBaseService.CodeSchema source)
    {
        switch (source)
        {
            case Generated.AdrBaseService.CodeSchema.Unauthorized:
                return Models.Code.Unauthorized;
            case Generated.AdrBaseService.CodeSchema.SerializationError:
                return Models.Code.SerializationError;
            case Generated.AdrBaseService.CodeSchema.BadRequest:
                return Models.Code.BadRequest;
            case Generated.AdrBaseService.CodeSchema.KubeError:
                return Models.Code.KubeError;
            case Generated.AdrBaseService.CodeSchema.InternalError:
                return Models.Code.InternalError;
            default:
                throw new ArgumentException("Unknown code");
        }
    }

    internal static Models.Code ToModel(this Generated.DeviceDiscoveryService.CodeSchema source)
    {
        switch (source)
        {
            case Generated.DeviceDiscoveryService.CodeSchema.Unauthorized:
                return Models.Code.Unauthorized;
            case Generated.DeviceDiscoveryService.CodeSchema.SerializationError:
                return Models.Code.SerializationError;
            case Generated.DeviceDiscoveryService.CodeSchema.BadRequest:
                return Models.Code.BadRequest;
            case Generated.DeviceDiscoveryService.CodeSchema.KubeError:
                return Models.Code.KubeError;
            case Generated.DeviceDiscoveryService.CodeSchema.InternalError:
                return Models.Code.InternalError;
            default:
                throw new ArgumentException("Unknown code");
        }
    }

    internal static Models.AkriServiceError ToModel(this Generated.DeviceDiscoveryService.AkriServiceError source)
    {
        return new Models.AkriServiceError
        {
            Code = source.Code.ToModel(),
            Message = source.Message,
            Timestamp = source.Timestamp,
        };
    }

    public static Device ToModel(this Generated.AdrBaseService.Device source)
    {
        return new Device
        {
            Attributes = source.Attributes,
            DiscoveredDeviceRef = source.DiscoveredDeviceRef,
            Enabled = source.Enabled,
            Endpoints = source.Endpoints?.ToModel(),
            ExternalDeviceId = source.ExternalDeviceId,
            LastTransitionTime = source.LastTransitionTime,
            Manufacturer = source.Manufacturer,
            Model = source.Model,
            OperatingSystem = source.OperatingSystem,
            OperatingSystemVersion = source.OperatingSystemVersion,
            Uuid = source.Uuid,
            Version = source.Version
        };
    }

    public static NotificationResponse ToModel(this SetNotificationPreferenceForDeviceUpdatesResponsePayload source)
    {
        return new NotificationResponse
        {
            ResponsePayload = source.ResponsePayload
        };
    }

    public static NotificationResponse ToModel(this SetNotificationPreferenceForAssetUpdatesResponsePayload source)
    {
        return new NotificationResponse
        {
            ResponsePayload = source.ResponsePayload
        };
    }

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

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

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

    internal static AssetManagementGroupAction ToModel(this Generated.AdrBaseService.AssetManagementGroupActionSchemaElementSchema source)
    {
        return new AssetManagementGroupAction
        {
            Name = source.Name,
            TargetUri = source.TargetUri,
            TimeoutInSeconds = source.TimeoutInSeconds,
            Topic = source.Topic,
            TypeRef = source.TypeRef,
            ActionConfiguration = source.ActionConfiguration,
            ActionType = source.ActionType.ToModel()
        };
    }

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

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

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

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

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

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

    internal static AssetDataset ToModel(this Generated.AdrBaseService.AssetDatasetSchemaElementSchema source)
    {
        return new AssetDataset
        {
            Name = source.Name,
            DataPoints = source.DataPoints?.Select(x => x.ToModel()).ToList(),
            DataSource = source.DataSource,
            TypeRef = source.TypeRef,
            Destinations = source.Destinations?.Select(x => x.ToModel()).ToList(),
            DatasetConfiguration = source.DatasetConfiguration
        };
    }

    internal static AssetDatasetDataPoint ToModel(this Generated.AdrBaseService.AssetDatasetDataPointSchemaElementSchema source)
    {
        return new AssetDatasetDataPoint
        {
            Name = source.Name,
            DataSource = source.DataSource,
            DataPointConfiguration = source.DataPointConfiguration,
            TypeRef = source.TypeRef,
        };
    }

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

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

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

    internal static Authentication ToModel(this Generated.AdrBaseService.AuthenticationSchema source)
    {
        return new Authentication
        {
            Method = source.Method.ToModel(),
            X509Credentials = source.X509credentials?.ToModel(),
            UsernamePasswordCredentials = source.UsernamePasswordCredentials?.ToModel()
        };
    }

    internal static Method ToModel(this Generated.AdrBaseService.MethodSchema source)
    {
        switch (source)
        {
            case Generated.AdrBaseService.MethodSchema.UsernamePassword:
                return Method.UsernamePassword;
            case Generated.AdrBaseService.MethodSchema.Certificate:
                return Method.Certificate;
            case Generated.AdrBaseService.MethodSchema.Anonymous:
                return Method.Anonymous;
            default:
                throw new ArgumentException("Unknown authentication method");
        }
    }

    internal static X509Credentials ToModel(this Generated.AdrBaseService.X509credentialsSchema source)
    {
        return new X509Credentials
        {
            CertificateSecretName = source.CertificateSecretName,
            IntermediateCertificatesSecretName = source.IntermediateCertificatesSecretName,
            KeySecretName = source.KeySecretName,
        };
    }

    internal static UsernamePasswordCredentials ToModel(this Generated.AdrBaseService.UsernamePasswordCredentialsSchema source)
    {
        return new UsernamePasswordCredentials
        {
            PasswordSecretName = source.PasswordSecretName,
            UsernameSecretName = source.UsernameSecretName
        };
    }

    internal static DeviceEndpoints ToModel(this Generated.AdrBaseService.DeviceEndpointsSchema source)
    {
        return new DeviceEndpoints
        {
            Inbound = new Dictionary<string, InboundEndpointSchemaMapValue>(
                source.Inbound?.Select(x => new KeyValuePair<string, InboundEndpointSchemaMapValue>(x.Key, x.Value.ToModel())) ??
                new Dictionary<string, InboundEndpointSchemaMapValue>()),
            Outbound = source.Outbound?.ToModel()
        };
    }

    internal static InboundEndpointSchemaMapValue ToModel(this Generated.AdrBaseService.InboundSchemaMapValueSchema source)
    {
        return new InboundEndpointSchemaMapValue
        {
            Address = source.Address,
            AdditionalConfiguration = source.AdditionalConfiguration,
            Version = source.Version,
            EndpointType = source.EndpointType,
            Authentication = source.Authentication?.ToModel(),
            TrustSettings = source.TrustSettings?.ToModel()
        };
    }

    internal static TrustSettings ToModel(this Generated.AdrBaseService.TrustSettingsSchema source)
    {
        return new TrustSettings
        {
            TrustList = source.TrustList
        };
    }

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

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

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

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

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

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

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

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

    internal static DeviceOutboundEndpoint ToModel(this Generated.AdrBaseService.DeviceOutboundEndpoint source)
    {
        return new DeviceOutboundEndpoint
        {
            Address = source.Address,
            EndpointType = source.EndpointType
        };
    }

    internal static OutboundSchema ToModel(this Generated.AdrBaseService.OutboundSchema source)
    {
        return new OutboundSchema
        {
            Assigned = new Dictionary<string, DeviceOutboundEndpoint>(source.Assigned.Select(x => new KeyValuePair<string, DeviceOutboundEndpoint>(x.Key, x.Value.ToModel()))),
            Unassigned = new Dictionary<string, DeviceOutboundEndpoint>(source.Unassigned?.Select(x => new KeyValuePair<string, DeviceOutboundEndpoint>(x.Key, x.Value.ToModel())) ??
                                                                        new Dictionary<string, DeviceOutboundEndpoint>())
        };
    }
}
