// Copyright 2021 CloudWeGo Authors
//
// Licensed 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 generator

import (
	"reflect"
	"testing"
	"time"

	"github.com/cloudwego/kitex/internal/test"
	"github.com/cloudwego/kitex/tool/internal_pkg/util"
)

func TestConfig_Pack(t *testing.T) {
	var s feature
	var i int64
	val := reflect.ValueOf(&s)
	val.Elem().SetInt(i)
	type fields struct {
		Verbose               bool
		GenerateMain          bool
		GenerateInvoker       bool
		Version               string
		NoFastAPI             bool
		ModuleName            string
		ServiceName           string
		Use                   string
		IDLType               string
		Includes              util.StringSlice
		ThriftOptions         util.StringSlice
		ProtobufOptions       util.StringSlice
		IDL                   string
		OutputPath            string
		PackagePrefix         string
		CombineService        bool
		CopyIDL               bool
		ThriftPlugins         util.StringSlice
		ProtobufPlugins       util.StringSlice
		Features              []feature
		FrugalPretouch        bool
		Record                bool
		RecordCmd             string
		ThriftPluginTimeLimit time.Duration
		TemplateDir           string
		Protocol              string
		HandlerReturnKeepResp bool
	}

	tests := []struct {
		name    string
		fields  fields
		wantRes []string
	}{
		// TODO: Add test cases.
		{
			name:    "some",
			fields:  fields{Features: []feature{feature(999)}, ThriftPluginTimeLimit: 30 * time.Second},
			wantRes: []string{"Verbose=false", "GenerateMain=false", "GenerateInvoker=false", "Version=", "NoFastAPI=false", "ModuleName=", "ServiceName=", "Use=", "IDLType=", "Includes=", "ThriftOptions=", "ProtobufOptions=", "Hessian2Options=", "IDL=", "OutputPath=", "PackagePrefix=", "CombineService=false", "CopyIDL=false", "ProtobufPlugins=", "Features=999", "FrugalPretouch=false", "ThriftPluginTimeLimit=30s", "CompilerPath=", "ExtensionFile=", "Record=false", "RecordCmd=", "TemplateDir=", "GenPath=", "DeepCopyAPI=false", "Protocol=", "HandlerReturnKeepResp=false", "NoDependencyCheck=false", "Rapid=false", "LocalThriftgo=false", "FrugalStruct=", "NoRecurse=false", "BuiltinTpl=", "StreamX=false"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := &Config{
				Verbose:               tt.fields.Verbose,
				GenerateMain:          tt.fields.GenerateMain,
				GenerateInvoker:       tt.fields.GenerateInvoker,
				Version:               tt.fields.Version,
				NoFastAPI:             tt.fields.NoFastAPI,
				ModuleName:            tt.fields.ModuleName,
				ServiceName:           tt.fields.ServiceName,
				Use:                   tt.fields.Use,
				IDLType:               tt.fields.IDLType,
				Includes:              tt.fields.Includes,
				ThriftOptions:         tt.fields.ThriftOptions,
				ProtobufOptions:       tt.fields.ProtobufOptions,
				IDL:                   tt.fields.IDL,
				OutputPath:            tt.fields.OutputPath,
				PackagePrefix:         tt.fields.PackagePrefix,
				CombineService:        tt.fields.CombineService,
				CopyIDL:               tt.fields.CopyIDL,
				ThriftPlugins:         tt.fields.ThriftPlugins,
				Features:              tt.fields.Features,
				FrugalPretouch:        tt.fields.FrugalPretouch,
				ThriftPluginTimeLimit: tt.fields.ThriftPluginTimeLimit,
				TemplateDir:           tt.fields.TemplateDir,
				Protocol:              tt.fields.Protocol,
			}
			if gotRes := c.Pack(); !reflect.DeepEqual(gotRes, tt.wantRes) {
				t.Errorf("Config.Pack() = \n%v\nwant\n%v", gotRes, tt.wantRes)
			}
		})
	}
}

func TestConfig_Unpack(t *testing.T) {
	type fields struct {
		Verbose               bool
		GenerateMain          bool
		GenerateInvoker       bool
		Version               string
		NoFastAPI             bool
		ModuleName            string
		ServiceName           string
		Use                   string
		IDLType               string
		Includes              util.StringSlice
		ThriftOptions         util.StringSlice
		ProtobufOptions       util.StringSlice
		IDL                   string
		OutputPath            string
		PackagePrefix         string
		CombineService        bool
		CopyIDL               bool
		Features              []feature
		FrugalPretouch        bool
		TemplateDir           string
		Protocol              string
		HandlerReturnKeepResp bool
	}
	type args struct {
		args []string
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		wantErr bool
	}{
		// TODO: Add test cases.
		{
			name:    "some",
			fields:  fields{},
			args:    args{args: []string{"Features=0"}},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := &Config{
				Verbose:               tt.fields.Verbose,
				GenerateMain:          tt.fields.GenerateMain,
				GenerateInvoker:       tt.fields.GenerateInvoker,
				Version:               tt.fields.Version,
				NoFastAPI:             tt.fields.NoFastAPI,
				ModuleName:            tt.fields.ModuleName,
				ServiceName:           tt.fields.ServiceName,
				Use:                   tt.fields.Use,
				IDLType:               tt.fields.IDLType,
				Includes:              tt.fields.Includes,
				ThriftOptions:         tt.fields.ThriftOptions,
				ProtobufOptions:       tt.fields.ProtobufOptions,
				IDL:                   tt.fields.IDL,
				OutputPath:            tt.fields.OutputPath,
				PackagePrefix:         tt.fields.PackagePrefix,
				CombineService:        tt.fields.CombineService,
				CopyIDL:               tt.fields.CopyIDL,
				Features:              tt.fields.Features,
				FrugalPretouch:        tt.fields.FrugalPretouch,
				TemplateDir:           tt.fields.TemplateDir,
				Protocol:              tt.fields.Protocol,
				HandlerReturnKeepResp: tt.fields.HandlerReturnKeepResp,
			}
			if err := c.Unpack(tt.args.args); (err != nil) != tt.wantErr {
				t.Errorf("Config.Unpack() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func Test_needCallOpt(t *testing.T) {
	t.Run("protobuf", func(t *testing.T) {
		pkg := &PackageInfo{
			Codec: "protobuf",
		}
		test.Assert(t, needCallOpt(pkg))
	})
	t.Run("thrift-no-methods", func(t *testing.T) {
		pkg := &PackageInfo{
			Codec: "thrift",
			ServiceInfo: &ServiceInfo{
				Methods: nil,
			},
		}
		test.Assert(t, !needCallOpt(pkg))
	})
	t.Run("thrift-with-only-streaming-methods", func(t *testing.T) {
		pkg := &PackageInfo{
			Codec: "thrift",
			ServiceInfo: &ServiceInfo{
				Methods: []*MethodInfo{{
					IsStreaming:     true,
					ServerStreaming: true,
				}},
			},
		}
		test.Assert(t, !needCallOpt(pkg))
	})
	t.Run("thrift-with-ping-pong-methods", func(t *testing.T) {
		pkg := &PackageInfo{
			Codec: "thrift",
			ServiceInfo: &ServiceInfo{
				Methods: []*MethodInfo{
					{IsStreaming: true, ServerStreaming: true},
					{},
				},
			},
		}
		test.Assert(t, needCallOpt(pkg))
	})
}
