/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package proto_suite

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"
)

import (
	triplepb "dubbo-go-pixiu-benchmark/api"

	"dubbo-go-pixiu-benchmark/test"

	"dubbo.apache.org/dubbo-go/v3/config"
	_ "dubbo.apache.org/dubbo-go/v3/imports"

	tripleConstant "github.com/dubbogo/triple/pkg/common/constant"

	. "github.com/onsi/ginkgo/v2"

	"github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/onsi/gomega/gmeasure"
)

var (
	grpcGreeterImpl                   = new(triplepb.GreeterClientImpl)
	tripleServerSession, pixiuSession *gexec.Session
)

func TestTripleCases(t *testing.T) {
	gomega.RegisterFailHandler(Fail)
	RunSpecs(t, "test")
}

var _ = Describe("triple protocol performance test", Ordered, func() {
	BeforeAll(func() {
		var err error
		test.CurPath, err = os.Getwd()
		gomega.Expect(err).NotTo(gomega.HaveOccurred())

		tripleServerSession = prepareTripleServer()
		pixiuSession = test.PreparePixiu("../../../dist/pixiu", test.CurPath+"/../../../protocol/triple/pb/pixiu/conf/config.yaml")

		time.Sleep(3 * time.Second)

		prepareTripleClient()

	})

	It("triple protocol performance test", func() {

		experiment := gmeasure.NewExperiment("triple protocol performance test")
		AddReportEntry(experiment.Name, experiment)

		experiment.Sample(func(idx int) {
			defer GinkgoRecover()

			experiment.MeasureDuration("SayHello", func() {
				req := &triplepb.HelloRequest{
					Name: "laurence",
				}
				ctx := context.WithValue(context.Background(), tripleConstant.TripleCtxKey("tri-req-id"), "test_value_XXXXXXXX")
				_, err := grpcGreeterImpl.SayHello(ctx, req)
				gomega.Expect(err).NotTo(gomega.HaveOccurred())
				//fmt.Printf("consumer:%+v\n", reply)
			})
		}, test.SampleConfig)
	})

	It("pixiu to triple protocol performance test", func() {
		defer GinkgoRecover()

		urlPrefix := "http://localhost:8881/dubbo.io/org.apache.dubbogo.samples.api.Greeter/%s"

		experiment := gmeasure.NewExperiment("pixiu to triple protocol performance test")
		AddReportEntry(experiment.Name, experiment)

		experiment.Sample(func(idx int) {
			experiment.MeasureDuration("SayHello", func() {
				defer GinkgoRecover()

				url := fmt.Sprintf(urlPrefix, "SayHello")
				data := `
{
	"name":"test"
}
`
				resp, err := http.Post(url, "application/json", strings.NewReader(data))
				gomega.Expect(err).NotTo(gomega.HaveOccurred())
				gomega.Expect(resp.Status).To(gomega.Equal("200 OK"))
				reply, err := io.ReadAll(resp.Body)
				gomega.Expect(err).NotTo(gomega.HaveOccurred())
				gomega.Expect(string(reply)).NotTo(gomega.MatchRegexp("client call err*"))
				//fmt.Printf("consumer:%+v\n", string(reply))
			})
		}, test.SampleConfig)
	})

	AfterAll(func() {
		tripleServerSession.Terminate().Wait(5 * time.Second)
		pixiuSession.Terminate().Wait(5 * time.Second)
	})
})

func prepareTripleServer() *gexec.Session {
	serverProcess, err := gexec.Build("dubbo-go-pixiu-benchmark/protocol/triple/pb/go-server/cmd")
	gomega.Expect(err).NotTo(gomega.HaveOccurred())

	command := exec.Command(serverProcess)
	session, err := gexec.Start(command, io.Discard, io.Discard)
	//session, err := gexec.Start(command, os.Stdout, os.Stderr)

	gomega.Expect(err).NotTo(gomega.HaveOccurred())

	return session
}

func prepareTripleClient() {
	config.SetConsumerService(grpcGreeterImpl)
	err := config.Load(config.WithPath(test.CurPath + "/../../../protocol/triple/pb/go-client/conf/dubbogo.yml"))
	gomega.Expect(err).NotTo(gomega.HaveOccurred())
}
