// GetProtoBytes - Will return platform message as bytes
func GetProtoBytes(message platform.Message) []byte {
	protoBytes, _ := platform.Marshal(message)
	return protoBytes
}
func TestMicroplatformHandler(t *testing.T) {
	server, _ := getServer(testPortMicro)

	connectionManager := platform.NewAmqpConnectionManager(rabbitUser, rabbitPass, rabbitAddr+":"+rabbitPort, "")
	publisher = getDefaultPublisher(connectionManager)
	subscriber = getDefaultSubscriber(connectionManager, server.GetRouterURI())

	router := platform.NewStandardRouter(publisher, subscriber)
	server.SetRouter(router)

	Convey("By accessing / with hex encoded string we should get back proper endpoint response", t, func() {

		server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			w.WriteHeader(200)
			w.Header().Set("Content-Type", "text/plain")

			contents, err := ioutil.ReadAll(req.Body)

			if err != nil {
				w.Write(ErrorResponse(fmt.Sprintf("Failed to read body: %s", err)))
				return
			}

			platformRequestBytes, err := hex.DecodeString(fmt.Sprintf("%s", contents))

			if err != nil {
				w.Write(ErrorResponse(fmt.Sprintf("Failed to decode body: %s", err)))
				return
			}

			platformRequest := &platform.Request{}

			if err := platform.Unmarshal(platformRequestBytes, platformRequest); err != nil {
				w.Write(ErrorResponse(fmt.Sprintf("Failed to unmarshal platform request: %s", err)))
				return
			}

			if platformRequest.Routing == nil {
				platformRequest.Routing = &platform.Routing{}
			}

			if platformRequest.Routing.RouteFrom != nil {
				platformRequest.Routing.RouteFrom = []*platform.Route{}
			}

			if !platform.RouteToSchemeMatches(platformRequest, "microservice") {
				w.Write(ErrorResponse(fmt.Sprintf("Unsupported scheme provided: %s", platformRequest.Routing.RouteTo)))
				return
			}

			w.Header().Set("Content-Type", "text/plain")

			mainReq := platform.Request{
				Routing: &platform.Routing{
					RouteTo: []*platform.Route{&platform.Route{Uri: teltech.String("resource:///testing/reply/http-router")}},
				},
			}

			w.Write([]byte(hex.EncodeToString(GetProtoBytes(platform.GenerateResponse(&mainReq, &mainReq)))))
			return
		}))

		defer server.Close()

		// Give it time to start the listener
		time.Sleep(300 * time.Millisecond)

		client := &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			},
		}

		Convey("By passing valid / we should get back valid response", func() {
			req := &platform.Request{
				Routing: &platform.Routing{
					RouteTo: []*platform.Route{&platform.Route{Uri: teltech.String("microservice:///testing/get/http-router")}},
				},
				Completed: teltech.Bool(true),
			}

			responseBytes, err := platform.Marshal(req)
			So(err, ShouldBeNil)

			reqHex := []byte(hex.EncodeToString(responseBytes))
			request, err := http.NewRequest("POST", server.URL, bytes.NewBuffer(reqHex))
			So(err, ShouldBeNil)

			request.Header.Set("Content-Type", "text/plain")

			resp, err := client.Do(request)
			So(err, ShouldBeNil)

			defer resp.Body.Close()

			contents, err := ioutil.ReadAll(resp.Body)
			So(err, ShouldBeNil)

			platformResponseBytes, err := hex.DecodeString(string(contents))
			So(err, ShouldBeNil)

			response := &platform.Request{}
			err = platform.Unmarshal(platformResponseBytes, response)
			So(err, ShouldBeNil)

			So(response.GetRouting().GetRouteTo()[0].GetUri(), ShouldNotEqual, "resource:///meta/reply/error")
			So(response.GetRouting().GetRouteTo()[0].GetUri(), ShouldEqual, "resource:///testing/reply/http-router")
		})

		Convey("By passing invalid hex message towards / we should get back hex decode errors", func() {
			reqHex := []byte("I am not valid request")
			request, err := http.NewRequest("POST", server.URL, bytes.NewBuffer(reqHex))
			So(err, ShouldBeNil)

			request.Header.Set("Content-Type", "text/plain")

			resp, err := client.Do(request)
			So(err, ShouldBeNil)

			defer resp.Body.Close()

			contents, err := ioutil.ReadAll(resp.Body)
			So(err, ShouldBeNil)

			platformResponseBytes, err := hex.DecodeString(string(contents))
			So(err, ShouldBeNil)

			response := &platform.Request{}
			err = platform.Unmarshal(platformResponseBytes, response)
			So(err, ShouldBeNil)

			So(response.GetRouting().GetRouteTo()[0].GetUri(), ShouldNotEqual, "resource:///meta/reply/error")

			responseErr := &platform.Error{}
			err = platform.Unmarshal(response.GetPayload(), responseErr)
			So(err, ShouldBeNil)
			So(responseErr.GetMessage(), ShouldContainSubstring, "Failed to decode body")
		})

		Convey("By passing invalid hex request towards / we should get back unmarshal errors", func() {
			reqHex := []byte(hex.EncodeToString([]byte("Somewhere over the rainbow...")))
			request, err := http.NewRequest("POST", server.URL, bytes.NewBuffer(reqHex))
			So(err, ShouldBeNil)

			request.Header.Set("Content-Type", "text/plain")

			resp, err := client.Do(request)
			So(err, ShouldBeNil)

			defer resp.Body.Close()

			contents, err := ioutil.ReadAll(resp.Body)
			So(err, ShouldBeNil)

			platformResponseBytes, err := hex.DecodeString(string(contents))
			So(err, ShouldBeNil)

			response := &platform.Request{}
			err = platform.Unmarshal(platformResponseBytes, response)
			So(err, ShouldBeNil)

			So(response.GetRouting().GetRouteTo()[0].GetUri(), ShouldNotEqual, "resource:///meta/reply/error")

			responseErr := &platform.Error{}
			err = platform.Unmarshal(response.GetPayload(), responseErr)
			So(err, ShouldBeNil)
			So(responseErr.GetMessage(), ShouldContainSubstring, "Failed to unmarshal platform request")
		})

		Convey("By passing valid hex and request but invalid router scheme we should see invald scheme error", func() {
			req := &platform.Request{
				Routing: &platform.Routing{
					RouteTo: []*platform.Route{&platform.Route{Uri: teltech.String("microservice-invalid:///testing/get/http-router")}},
				},
				Completed: teltech.Bool(true),
			}

			responseBytes, err := platform.Marshal(req)
			So(err, ShouldBeNil)

			reqHex := []byte(hex.EncodeToString(responseBytes))
			request, err := http.NewRequest("POST", server.URL, bytes.NewBuffer(reqHex))
			So(err, ShouldBeNil)

			request.Header.Set("Content-Type", "text/plain")

			resp, err := client.Do(request)
			So(err, ShouldBeNil)

			defer resp.Body.Close()

			contents, err := ioutil.ReadAll(resp.Body)
			So(err, ShouldBeNil)

			platformResponseBytes, err := hex.DecodeString(string(contents))
			So(err, ShouldBeNil)

			response := &platform.Request{}
			err = platform.Unmarshal(platformResponseBytes, response)
			So(err, ShouldBeNil)

			So(response.GetRouting().GetRouteTo()[0].GetUri(), ShouldNotEqual, "resource:///meta/reply/error")

			responseErr := &platform.Error{}
			err = platform.Unmarshal(response.GetPayload(), responseErr)
			So(err, ShouldBeNil)
			So(responseErr.GetMessage(), ShouldContainSubstring, "Unsupported scheme provided")
		})
	})
}
// MicroplatformEndpointHandler - HTTP proxy request towards gRPC router
func MicroplatformEndpointHandler(server *Server) func(w http.ResponseWriter, req *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "text/plain")

		contents, err := ioutil.ReadAll(req.Body)

		if err != nil {
			w.Write(ErrorResponse(fmt.Sprintf("Failed to read body: %s", err)))
			return
		}

		platformRequestBytes, err := hex.DecodeString(fmt.Sprintf("%s", contents))

		if err != nil {
			w.Write(ErrorResponse(fmt.Sprintf("Failed to decode body: %s", err)))
			return
		}

		platformRequest := &platform.Request{}

		if err := platform.Unmarshal(platformRequestBytes, platformRequest); err != nil {
			w.Write(ErrorResponse(fmt.Sprintf("Failed to unmarshal platform request: %s", err)))
			return
		}

		if platformRequest.Routing == nil {
			platformRequest.Routing = &platform.Routing{}
		}

		if platformRequest.Routing.RouteFrom != nil {
			platformRequest.Routing.RouteFrom = []*platform.Route{}
		}

		if !platform.RouteToSchemeMatches(platformRequest, "microservice") {
			w.Write(ErrorResponse(fmt.Sprintf("Unsupported scheme provided: %s", platformRequest.Routing.RouteTo)))
			return
		}

		responses, timeout := server.Router.Route(platformRequest)

		for {
			select {
			case response := <-responses:
				logger.Printf("Got a response for request:", platformRequest.GetUuid())

				if response.GetRouting().GetRouteTo()[0].GetUri() != "resource:///heartbeat" {

					responseBytes, err := platform.Marshal(response)

					if err != nil {
						w.Write(ErrorResponse(fmt.Sprintf(
							"failed to marshal platform request: %s - err: %s", platformRequest.GetUuid(), err,
						)))
						return
					}

					w.Write([]byte(hex.EncodeToString(responseBytes)))
					return
				}

			case <-timeout:
				w.Write(ErrorResponse(fmt.Sprintf("Got a timeout for request: %s", platformRequest.GetUuid())))
				return
			}
		}

		return
	}
}