package services

import (
	"context"
	"encoding/base64"
	"fmt"
	"net/url"
	"os"
	"strings"
	"time"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"go.opentelemetry.io/otel/trace"
)

// Optional exporter. Credentials stay server-side and are never span attributes.
func InitAITelemetry(ctx context.Context) (func(context.Context) error, error) {
	noop := func(context.Context) error { return nil }
	if os.Getenv("AI_TELEMETRY_ENABLED") != "true" {
		return noop, nil
	}
	base := strings.TrimRight(os.Getenv("LANGFUSE_BASE_URL"), "/")
	public, secret := os.Getenv("LANGFUSE_PUBLIC_KEY"), os.Getenv("LANGFUSE_SECRET_KEY")
	u, err := url.Parse(base)
	if err != nil || u.Host == "" || u.User != nil || u.RawQuery != "" || (u.Scheme != "https" && !(u.Scheme == "http" && (u.Hostname() == "localhost" || u.Hostname() == "127.0.0.1"))) || public == "" || secret == "" {
		return noop, fmt.Errorf("konfigurasi Langfuse belum lengkap atau URL tidak valid")
	}
	exporter, err := otlptracehttp.New(ctx, otlptracehttp.WithEndpointURL(base+"/api/public/otel/v1/traces"), otlptracehttp.WithHeaders(map[string]string{
		"Authorization": "Basic " + base64.StdEncoding.EncodeToString([]byte(public+":"+secret)), "x-langfuse-ingestion-version": "4",
	}), otlptracehttp.WithTimeout(5*time.Second))
	if err != nil {
		return noop, fmt.Errorf("exporter telemetry belum tersedia")
	}
	provider := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter, sdktrace.WithMaxQueueSize(512)), sdktrace.WithResource(resource.NewSchemaless(attribute.String("service.name", "chatloop-agentic"))))
	otel.SetTracerProvider(provider)
	return provider.Shutdown, nil
}

type aiTraceScope struct {
	agentID uint
	dryRun  bool
}
type aiTraceScopeKey struct{}

func startAISpan(ctx context.Context, name, kind string) (context.Context, trace.Span) {
	scope, _ := ctx.Value(aiTraceScopeKey{}).(aiTraceScope)
	return otel.Tracer("chatloop/agentic").Start(ctx, name, trace.WithAttributes(
		attribute.String("langfuse.observation.type", kind), attribute.String("langfuse.trace.name", "chatloop.agent.turn"),
		attribute.Int64("langfuse.trace.metadata.agent_id", int64(scope.agentID)), attribute.Bool("langfuse.trace.metadata.simulator", scope.dryRun),
		attribute.String("langfuse.version", "agentic-v1"),
	))
}

func markAIError(span trace.Span, code string) {
	span.SetStatus(codes.Error, code)
	span.SetAttributes(attribute.String("error.type", code))
}
