package ocpp

import (
	"bytes"
	"context"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func TestAcceptKey(t *testing.T) {
	// RFC 6455 §1.3 worked example.
	if got := acceptKey("dGhlIHNhbXBsZSBub25jZQ=="); got != "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" {
		t.Fatalf("acceptKey = %q, want s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", got)
	}
}

// echoServer upgrades and echoes every message back, exercising the framing +
// masking round trip in both directions across a range of payload sizes.
func TestFramingRoundTrip(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		conn, err := Upgrade(w, r)
		if err != nil {
			t.Errorf("upgrade: %v", err)
			return
		}
		for {
			msg, err := conn.ReadMessage()
			if err != nil {
				return
			}
			if err := conn.WriteMessage(msg); err != nil {
				return
			}
		}
	}))
	defer srv.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	conn, err := Dial(ctx, wsURL(srv.URL, "/"), []string{"ocpp1.6"}, nil)
	if err != nil {
		t.Fatalf("dial: %v", err)
	}
	defer conn.Close()

	// Small (<126), medium (2-byte length), large (8-byte length) — all masked
	// client→server, unmasked on the way back.
	for _, size := range []int{5, 200, 70000} {
		want := bytes.Repeat([]byte("x"), size)
		if err := conn.WriteMessage(want); err != nil {
			t.Fatalf("write size %d: %v", size, err)
		}
		got, err := conn.ReadMessage()
		if err != nil {
			t.Fatalf("read size %d: %v", size, err)
		}
		if !bytes.Equal(got, want) {
			t.Fatalf("size %d: echoed %d bytes, want %d", size, len(got), len(want))
		}
	}
}

func TestUpgradeRejectsNonWebSocket(t *testing.T) {
	rec := httptest.NewRecorder()
	req := httptest.NewRequest(http.MethodGet, "/ocpp/CP1", nil)
	if _, err := Upgrade(rec, req); err == nil {
		t.Fatal("expected error upgrading a plain GET")
	}
}

func TestDialRejectsBadScheme(t *testing.T) {
	if _, err := Dial(context.Background(), "ftp://example/x", nil, nil); err == nil ||
		!strings.Contains(err.Error(), "unsupported scheme") {
		t.Fatalf("want unsupported scheme error, got %v", err)
	}
}
