package pipeline

import (
	"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter"
	"github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsproxy"
	"github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension"
	"github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/ecsobserver"
	"github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension"
	"github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor"
	"github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor"
	"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricsgenerationprocessor"
	"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstransformprocessor"
	"github.com/tidbcloud/metrics/internal/otel_collector/exporter/datadog"
	"github.com/tidbcloud/metrics/internal/otel_collector/processor/thanos"
	"github.com/tidbcloud/metrics/internal/otel_collector/receiver/metadb"
	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/service/defaultcomponents"
	"go.uber.org/multierr"
)

// Components register OTel components.
// Selected aws-otel-collector distribution components are enabled, plus the TiDB Cloud private components.
func Components() (component.Factories, error) {
	var errs error
	// Enable aws-otel-collector distribution components.
	factories, err := defaultcomponents.Components()
	if err != nil {
		return component.Factories{}, err
	}

	// Enable extensions.
	extensions := []component.ExtensionFactory{
		awsproxy.NewFactory(),
		ecsobserver.NewFactory(),
		healthcheckextension.NewFactory(),
		pprofextension.NewFactory(),
	}
	for _, ext := range factories.Extensions {
		extensions = append(extensions, ext)
	}
	factories.Extensions, err = component.MakeExtensionFactoryMap(extensions...)
	if err != nil {
		errs = multierr.Append(errs, err)
	}

	// nable the selected receivers.
	receivers := []component.ReceiverFactory{
		metadb.NewFactory(),
	}
	for _, rcv := range factories.Receivers {
		receivers = append(receivers, rcv)
	}
	factories.Receivers, err = component.MakeReceiverFactoryMap(receivers...)
	if err != nil {
		errs = multierr.Append(errs, err)
	}

	// Enable the selected processors.
	processors := []component.ProcessorFactory{
		thanos.NewFactory(),
		attributesprocessor.NewFactory(),
		filterprocessor.NewFactory(),
		metricstransformprocessor.NewFactory(),
		metricsgenerationprocessor.NewFactory(),
	}
	for _, pr := range factories.Processors {
		processors = append(processors, pr)
	}
	factories.Processors, err = component.MakeProcessorFactoryMap(processors...)
	if err != nil {
		errs = multierr.Append(errs, err)
	}

	// Enable the selected exporters.
	exporters := []component.ExporterFactory{
		datadog.NewFactory(),
		fileexporter.NewFactory(),
	}
	for _, exp := range factories.Exporters {
		exporters = append(exporters, exp)
	}
	factories.Exporters, err = component.MakeExporterFactoryMap(exporters...)
	if err != nil {
		errs = multierr.Append(errs, err)
	}

	return factories, errs
}
