package tests

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

	"github.com/jfraeys/fetch_ml/internal/api"
)

func TestProtocolSerialization(t *testing.T) {
	// Test success packet
	successPacket := api.NewSuccessPacket("Operation completed successfully")
	data, err := successPacket.Serialize()
	if err != nil {
		t.Fatalf("Failed to serialize success packet: %v", err)
	}

	// Verify packet type
	if len(data) < 1 || data[0] != api.PacketTypeSuccess {
		t.Errorf("Expected packet type %d, got %d", api.PacketTypeSuccess, data[0])
	}

	// Verify timestamp is present (9 bytes minimum: 1 type + 8 timestamp)
	if len(data) < 9 {
		t.Errorf("Expected at least 9 bytes, got %d", len(data))
	}

	// Test error packet
	errorPacket := api.NewErrorPacket(api.ErrorCodeAuthenticationFailed, "Auth failed", "Invalid API key")
	data, err = errorPacket.Serialize()
	if err != nil {
		t.Fatalf("Failed to serialize error packet: %v", err)
	}

	if len(data) < 1 || data[0] != api.PacketTypeError {
		t.Errorf("Expected packet type %d, got %d", api.PacketTypeError, data[0])
	}

	// Test progress packet
	progressPacket := api.NewProgressPacket(api.ProgressTypePercentage, 75, 100, "Processing...")
	data, err = progressPacket.Serialize()
	if err != nil {
		t.Fatalf("Failed to serialize progress packet: %v", err)
	}

	if len(data) < 1 || data[0] != api.PacketTypeProgress {
		t.Errorf("Expected packet type %d, got %d", api.PacketTypeProgress, data[0])
	}

	// Test status packet
	statusPacket := api.NewStatusPacket(`{"workers":1,"queued":0}`)
	data, err = statusPacket.Serialize()
	if err != nil {
		t.Fatalf("Failed to serialize status packet: %v", err)
	}

	if len(data) < 1 || data[0] != api.PacketTypeStatus {
		t.Errorf("Expected packet type %d, got %d", api.PacketTypeStatus, data[0])
	}
}

func TestErrorMessageMapping(t *testing.T) {
	tests := map[byte]string{
		api.ErrorCodeUnknownError:         "Unknown error occurred",
		api.ErrorCodeAuthenticationFailed: "Authentication failed",
		api.ErrorCodeJobNotFound:          "Job not found",
		api.ErrorCodeServerOverloaded:     "Server is overloaded",
	}

	for code, expected := range tests {
		actual := api.GetErrorMessage(code)
		if actual != expected {
			t.Errorf("Expected error message '%s' for code %d, got '%s'", expected, code, actual)
		}
	}
}

func TestLogLevelMapping(t *testing.T) {
	tests := map[byte]string{
		api.LogLevelDebug: "DEBUG",
		api.LogLevelInfo:  "INFO",
		api.LogLevelWarn:  "WARN",
		api.LogLevelError: "ERROR",
	}

	for level, expected := range tests {
		actual := api.GetLogLevelName(level)
		if actual != expected {
			t.Errorf("Expected log level '%s' for level %d, got '%s'", expected, level, actual)
		}
	}
}

func TestTimestampConsistency(t *testing.T) {
	before := time.Now().Unix()

	packet := api.NewSuccessPacket("Test message")
	data, err := packet.Serialize()
	if err != nil {
		t.Fatalf("Failed to serialize: %v", err)
	}

	after := time.Now().Unix()

	// Extract timestamp (bytes 1-8, big-endian)
	if len(data) < 9 {
		t.Fatalf("Packet too short: %d bytes", len(data))
	}

	timestamp := binary.BigEndian.Uint64(data[1:9])

	if timestamp < uint64(before) || timestamp > uint64(after) {
		t.Errorf("Timestamp %d not in expected range [%d, %d]", timestamp, before, after)
	}
}
