package protosocket

import (
	"context"
	"testing"
)

func TestEnvelopeStructRoundTrip(t *testing.T) {
	original := Envelope{
		ProtocolVersion: ProtocolVersion,
		ID:              "msg-123",
		CorrelationID:   "corr-456",
		Type:            "request",
		Channel:         "tasks",
		Action:          "create",
		Actor:           map[string]any{"id": "user-1"},
		Auth:            map[string]any{"token": "secret"},
		Payload:         map[string]any{"title": "hello"},
		Meta:            map[string]any{"source": "client"},
		Error: &EnvelopeError{
			Code:      "SOME_ERROR",
			Message:   "An error occurred",
			Retryable: true,
			Details:   map[string]any{"retry": true},
		},
	}

	s, err := original.ToStruct()
	if err != nil {
		t.Fatalf("failed to convert Envelope to Struct: %v", err)
	}

	roundtrip, err := EnvelopeFromStruct(s)
	if err != nil {
		t.Fatalf("failed to convert Struct back to Envelope: %v", err)
	}

	if roundtrip.ProtocolVersion != original.ProtocolVersion {
		t.Errorf("ProtocolVersion mismatch: got %q, want %q", roundtrip.ProtocolVersion, original.ProtocolVersion)
	}
	if roundtrip.ID != original.ID {
		t.Errorf("ID mismatch: got %q, want %q", roundtrip.ID, original.ID)
	}
	if roundtrip.CorrelationID != original.CorrelationID {
		t.Errorf("CorrelationID mismatch: got %q, want %q", roundtrip.CorrelationID, original.CorrelationID)
	}
	if roundtrip.Type != original.Type {
		t.Errorf("Type mismatch: got %q, want %q", roundtrip.Type, original.Type)
	}
	if roundtrip.Channel != original.Channel {
		t.Errorf("Channel mismatch: got %q, want %q", roundtrip.Channel, original.Channel)
	}
	if roundtrip.Action != original.Action {
		t.Errorf("Action mismatch: got %q, want %q", roundtrip.Action, original.Action)
	}

	if roundtrip.Actor["id"] != "user-1" {
		t.Errorf("Actor mismatch: got %v", roundtrip.Actor)
	}
	if roundtrip.Auth["token"] != "secret" {
		t.Errorf("Auth mismatch: got %v", roundtrip.Auth)
	}
	if roundtrip.Payload["title"] != "hello" {
		t.Errorf("Payload mismatch: got %v", roundtrip.Payload)
	}
	if roundtrip.Meta["source"] != "client" {
		t.Errorf("Meta mismatch: got %v", roundtrip.Meta)
	}

	if roundtrip.Error == nil {
		t.Fatal("Error should not be nil")
	}
	if roundtrip.Error.Code != "SOME_ERROR" {
		t.Errorf("Error.Code mismatch: got %q, want %q", roundtrip.Error.Code, "SOME_ERROR")
	}
	if roundtrip.Error.Message != "An error occurred" {
		t.Errorf("Error.Message mismatch: got %q, want %q", roundtrip.Error.Message, "An error occurred")
	}
	if !roundtrip.Error.Retryable {
		t.Errorf("Error.Retryable mismatch: got false, want true")
	}
	if roundtrip.Error.Details["retry"] != true {
		t.Errorf("Error.Details mismatch: got %v", roundtrip.Error.Details)
	}
}

func TestDispatcherReturnsUnsupportedActionErrorEnvelope(t *testing.T) {
	dispatcher := NewDispatcher()
	ctx := context.Background()

	request := Envelope{
		ProtocolVersion: ProtocolVersion,
		ID:              "req-1",
		Type:            "request",
		Channel:         "tasks",
		Action:          "unknown-action",
	}

	response := dispatcher.Dispatch(ctx, request)

	if response.Type != "error" {
		t.Errorf("expected response type 'error', got %q", response.Type)
	}
	if response.CorrelationID != "req-1" {
		t.Errorf("expected CorrelationID 'req-1', got %q", response.CorrelationID)
	}
	if response.Error == nil {
		t.Fatal("expected non-nil Error in response")
	}
	if response.Error.Code != "UNSUPPORTED_ACTION" {
		t.Errorf("expected error code 'UNSUPPORTED_ACTION', got %q", response.Error.Code)
	}
	if response.Error.Retryable {
		t.Error("expected Retryable to be false for UNSUPPORTED_ACTION")
	}
}
