package websocket

import (
	"context"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/grpc/kafka_grpc"
	kafka "github.com/fiskerinc/cloud-services/pkg/kafka/mock"
	"github.com/fiskerinc/cloud-services/pkg/testhelper"

	"github.com/gobwas/ws"
	"github.com/gobwas/ws/wsutil"
)

func TestSessionTRex(t *testing.T) {
	ws, _ := net.Pipe()
	s := &SessionTRex{
		Session: &Session{
			Websocket: ws,
		},
	}

	if fmt.Sprintf("%T", s) != "*websocket.SessionTRex" {
		t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRex", "*websocket.SessionTRex", fmt.Sprintf("%T", s))
	}
}

func TestNewTRexSession(t *testing.T) {
	createNewSession := func(w http.ResponseWriter, r *http.Request) {
		s, err := NewTRexSession(w, r, "1F15K3R45N1234567", "1.2.3.4", "12345678912346789123456789")
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "TestNewSessionTRex", nil, err)
		}
		defer s.Close()

		if fmt.Sprintf("%T", s) != "*websocket.SessionTRex" {
			t.Errorf(testhelper.TestErrorTemplate, "TestNewSessionTRex", "*websocket.SessionTRex", fmt.Sprintf("%T", s))
		}
	}

	server := httptest.NewServer(http.HandlerFunc(createNewSession))
	defer server.Close()

	conn := createMockWebsocketClient(server.URL, "")
	defer conn.Close()
}

func TestSessionTRexAuthenticate(t *testing.T) {
	userAgent := "Fisker Ocean T.Rex 1.2.3.4 abc123"

	createNewSession := func(w http.ResponseWriter, r *http.Request) {
		s, err := NewSecureSession(w, r)
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexAuthenticate", nil, err)
		}
		defer s.Close()

		err = s.Authenticate()
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexAuthenticate", nil, err)
		}
	}

	server := httptest.NewServer(http.HandlerFunc(createNewSession))
	defer server.Close()

	conn := createMockWebsocketClient(server.URL, userAgent)
	defer conn.Close()

	am := common.TRexSessionMessage{
		Handler: "verify",
		Data: common.TRexSessionData{
			VIN: "1HD1CGP134K410769",
		},
	}

	msg, err := json.Marshal(am)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexAuthenticate", nil, err)
	}

	wsutil.WriteClientMessage(conn, ws.OpText, msg)
}

func TestSessionTRexListen(t *testing.T) {
	userAgent := "Fisker Ocean T.Rex 1.2.3.4 abc123"
	payload := "hello fisker!"

	createNewSession := func(w http.ResponseWriter, r *http.Request) {
		s, err := NewSecureSession(w, r)
		if err != nil {
			t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexListen", nil, err)
		}
		defer s.Close()

		ctx := context.Background()
		err = s.Listen(ctx, kafka.GetKafkaMock(nil))
		if err.Error() != "EOF" {
			t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexListen", nil, err)
		}
	}

	server := httptest.NewServer(http.HandlerFunc(createNewSession))
	defer server.Close()

	conn := createMockWebsocketClient(server.URL, userAgent)
	defer conn.Close()

	err := wsutil.WriteClientMessage(conn, ws.OpText, []byte(payload))
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexListen", nil, err)
	}
}

func TestSessionTRexRoute(t *testing.T) {
	ws, _ := net.Pipe()
	s := &SessionTRex{
		Session: &Session{
			Websocket: ws,
		},
	}

	msg := common.Message{
		Handler: "canbus",
		Data: &kafka_grpc.GRPC_CANData{
			EpochUsec: 1653255445,
			Dropped:   10,
			Filtered:  20,
			Frames: []*kafka_grpc.GRPC_CANFrame{
				{
					Epoch: 1642455023642165,
					ID:    832,
					Value: []byte("AAAAAAAAIAE="),
				},
			},
		},
	}

	data, err := json.Marshal(msg)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexRoute", nil, err)
	}

	err = s.Route(kafka.GetKafkaMock(nil), data)
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexRoute", nil, err)
	}
}

func TestSessionTRexLoad(t *testing.T) {
	ws, _ := net.Pipe()
	s := &SessionTRex{
		Session: &Session{
			Websocket: ws,
			Type:      common.TRex,
			ID:        "FISKER123",
		},
	}

	err := s.Load(kafka.GetKafkaMock(nil))
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexLoad", nil, err)
	}
}

func TestSessionTRexTeardown(t *testing.T) {
	ws, _ := net.Pipe()
	s := &SessionTRex{
		Session: &Session{
			Websocket: ws,
			Type:      common.TRex,
			ID:        "FISKER123",
		},
	}

	err := s.Load(kafka.GetKafkaMock(nil))
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexTeardown", nil, err)
	}

	err = s.Teardown(kafka.GetKafkaMock(nil))
	if err != nil {
		t.Errorf(testhelper.TestErrorTemplate, "TestSessionTRexTeardown", nil, err)
	}
}
