package websocket

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

	"github.com/fiskerinc/cloud-services/pkg/common"
	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 TestSessionHMI(t *testing.T) {
	ws, _ := net.Pipe()
	s := SessionHMI{
		Session: &Session{
			Websocket: ws,
		},
	}

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

func TestNewHMISession(t *testing.T) {
	createNewSession := func(w http.ResponseWriter, r *http.Request) {
		s, err := NewTRexSession(w, r, "1F15K3R45N1234567", "2.0.0", "123456789123456789123456789")
		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 TestSessionHMIAuthenticate(t *testing.T) {
	userAgent := "HMI 1.2.3.4"

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

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

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

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

	am := common.HMISessionMessage{
		Handler: "verify",
		Data: common.HMISessionData{
			Salt: "XXXXXX",
		},
	}

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

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

func TestSessionHMIListen(t *testing.T) {
	userAgent := "HMI 1.2.3.4"
	payload := "hello fisker!"

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

		ctx := context.Background()
		err = s.Listen(ctx, kafka.GetKafkaMock(nil))
		if err.Error() != "EOF" {
			t.Errorf(testhelper.TestErrorTemplate, "TestSessionHMIListen", 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, "TestSessionHMIListen", nil, err)
	}
}

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

	msg := common.Message{
		Handler: "update_approve",
		Data:    "hello fisker!",
	}

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

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

	msg = common.Message{
		Handler: "invalid_handler",
		Data:    "false",
	}

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

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

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

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

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

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

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