package envelope

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"strings"
)

type Protocol string

const (
	ProtocolGB32960    Protocol = "GB32960"
	ProtocolJT808      Protocol = "JT808"
	ProtocolYutongMQTT Protocol = "YUTONG_MQTT"
)

type ParseStatus string

const (
	ParseOK       ParseStatus = "OK"
	ParsePartial  ParseStatus = "PARTIAL"
	ParseBadFrame ParseStatus = "BAD_FRAME"
)

type EventKind string

const (
	EventKindRaw     EventKind = "RAW"
	EventKindFields  EventKind = "FIELDS"
	EventKindUnified EventKind = "UNIFIED"
)

const (
	FieldSpeedKMH       = "speed_kmh"
	FieldTotalMileageKM = "total_mileage_km"
	FieldLongitude      = "longitude"
	FieldLatitude       = "latitude"
	FieldSOCPercent     = "soc_percent"
)

type FrameEnvelope struct {
	EventID                string            `json:"event_id"`
	TraceID                string            `json:"trace_id"`
	EventKind              EventKind         `json:"event_kind,omitempty"`
	SourceEventID          string            `json:"source_event_id,omitempty"`
	FieldMapping           string            `json:"field_mapping,omitempty"`
	Protocol               Protocol          `json:"protocol"`
	MessageID              string            `json:"message_id"`
	Sequence               uint16            `json:"sequence"`
	VIN                    string            `json:"vin,omitempty"`
	VehicleKeyHint         string            `json:"vehicle_key,omitempty"`
	Phone                  string            `json:"phone,omitempty"`
	DeviceID               string            `json:"device_id,omitempty"`
	Plate                  string            `json:"plate,omitempty"`
	SourceEndpoint         string            `json:"source_endpoint,omitempty"`
	SourceCode             string            `json:"source_code,omitempty"`
	PlatformName           string            `json:"platform_name,omitempty"`
	SourceKind             string            `json:"source_kind,omitempty"`
	AuthenticationMode     string            `json:"authentication_mode,omitempty"`
	AuthenticationStatus   string            `json:"authentication_status,omitempty"`
	AuthenticationEnforced bool              `json:"authentication_enforced,omitempty"`
	EventTimeMS            int64             `json:"event_time_ms"`
	ReceivedAtMS           int64             `json:"received_at_ms"`
	RawHex                 string            `json:"raw_hex,omitempty"`
	RawText                string            `json:"raw_text,omitempty"`
	Parsed                 map[string]any    `json:"parsed,omitempty"`
	ParsedFields           map[string]any    `json:"parsed_fields,omitempty"`
	ParsedFieldTypes       map[string]string `json:"parsed_field_types,omitempty"`
	Fields                 map[string]any    `json:"fields,omitempty"`
	ParseStatus            ParseStatus       `json:"parse_status"`
	ParseError             string            `json:"parse_error,omitempty"`
}

func (e FrameEnvelope) VehicleKey() string {
	if key := strings.TrimSpace(e.VIN); key != "" {
		return key
	}
	if key := strings.TrimSpace(e.Phone); key != "" {
		return string(e.Protocol) + ":" + key
	}
	if key := strings.TrimSpace(e.VehicleKeyHint); key != "" {
		return key
	}
	if key := strings.TrimSpace(e.DeviceID); key != "" {
		return string(e.Protocol) + ":" + key
	}
	return string(e.Protocol) + ":unknown"
}

func (e FrameEnvelope) StableEventID() string {
	if strings.TrimSpace(e.EventID) != "" {
		return e.EventID
	}
	input := fmt.Sprintf("%s|%s|%s|%d|%d|%s",
		e.Protocol, e.MessageID, e.VehicleKey(), e.Sequence, e.EventTimeMS, e.RawHex)
	sum := sha256.Sum256([]byte(input))
	return hex.EncodeToString(sum[:16])
}

func (e FrameEnvelope) KafkaKey() []byte {
	return []byte(e.VehicleKey())
}

func (e FrameEnvelope) MarshalJSONBytes() ([]byte, error) {
	if e.EventID == "" {
		e.EventID = e.StableEventID()
	}
	if e.ParseStatus == "" {
		e.ParseStatus = ParseOK
	}
	if e.EventKind == "" {
		e.EventKind = EventKindRaw
	}
	return json.Marshal(e)
}
