private void GenerateAndCollectMetrics(ImmutableTransaction immutableTransaction, TimeSpan?apdexT, string transactionApdexMetricName, TimeSpan totalTime, TransactionMetricStatsCollection txStats)
        {
            foreach (var segment in immutableTransaction.Segments)
            {
                GenerateSegmentMetrics(segment, txStats);
            }

            var isWebTransaction = immutableTransaction.IsWebTransaction();

            if (_configurationService.Configuration.DistributedTracingEnabled)
            {
                TimeSpan duration  = default;
                string   type      = default;
                string   account   = default;
                string   app       = default;
                string   transport = default;

                if (immutableTransaction.TracingState != null)
                {
                    duration = immutableTransaction.TracingState.TransportDuration;
                    type     = EnumNameCache <DistributedTracingParentType> .GetName(immutableTransaction.TracingState.Type);

                    account   = immutableTransaction.TracingState.AccountId;
                    app       = immutableTransaction.TracingState.AppId;
                    transport = EnumNameCache <TransportType> .GetName(immutableTransaction.TracingState.TransportType);
                }

                MetricBuilder.TryBuildDistributedTraceDurationByCaller(type, account, app, transport, isWebTransaction,
                                                                       immutableTransaction.Duration, txStats);

                if (immutableTransaction.TracingState != null)
                {
                    MetricBuilder.TryBuildDistributedTraceTransportDuration(type, account, app, transport, isWebTransaction, duration, txStats);
                }

                if (ErrorCollectionEnabled() && immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.HasError)
                {
                    MetricBuilder.TryBuildDistributedTraceErrorsByCaller(type, account, app, transport, isWebTransaction, txStats);
                }
            }

            MetricBuilder.TryBuildTransactionMetrics(isWebTransaction, immutableTransaction.ResponseTimeOrDuration, txStats);

            // Total time is the total amount of time spent, even when work is happening parallel, which means it is the sum of all exclusive times.
            // https://source.datanerd.us/agents/agent-specs/blob/master/Total-Time-Async.md
            MetricBuilder.TryBuildTotalTimeMetrics(isWebTransaction, totalTime, txStats);

            // CPU time is the total time spent actually doing work rather than waiting. Basically, it's TotalTime minus TimeSpentWaiting.
            // Our agent does not yet the ability to calculate time spent waiting, so we cannot generate this metric.
            // https://source.datanerd.us/agents/agent-specs/blob/master/Total-Time-Async.md
            //_metricBuilder.TryBuildCpuTimeRollupMetric(isWebTransaction, immutableTransaction.Duration, txStats),
            //_metricBuilder.TryBuildCpuTimeMetric(transactionMetricName, immutableTransaction.Duration, txStats)

            if (immutableTransaction.TransactionMetadata.QueueTime != null)
            {
                MetricBuilder.TryBuildQueueTimeMetric(immutableTransaction.TransactionMetadata.QueueTime.Value, txStats);
            }

            if (apdexT != null && !immutableTransaction.IgnoreApdex)
            {
                GetApdexMetrics(immutableTransaction, apdexT.Value, transactionApdexMetricName, txStats);
            }

            if (ErrorCollectionEnabled() && immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.HasError)
            {
                var isErrorExpected = immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorData.IsExpected;
                MetricBuilder.TryBuildErrorsMetrics(isWebTransaction, txStats, isErrorExpected);
            }

            var referrerCrossProcessId = immutableTransaction.TransactionMetadata.CrossApplicationReferrerProcessId;

            if (referrerCrossProcessId != null)
            {
                var catResponseTime = TimeSpan.FromSeconds(immutableTransaction.TransactionMetadata.CrossApplicationResponseTimeInSeconds);
                MetricBuilder.TryBuildClientApplicationMetric(referrerCrossProcessId, catResponseTime, catResponseTime, txStats);
            }

            using (_agentTimerService.StartNew("CollectMetrics"))
            {
                _metricAggregator.Collect(txStats);
            }
        }