package platform

import (
	"bufio"
	"context"
	"fmt"
	"net"
	"strings"
	"testing"
)

func TestRedisOnlineKeyCounterScansVehicleOnlineKeys(t *testing.T) {
	listener, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("listen fake redis: %v", err)
	}
	defer listener.Close()
	done := make(chan struct{})
	go func() {
		defer close(done)
		conn, err := listener.Accept()
		if err != nil {
			return
		}
		defer conn.Close()
		reader := bufio.NewReader(conn)
		for {
			command, err := readFakeRedisCommand(reader)
			if err != nil {
				return
			}
			switch strings.ToUpper(command[0]) {
			case "PING":
				_, _ = conn.Write([]byte("+PONG\r\n"))
			case "SELECT":
				_, _ = conn.Write([]byte("+OK\r\n"))
			case "SCAN":
				if command[1] == "0" {
					_, _ = conn.Write(fakeRedisScanReply("7", []string{"vehicle:online:GB32960:VIN001", "vehicle:online:JT808:VIN002"}))
				} else {
					_, _ = conn.Write(fakeRedisScanReply("0", []string{"vehicle:online:YUTONG_MQTT:VIN003"}))
				}
			default:
				t.Errorf("unexpected fake redis command: %#v", command)
				return
			}
		}
	}()

	counter := NewRedisOnlineKeyCounter(listener.Addr().String(), "", "", 50)
	count, err := counter.CountOnlineKeys(context.Background())
	if err != nil {
		t.Fatalf("CountOnlineKeys returned error: %v", err)
	}
	if count != 3 {
		t.Fatalf("expected 3 online keys, got %d", count)
	}
	_ = listener.Close()
	<-done
}

func fakeRedisScanReply(cursor string, keys []string) []byte {
	var builder strings.Builder
	builder.WriteString("*2\r\n")
	builder.WriteString(fmt.Sprintf("$%d\r\n%s\r\n", len(cursor), cursor))
	builder.WriteString(fmt.Sprintf("*%d\r\n", len(keys)))
	for _, key := range keys {
		builder.WriteString(fmt.Sprintf("$%d\r\n%s\r\n", len(key), key))
	}
	return []byte(builder.String())
}

func readFakeRedisCommand(reader *bufio.Reader) ([]string, error) {
	line, err := reader.ReadString('\n')
	if err != nil {
		return nil, err
	}
	var count int
	if _, err := fmt.Sscanf(strings.TrimSpace(line), "*%d", &count); err != nil {
		return nil, err
	}
	parts := make([]string, 0, count)
	for i := 0; i < count; i++ {
		if _, err := reader.ReadString('\n'); err != nil {
			return nil, err
		}
		value, err := reader.ReadString('\n')
		if err != nil {
			return nil, err
		}
		parts = append(parts, strings.TrimSuffix(strings.TrimSuffix(value, "\n"), "\r"))
	}
	return parts, nil
}
