package gateway

import (
	"context"
	"errors"
	"strings"
	"time"

	"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
	"lingniu-vehicle-ingest/go/vehicle-gateway/internal/metrics"
)

var gatewayIdentityDurationBucketsMS = []float64{1, 5, 10, 25, 50, 100, 250, 500, 1000, 5000}
var gatewayFieldsCountBuckets = []float64{1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}

func identityErrorStatus(err error) string {
	if errors.Is(err, context.DeadlineExceeded) {
		return "timeout"
	}
	return "error"
}

func recordGatewayIdentityDuration(registry *metrics.Registry, protocol envelope.Protocol, status string, elapsed time.Duration) {
	if registry == nil {
		return
	}
	elapsedMS := float64(elapsed.Nanoseconds()) / float64(time.Millisecond)
	labels := metrics.Labels{
		"protocol": string(protocol),
		"status":   status,
	}
	registry.SetGauge("vehicle_gateway_identity_duration_ms", labels, elapsedMS)
	registry.ObserveHistogram("vehicle_gateway_identity_duration_ms_histogram", labels, gatewayIdentityDurationBucketsMS, elapsedMS)
}

func recordGatewayIdentityCacheStatus(registry *metrics.Registry, protocol envelope.Protocol, env envelope.FrameEnvelope) {
	if registry == nil {
		return
	}
	status := identityCacheStatus(env)
	if status == "" {
		return
	}
	registry.IncCounter("vehicle_gateway_identity_cache_total", metrics.Labels{
		"protocol":     string(protocol),
		"cache_status": status,
	})
}

func identityCacheStatus(env envelope.FrameEnvelope) string {
	identity, ok := env.Parsed["identity"].(map[string]any)
	if !ok {
		return ""
	}
	status, ok := identity["cache_status"].(string)
	if !ok {
		return ""
	}
	return strings.TrimSpace(status)
}

func annotateIdentityError(env *envelope.FrameEnvelope, err error) {
	if env == nil || err == nil {
		return
	}
	if env.Parsed == nil {
		env.Parsed = map[string]any{}
	}
	identity, _ := env.Parsed["identity"].(map[string]any)
	if identity == nil {
		identity = map[string]any{}
	}
	if _, ok := identity["resolved"]; !ok {
		identity["resolved"] = strings.TrimSpace(env.VIN) != ""
	}
	identity["error"] = err.Error()
	env.Parsed["identity"] = identity
}

func recordGatewayFieldsMetric(registry *metrics.Registry, protocol envelope.Protocol, status string) {
	if registry == nil {
		return
	}
	registry.IncCounter("vehicle_gateway_fields_total", metrics.Labels{
		"protocol": string(protocol),
		"status":   status,
	})
}

func recordGatewayFieldsCount(registry *metrics.Registry, protocol envelope.Protocol, status string, fieldCount int) {
	if registry == nil {
		return
	}
	if fieldCount < 0 {
		fieldCount = 0
	}
	labels := metrics.Labels{
		"protocol": string(protocol),
		"status":   status,
	}
	value := float64(fieldCount)
	registry.SetGauge("vehicle_gateway_fields_count", labels, value)
	registry.ObserveHistogram("vehicle_gateway_fields_count_histogram", labels, gatewayFieldsCountBuckets, value)
}
