// Code generated by Kitex v0.13.1. DO NOT EDIT.

package testservice

import (
	"context"
	"errors"
	"fmt"
	echo "generic_streaming_demo_thrift/kitex_gen/echo"
	client "github.com/cloudwego/kitex/client"
	kitex "github.com/cloudwego/kitex/pkg/serviceinfo"
	streaming "github.com/cloudwego/kitex/pkg/streaming"
)

var errInvalidMessageType = errors.New("invalid message type for service method handler")

var serviceMethods = map[string]kitex.MethodInfo{
	"Echo": kitex.NewMethodInfo(
		echoHandler,
		newTestServiceEchoArgs,
		newTestServiceEchoResult,
		false,
		kitex.WithStreamingMode(kitex.StreamingBidirectional),
	),
	"EchoClient": kitex.NewMethodInfo(
		echoClientHandler,
		newTestServiceEchoClientArgs,
		newTestServiceEchoClientResult,
		false,
		kitex.WithStreamingMode(kitex.StreamingClient),
	),
	"EchoServer": kitex.NewMethodInfo(
		echoServerHandler,
		newTestServiceEchoServerArgs,
		newTestServiceEchoServerResult,
		false,
		kitex.WithStreamingMode(kitex.StreamingServer),
	),
	"EchoPingPong": kitex.NewMethodInfo(
		echoPingPongHandler,
		newTestServiceEchoPingPongArgs,
		newTestServiceEchoPingPongResult,
		false,
		kitex.WithStreamingMode(kitex.StreamingNone),
	),
}

var (
	testServiceServiceInfo                = NewServiceInfo()
	testServiceServiceInfoForClient       = NewServiceInfoForClient()
	testServiceServiceInfoForStreamClient = NewServiceInfoForStreamClient()
)

// for server
func serviceInfo() *kitex.ServiceInfo {
	return testServiceServiceInfo
}

// for stream client
func serviceInfoForStreamClient() *kitex.ServiceInfo {
	return testServiceServiceInfoForStreamClient
}

// for client
func serviceInfoForClient() *kitex.ServiceInfo {
	return testServiceServiceInfoForClient
}

// NewServiceInfo creates a new ServiceInfo containing all methods
func NewServiceInfo() *kitex.ServiceInfo {
	return newServiceInfo(true, true, true)
}

// NewServiceInfo creates a new ServiceInfo containing non-streaming methods
func NewServiceInfoForClient() *kitex.ServiceInfo {
	return newServiceInfo(false, false, true)
}
func NewServiceInfoForStreamClient() *kitex.ServiceInfo {
	return newServiceInfo(true, true, false)
}

func newServiceInfo(hasStreaming bool, keepStreamingMethods bool, keepNonStreamingMethods bool) *kitex.ServiceInfo {
	serviceName := "TestService"
	handlerType := (*echo.TestService)(nil)
	methods := map[string]kitex.MethodInfo{}
	for name, m := range serviceMethods {
		if m.IsStreaming() && !keepStreamingMethods {
			continue
		}
		if !m.IsStreaming() && !keepNonStreamingMethods {
			continue
		}
		methods[name] = m
	}
	extra := map[string]interface{}{
		"PackageName": "echo",
	}
	if hasStreaming {
		extra["streaming"] = hasStreaming
	}
	svcInfo := &kitex.ServiceInfo{
		ServiceName:     serviceName,
		HandlerType:     handlerType,
		Methods:         methods,
		PayloadCodec:    kitex.Thrift,
		KiteXGenVersion: "v0.13.1",
		Extra:           extra,
	}
	return svcInfo
}

func echoHandler(ctx context.Context, handler interface{}, arg, result interface{}) error {
	st, ok := arg.(*streaming.Args)
	if !ok {
		return errors.New("TestService.Echo is a thrift streaming method, please call with Kitex StreamClient")
	}
	stream := &testServiceEchoServer{st.Stream}
	return handler.(echo.TestService).Echo(stream)
}

type testServiceEchoClient struct {
	streaming.Stream
}

func (x *testServiceEchoClient) DoFinish(err error) {
	if finisher, ok := x.Stream.(streaming.WithDoFinish); ok {
		finisher.DoFinish(err)
	} else {
		panic(fmt.Sprintf("streaming.WithDoFinish is not implemented by %T", x.Stream))
	}
}
func (x *testServiceEchoClient) Send(m *echo.Request) error {
	return x.Stream.SendMsg(m)
}
func (x *testServiceEchoClient) Recv() (*echo.Response, error) {
	m := new(echo.Response)
	return m, x.Stream.RecvMsg(m)
}

type testServiceEchoServer struct {
	streaming.Stream
}

func (x *testServiceEchoServer) Send(m *echo.Response) error {
	return x.Stream.SendMsg(m)
}

func (x *testServiceEchoServer) Recv() (*echo.Request, error) {
	m := new(echo.Request)
	return m, x.Stream.RecvMsg(m)
}

func newTestServiceEchoArgs() interface{} {
	return echo.NewTestServiceEchoArgs()
}

func newTestServiceEchoResult() interface{} {
	return echo.NewTestServiceEchoResult()
}

func echoClientHandler(ctx context.Context, handler interface{}, arg, result interface{}) error {
	st, ok := arg.(*streaming.Args)
	if !ok {
		return errors.New("TestService.EchoClient is a thrift streaming method, please call with Kitex StreamClient")
	}
	stream := &testServiceEchoClientServer{st.Stream}
	return handler.(echo.TestService).EchoClient(stream)
}

