// Package telemetry provides internal OpenTelemetry provider setup.
package telemetry

import (
	"context"
	"fmt"
	"time"

	"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/sdk/log"
	"go.opentelemetry.io/otel/sdk/metric"
	"go.opentelemetry.io/otel/sdk/resource"
	"go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
)

// SetupMeterProvider creates and configures a MeterProvider with OTLP/HTTP exporter.
func SetupMeterProvider(ctx context.Context, endpoint string, res *resource.Resource, insecure bool) (*metric.MeterProvider, error) {
	// Create OTLP/HTTP metric exporter
	opts := []otlpmetrichttp.Option{
		otlpmetrichttp.WithEndpoint(endpoint),
	}
	if insecure {
		opts = append(opts, otlpmetrichttp.WithInsecure())
	}
	exporter, err := otlpmetrichttp.New(ctx, opts...)
	if err != nil {
		return nil, fmt.Errorf("failed to create metric exporter: %w", err)
	}

	// Create meter provider with periodic reader
	provider := metric.NewMeterProvider(
		metric.WithResource(res),
		metric.WithReader(metric.NewPeriodicReader(exporter,
			metric.WithInterval(10*time.Second), // Export metrics every 10 seconds
		)),
	)

	return provider, nil
}

// SetupTracerProvider creates and configures a TracerProvider with OTLP/HTTP exporter.
func SetupTracerProvider(ctx context.Context, endpoint string, res *resource.Resource, insecure bool) (*trace.TracerProvider, error) {
	// Create OTLP/HTTP trace exporter
	opts := []otlptracehttp.Option{
		otlptracehttp.WithEndpoint(endpoint),
	}
	if insecure {
		opts = append(opts, otlptracehttp.WithInsecure())
	}
	exporter, err := otlptracehttp.New(ctx, opts...)
	if err != nil {
		return nil, fmt.Errorf("failed to create trace exporter: %w", err)
	}

	// Create tracer provider with batch processor
	provider := trace.NewTracerProvider(
		trace.WithResource(res),
		trace.WithBatcher(exporter,
			trace.WithBatchTimeout(5*time.Second), // Batch traces every 5 seconds
		),
	)

	return provider, nil
}

// SetupLoggerProvider creates and configures a LoggerProvider with OTLP/HTTP exporter.
func SetupLoggerProvider(ctx context.Context, endpoint string, res *resource.Resource, insecure bool) (*log.LoggerProvider, error) {
	// Create OTLP/HTTP log exporter
	opts := []otlploghttp.Option{
		otlploghttp.WithEndpoint(endpoint),
	}
	if insecure {
		opts = append(opts, otlploghttp.WithInsecure())
	}
	exporter, err := otlploghttp.New(ctx, opts...)
	if err != nil {
		return nil, fmt.Errorf("failed to create log exporter: %w", err)
	}

	// Create logger provider with batch processor
	provider := log.NewLoggerProvider(
		log.WithResource(res),
		log.WithProcessor(log.NewBatchProcessor(exporter,
			log.WithExportInterval(5*time.Second), // Batch logs every 5 seconds
		)),
	)

	return provider, nil
}

// CreateResource creates an OpenTelemetry resource with model-specific attributes.
func CreateResource(serviceName, modelID, version, team, modelType, modelCategory string) (*resource.Resource, error) {
	return resource.New(context.Background(),
		resource.WithAttributes(
			// Standard OTel semantic conventions
			semconv.ServiceName(serviceName),
			semconv.ServiceVersion(version),
			semconv.ServiceInstanceID(modelID),
		),
		resource.WithAttributes(
			// Custom model attributes (not duplicating standard conventions)
			semconv.ServiceInstanceIDKey.String(modelID), // model.id
			semconv.Key("team.name").String(team),
			semconv.Key("model.type").String(modelType),
			semconv.Key("model.category").String(modelCategory),
		),
		resource.WithSchemaURL(semconv.SchemaURL),
	)
}
