package feichibridge

import (
	"encoding/binary"
	"fmt"
	"strings"
	"testing"
	"time"

	"lingniu-vehicle-ingest/go/vehicle-gateway/internal/protocol/gb32960"
)

func TestDataFrameMapsFeichiFields(t *testing.T) {
	at := time.Date(2026, 7, 17, 14, 5, 6, 0, shanghai)
	record := Record{
		"2000": "2026-07-17 14:05:06",
		"2201": "42.3", "2202": "12345.6", "2203": "D 0 0",
		"2208": "35", "2209": "0", "2213": "纯电",
		"2214": "工作", "2301": "未充电状态", "3201": "启动状态",
		"2613": "550.2", "2614": "-20.5", "2617": "2200", "7615": "78",
		"2501": "有效定位", "2502": "113.2644", "2503": "23.1291",
		"2601": "1", "2602": "8", "2603": "3.955",
		"2604": "1", "2605": "26", "2606": "3.821",
		"2607": "1", "2608": "3", "2609": "48",
		"2610": "1", "2611": "9", "2612": "37",
		"2003": "1:3.900_3.901_3.902",
		"2103": "1:35_36_37",
	}
	frame, err := (Encoder{}).DataFrame(CommandRealtime, "LTEST32960VIN0001", at, record)
	if err != nil {
		t.Fatal(err)
	}
	env, err := gb32960.ParseFrame(frame, at.UnixMilli(), "test")
	if err != nil {
		t.Fatal(err)
	}
	if env.MessageID != "0x02" || env.VIN != "LTEST32960VIN0001" {
		t.Fatalf("unexpected envelope: %#v", env)
	}
	if got := env.Fields["speed_kmh"]; got != 42.3 {
		t.Fatalf("speed = %#v", got)
	}
	if got := env.Fields["total_mileage_km"]; got != 12345.6 {
		t.Fatalf("mileage = %#v", got)
	}
	if got := env.Fields["soc_percent"]; got != 78 {
		t.Fatalf("soc = %#v", got)
	}
	if got := env.Fields["longitude"]; got != 113.2644 {
		t.Fatalf("longitude = %#v", got)
	}
}

func TestDataFrameSplitsMoreThan255CellVoltages(t *testing.T) {
	values := make([]string, 288)
	for index := range values {
		values[index] = fmt.Sprintf("%.3f", 3.5+float64(index)/1000)
	}
	frame, err := (Encoder{}).DataFrame(CommandReissue, "LTEST32960VIN0002", time.Now(), Record{
		"2003": "1:" + strings.Join(values, "_"),
		"2613": "530",
		"2614": "10",
	})
	if err != nil {
		t.Fatal(err)
	}
	body := frame[24 : len(frame)-1]
	if got := strings.Count(string(body), string([]byte{0x08})); got < 2 {
		t.Fatalf("expected at least two voltage units, got %d", got)
	}
	if binary.BigEndian.Uint16(frame[22:24]) != uint16(len(body)) {
		t.Fatal("body length mismatch")
	}
	if _, err := gb32960.ParseFrame(frame, time.Now().UnixMilli(), "test"); err != nil {
		t.Fatal(err)
	}
}

func TestLoginFrameLayout(t *testing.T) {
	frame, err := LoginFrame("FEICHIBRIDGE00001", "bridge", "secret", 7, time.Date(2026, 7, 17, 1, 2, 3, 0, shanghai))
	if err != nil {
		t.Fatal(err)
	}
	if frame[2] != CommandLogin || frame[3] != 0xFE {
		t.Fatalf("unexpected login header: %x", frame[:4])
	}
	if got := binary.BigEndian.Uint16(frame[30:32]); got != 7 {
		t.Fatalf("serial = %d", got)
	}
	if got, want := frame[len(frame)-1], bcc(frame[2:len(frame)-1]); got != want {
		t.Fatalf("BCC = %x, want %x", got, want)
	}
}
