package telemetry

import (
	"strings"

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

type LocationProjection struct {
	Latitude     float64
	Longitude    float64
	SpeedKMH     *float64
	SOCPercent   *float64
	AltitudeM    *float64
	DirectionDeg *float64
	AlarmFlag    *int64
	StatusFlag   *int64
}

type locationFieldMapping struct {
	Latitude     []string
	Longitude    []string
	SpeedKMH     []string
	SOCPercent   []string
	AltitudeM    []string
	DirectionDeg []string
	AlarmFlag    []string
	StatusFlag   []string
}

// HasRealtimeFields separates protocol telemetry from headers, identity
// annotations, and transport metadata before realtime/stat projections.
func HasRealtimeFields(protocol envelope.Protocol, fields map[string]any) bool {
	switch protocol {
	case envelope.ProtocolGB32960:
		for field := range fields {
			if !strings.HasPrefix(field, "gb32960.") {
				continue
			}
			if strings.HasPrefix(field, "gb32960.header.") ||
				strings.HasPrefix(field, "gb32960.platform.") ||
				strings.HasPrefix(field, "gb32960.identity.") ||
				strings.HasPrefix(field, "gb32960.device_time.") {
				continue
			}
			return true
		}
		return false
	case envelope.ProtocolJT808:
		return hasPrefix(fields, "jt808.location.")
	case envelope.ProtocolYutongMQTT:
		return hasPrefix(fields, "yutong_mqtt.data.") ||
			hasPrefix(fields, "yutong_mqtt.root.data.")
	default:
		return false
	}
}

// LocationProjectionForProtocol is the single protocol-field contract used by
// storage projections. It intentionally ignores bare standardized field names.
func LocationProjectionForProtocol(protocol envelope.Protocol, fields map[string]any) (LocationProjection, bool) {
	mapping := locationMapping(protocol)
	latitude, hasLatitude := firstNumber(fields, mapping.Latitude)
	longitude, hasLongitude := firstNumber(fields, mapping.Longitude)
	if !hasLatitude || !hasLongitude {
		return LocationProjection{}, false
	}
	return LocationProjection{
		Latitude:     latitude,
		Longitude:    longitude,
		SpeedKMH:     numberPointer(fields, mapping.SpeedKMH),
		SOCPercent:   numberPointer(fields, mapping.SOCPercent),
		AltitudeM:    numberPointer(fields, mapping.AltitudeM),
		DirectionDeg: numberPointer(fields, mapping.DirectionDeg),
		AlarmFlag:    integerPointer(fields, mapping.AlarmFlag),
		StatusFlag:   integerPointer(fields, mapping.StatusFlag),
	}, true
}

func locationMapping(protocol envelope.Protocol) locationFieldMapping {
	switch protocol {
	case envelope.ProtocolGB32960:
		return locationFieldMapping{
			Latitude:   []string{"gb32960.position.latitude"},
			Longitude:  []string{"gb32960.position.longitude"},
			SpeedKMH:   []string{"gb32960.vehicle.speed_kmh"},
			SOCPercent: []string{"gb32960.vehicle.soc_percent"},
		}
	case envelope.ProtocolJT808:
		return locationFieldMapping{
			Latitude:     []string{"jt808.location.latitude"},
			Longitude:    []string{"jt808.location.longitude"},
			SpeedKMH:     []string{"jt808.location.speed_kmh"},
			AltitudeM:    []string{"jt808.location.altitude_m"},
			DirectionDeg: []string{"jt808.location.direction_deg"},
			AlarmFlag:    []string{"jt808.location.alarm_flag"},
			StatusFlag:   []string{"jt808.location.status_flag"},
		}
	case envelope.ProtocolYutongMQTT:
		return locationFieldMapping{
			Latitude: []string{
				"yutong_mqtt.data.latitude",
				"yutong_mqtt.root.data.latitude",
			},
			Longitude: []string{
				"yutong_mqtt.data.longitude",
				"yutong_mqtt.root.data.longitude",
			},
			SpeedKMH: []string{
				"yutong_mqtt.data.meter_speed",
				"yutong_mqtt.root.data.meter_speed",
				"yutong_mqtt.data.speed_kmh",
				"yutong_mqtt.root.data.speed_kmh",
				"yutong_mqtt.data.speed",
				"yutong_mqtt.root.data.speed",
			},
			SOCPercent: []string{
				"yutong_mqtt.data.battery_capacity_soc",
				"yutong_mqtt.root.data.battery_capacity_soc",
				"yutong_mqtt.data.soc_percent",
				"yutong_mqtt.root.data.soc_percent",
			},
			DirectionDeg: []string{
				"yutong_mqtt.data.gpsdirection",
				"yutong_mqtt.root.data.gpsdirection",
				"yutong_mqtt.data.direction_deg",
				"yutong_mqtt.root.data.direction_deg",
				"yutong_mqtt.data.direction",
				"yutong_mqtt.root.data.direction",
			},
		}
	default:
		return locationFieldMapping{}
	}
}

func firstNumber(fields map[string]any, keys []string) (float64, bool) {
	for _, key := range keys {
		if value, ok := Number(fields, key); ok {
			return value, true
		}
	}
	return 0, false
}

func numberPointer(fields map[string]any, keys []string) *float64 {
	value, ok := firstNumber(fields, keys)
	if !ok {
		return nil
	}
	return &value
}

func integerPointer(fields map[string]any, keys []string) *int64 {
	value, ok := firstNumber(fields, keys)
	if !ok {
		return nil
	}
	integer := int64(value)
	return &integer
}

func hasPrefix(fields map[string]any, prefix string) bool {
	for field := range fields {
		if strings.HasPrefix(field, prefix) {
			return true
		}
	}
	return false
}