type testServiceEchoClientClient struct {
	streaming.Stream
}

func (x *testServiceEchoClientClient) DoFinish(err error) {
	if finisher, ok := x.Stream.(streaming.WithDoFinish); ok {
		finisher.DoFinish(err)
	} else {
		panic(fmt.Sprintf("streaming.WithDoFinish is not implemented by %T", x.Stream))
	}
}
func (x *testServiceEchoClientClient) Send(m *echo.Request) error {
	return x.Stream.SendMsg(m)
}
func (x *testServiceEchoClientClient) CloseAndRecv() (*echo.Response, error) {
	if err := x.Stream.Close(); err != nil {
		return nil, err
	}
	m := new(echo.Response)
	return m, x.Stream.RecvMsg(m)
}

type testServiceEchoClientServer struct {
	streaming.Stream
}

func (x *testServiceEchoClientServer) SendAndClose(m *echo.Response) error {
	return x.Stream.SendMsg(m)
}

func (x *testServiceEchoClientServer) Recv() (*echo.Request, error) {
	m := new(echo.Request)
	return m, x.Stream.RecvMsg(m)
}

func newTestServiceEchoClientArgs() interface{} {
	return echo.NewTestServiceEchoClientArgs()
}

func newTestServiceEchoClientResult() interface{} {
	return echo.NewTestServiceEchoClientResult()
}

func echoServerHandler(ctx context.Context, handler interface{}, arg, result interface{}) error {
	st, ok := arg.(*streaming.Args)
	if !ok {
		return errors.New("TestService.EchoServer is a thrift streaming method, please call with Kitex StreamClient")
	}
	stream := &testServiceEchoServerServer{st.Stream}
	req := new(echo.Request)
	if err := st.Stream.RecvMsg(req); err != nil {
		return err
	}
	return handler.(echo.TestService).EchoServer(req, stream)
}

type testServiceEchoServerClient struct {
	streaming.Stream
}

func (x *testServiceEchoServerClient) DoFinish(err error) {
	if finisher, ok := x.Stream.(streaming.WithDoFinish); ok {
		finisher.DoFinish(err)
	} else {
		panic(fmt.Sprintf("streaming.WithDoFinish is not implemented by %T", x.Stream))
	}
}
func (x *testServiceEchoServerClient) Recv() (*echo.Response, error) {
	m := new(echo.Response)
	return m, x.Stream.RecvMsg(m)
}

type testServiceEchoServerServer struct {
	streaming.Stream
}

func (x *testServiceEchoServerServer) Send(m *echo.Response) error {
	return x.Stream.SendMsg(m)
}

func newTestServiceEchoServerArgs() interface{} {
	return echo.NewTestServiceEchoServerArgs()
}

func newTestServiceEchoServerResult() interface{} {
	return echo.NewTestServiceEchoServerResult()
}

func echoPingPongHandler(ctx context.Context, handler interface{}, arg, result interface{}) error {
	realArg := arg.(*echo.TestServiceEchoPingPongArgs)
	realResult := result.(*echo.TestServiceEchoPingPongResult)
	success, err := handler.(echo.TestService).EchoPingPong(ctx, realArg.Req)
	if err != nil {
		return err
	}
	realResult.Success = success
	return nil
}
func newTestServiceEchoPingPongArgs() interface{} {
	return echo.NewTestServiceEchoPingPongArgs()
}

func newTestServiceEchoPingPongResult() interface{} {
	return echo.NewTestServiceEchoPingPongResult()
}

type kClient struct {
	c client.Client
}

func newServiceClient(c client.Client) *kClient {
	return &kClient{
		c: c,
	}
}

func (p *kClient) Echo(ctx context.Context) (TestService_EchoClient, error) {
	streamClient, ok := p.c.(client.Streaming)
	if !ok {
		return nil, fmt.Errorf("client not support streaming")
	}
	res := new(streaming.Result)
	err := streamClient.Stream(ctx, "Echo", nil, res)
	if err != nil {
		return nil, err
	}
	stream := &testServiceEchoClient{res.Stream}
	return stream, nil
}

func (p *kClient) EchoClient(ctx context.Context) (TestService_EchoClientClient, error) {
	streamClient, ok := p.c.(client.Streaming)
	if !ok {
		return nil, fmt.Errorf("client not support streaming")
	}
	res := new(streaming.Result)
	err := streamClient.Stream(ctx, "EchoClient", nil, res)
	if err != nil {
		return nil, err
	}
	stream := &testServiceEchoClientClient{res.Stream}
	return stream, nil
}

func (p *kClient) EchoServer(ctx context.Context, req *echo.Request) (TestService_EchoServerClient, error) {
	streamClient, ok := p.c.(client.Streaming)
	if !ok {
		return nil, fmt.Errorf("client not support streaming")
	}
	res := new(streaming.Result)
	err := streamClient.Stream(ctx, "EchoServer", nil, res)
	if err != nil {
		return nil, err
	}
	stream := &testServiceEchoServerClient{res.Stream}

	if err := stream.Stream.SendMsg(req); err != nil {
		return nil, err
	}
	if err := stream.Stream.Close(); err != nil {
		return nil, err
	}
	return stream, nil
}

func (p *kClient) EchoPingPong(ctx context.Context, req *echo.Request) (r *echo.Response, err error) {
	var _args echo.TestServiceEchoPingPongArgs
	_args.Req = req
	var _result echo.TestServiceEchoPingPongResult
	if err = p.c.Call(ctx, "EchoPingPong", &_args, &_result); err != nil {
		return
	}
	return _result.GetSuccess(), nil
}
