package platform

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	l4g "github.com/alecthomas/log4go"
	"github.com/dailymotion/allure-go"
	"github.com/gavv/httpexpect/v2"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/qa-PlatformAPIAuto/common"
	"github.com/tidbcloud/qa-gourd/ProductService"
	"github.com/tidbcloud/qa-gourd/handler"
	"github.com/tidbcloud/qa-gourd/util"
)

func RunAllDataAPPSceneTest(w *ProductService.WebRequestInfo, UrlInfoMap map[string]ProductService.UrlInfo, reporter *util.AllureReporter) {
	pt := &PlatformTest{}
	pt.Init(w, UrlInfoMap, reporter)
	pt.PrepareClusterDataScene()
	pt.CheckDataAPPScene()
	pt.CheckAutoGenerateEndpointDataAPPScene()
	pt.CheckSystemDataAPPScene()
}

func (pt *PlatformTest) CheckDataAPPScene() {
	// user endpoint
	tierType := "Dedicated"
	if pt.w.Cluster.IsServerless {
		tierType = "Serverless"
	}
	pt.Reporter.StepReport(fmt.Sprintf("Test%sDataAPP", tierType),
		func() {
			dt := &DataAPPTest{
				pt:     pt,
				Region: pt.w.Cluster.Region,
			}
			dt.Init()
			dt.CreateDataAPP(DataAPPStandardType)
			dt.CreateAPIKey(APIKeyRole)
			dt.CreateEndpoint()
			dt.ConfigEndpoint(EndpointName)
			dt.GetEndpoint(EndpointName)
			dt.TestEndpoint(EndpointName)
			dt.DeployEndpoint(EndpointName)
			// sleep for 30 seconds
			util.SecondTimeWait(10, 3, fmt.Sprintf("Test%sDataAPP", tierType)+" Wait For Delegate Account")
			dt.RunEndpoint(EndpointName, "digest", nil, get_query_param, nil)
			BasicResp := dt.RunEndpoint(EndpointName, "basic", nil, get_query_param, nil)
			dt.CheckRunEndpointResult(BasicResp)
			dt.UnDeployEndpoint(EndpointName)
			dt.DeleteEndpoint(EndpointName)
			dt.DeleteDataAPP()
			// remain cluster
			if dt.RemainFlag {
				dt.pt.w.Cluster.RemainFlag = true
			}
		})
}

func (pt *PlatformTest) CheckAutoGenerateEndpointDataAPPScene() {
	// Release20230726 platform : Auto generate func & batch operation check
	tierType := "Dedicated"
	if pt.w.Cluster.IsServerless {
		tierType = "Serverless"
	}
	pt.Reporter.StepReport(fmt.Sprintf("Test%sDataAPPAutoGenerateEndpoint", tierType),
		func() {
			dt := &DataAPPTest{
				pt:     pt,
				Region: pt.w.Cluster.Region,
			}
			dt.Init()
			dt.CreateDataAPP(DataAPPStandardType)
			dt.CreateAPIKey(APIKeyRole)
			dt.AutoGenerateEndpoint()
			dt.GetEndpoint(BatchPostEndpointName)
			// sleep for 30 seconds
			util.SecondTimeWait(10, 3, fmt.Sprintf("Test%sDataAPPAutoGenerateEndpoint", tierType)+" Wait For Delegate Account")
			dt.RunEndpoint(BatchPostEndpointName, "digest", nil, nil, batch_post_body, "2 rows affected")
			dt.RunEndpoint(BatchPostEndpointName, "basic", nil, nil, batch_post_body, "2 rows affected")
			dt.DeleteDataAPP()
			// remain cluster
			if dt.RemainFlag {
				dt.pt.w.Cluster.RemainFlag = true
			}
		})
}

func (pt *PlatformTest) CheckSystemDataAPPScene() {
	// Release20231121 platform & BSS : New Chat2Query v2 Endpoint scene case
	tierType := "Dedicated"
	if pt.w.Cluster.IsServerless {
		tierType = "Serverless"
	}
	pt.Reporter.StepReport(fmt.Sprintf("Test%sSystemDataAPP", tierType),
		func() {
			dt := &DataAPPTest{
				pt:     pt,
				Region: pt.w.Cluster.Region,
			}
			// data service service region in staging&dev is us-west-2 (not cluster's region)
			if handler.EnvFile != "prod" {
				dt.Region = StagingServiceRegion
			}
			dt.Init()
			dt.CreateDataAPP(DataAPPChat2QueryType)
			dt.CreateAPIKey(Chat2QueryAPIKeyRole)
			dt.LoadAPPEndpoints()
			for _, endpoint := range dt.Endpoints {
				dt.ConfigEndpoint("", endpoint.EndpointId)
			}
			// sleep for 30 seconds
			// util.SecondTimeWait(10, 3, fmt.Sprintf("Test%sSystemDataAPP", tierType)+" Wait For Delegate Account")
			dt.SystemEndpointsRunScene()
			dt.DeleteDataAPP()
			// remain cluster
			if dt.RemainFlag {
				dt.pt.w.Cluster.RemainFlag = true
			}
		})
}

func (dt *DataAPPTest) CreateDataAPP(app_type string) {
	pathParam := map[string]string{
		"org_id":     dt.pt.w.User.OrgId,
		"project_id": dt.pt.w.User.ProjectId,
	}
	CurrDataAppName := DataAPPName + common.GenTempName()
	body := common.NewCreateDataAPPBody(CurrDataAppName, app_type, []string{dt.pt.w.Cluster.ClusterId})
	// create Dataapp
	createDataAPPResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["createDataAPP"], body, pathParam, nil)

	dt.AppId = fmt.Sprintf("%.0f", createDataAPPResp.JSON().Path(DataAPPIdPath).Number().Raw())
	if dt.AppId == "" || dt.AppId == "0" {
		errorMsg := fmt.Errorf("createDataAPP failed, app id is empty")
		l4g.Error(errorMsg)
		allure.FailNow(errorMsg)
	}
	dt.pt.Reporter.StepReport(fmt.Sprintf("createDataAPP , app_type is : %s , app id is  :%v", app_type, dt.AppId),
		func() {
			assert.Equal(dt.pt.Reporter.T, http.StatusOK, createDataAPPResp.Raw().StatusCode)
		})
	dt.AppType = app_type
}

func (dt *DataAPPTest) CreateAPIKey(Role string) {
	pathparam := map[string]string{
		"org_id":     dt.pt.w.User.OrgId,
		"project_id": dt.pt.w.User.ProjectId,
		"app_id":     dt.AppId,
	}
	body := map[string]interface{}{
		"name":           APIKeyName,
		"role":           Role,
		"rate_limit_rpm": APIKeyRateLimit,
	}
	createDataAPPKeyResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["createDataAPPKey"], body, pathparam, nil)

	dt.ak = createDataAPPKeyResp.JSON().Path(PublicKeyPath).String().Raw()
	dt.sk = createDataAPPKeyResp.JSON().Path(PrivateKeyPath).String().Raw()
	message := createDataAPPKeyResp.JSON().Path(MessagePath)
	code := createDataAPPKeyResp.JSON().Path(CodePath)

	dt.pt.Reporter.StepReport(fmt.Sprintf("create api key , app id is : %v, public key is :%s", dt.AppId, dt.ak),
		func() {
			message.IsEqual(ExpectMessage)
			code.IsEqual(ExpectCode)
		})
}

func (dt *DataAPPTest) CreateEndpoint() {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")
	pathparam := map[string]string{
		"org_id":     dt.pt.w.User.OrgId,
		"project_id": dt.pt.w.User.ProjectId,
		"app_id":     dt.AppId,
	}
	settings := common.EndpointSettings{
		// TimeOut:   Endpoint_Max_TimeOut,
		TimeOut:   EndpointTimeOut,
		RowsLimit: EndpointRowsLimit,
	}
	body := common.CreateEndpointParam{
		Name:        EndpointName,
		Description: EndpointDescription,
		Method:      EndpointMethod,
		Settings:    settings,
	}

	createEndpointResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["createEndpoint"], body, pathparam, nil)

	dt.Endpoints[EndpointName] = EndpointTest{EndpointId: fmt.Sprintf("%.0f", createEndpointResp.JSON().Path(EndpointIdPath).Number().Raw())}
	message := createEndpointResp.JSON().Path(MessagePath)
	code := createEndpointResp.JSON().Path(CodePath)

	dt.pt.Reporter.StepReport(fmt.Sprintf("create endpoint , app id is : %v, endpoint id is  :%v", dt.AppId, dt.Endpoints[EndpointName].EndpointId),
		func() {
			message.IsEqual(ExpectMessage)
			code.IsEqual(ExpectCode)
		})
	if dt.Endpoints[EndpointName].EndpointId == "" {
		errorMsg := fmt.Errorf("create Endpoint failed, endpoint id is empty")
		l4g.Error(errorMsg)
		allure.FailNow(errorMsg)
	}
}

// config endpoint , if param configEndpointId is empty, config endpoint by endpoint name in dt.Endpoints
func (dt *DataAPPTest) ConfigEndpoint(endpointFlag string, configEndpointId ...string) error {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")

	endpointId, err := dt.getEndpointId(endpointFlag, configEndpointId...)
	if err != nil {
		return err
	}
	pathparam := map[string]string{
		"org_id":      dt.pt.w.User.OrgId,
		"project_id":  dt.pt.w.User.ProjectId,
		"app_id":      dt.AppId,
		"endpoint_id": endpointId,
	}

	var body common.EndpointFormat
	if dt.AppType == DataAPPChat2QueryType {
		// In current version , only chat2data v1 endpoint can config rows limit param.
		body = common.EndpointFormat{
			Settings: common.EndpointSettings{
				TimeOut:   SystemEndpointMaxTimeOut,
				RowsLimit: EndpointRowsLimit,
			},
		}
	} else {
		body = common.EndpointFormat{
			SqlTemplate: EndpointSqlTemplate,
			Args: []common.EndpointArgs{{
				Name:     EndpointArgsName,
				Required: EndpointArgsRequired,
				Type:     EndpointArgsType,
			}},
			Endpoint: EndpointUrlPath,
			Settings: common.EndpointSettings{
				TimeOut:   EndpointTimeOut,
				RowsLimit: EndpointRowsLimit,
			},
			ClusterId: dt.pt.w.Cluster.ClusterId,
		}
	}
	patchEndpointResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["patchEndpoint"], body, pathparam, nil)

	message := patchEndpointResp.JSON().Path(MessagePath)
	code := patchEndpointResp.JSON().Path(CodePath)
	dt.pt.Reporter.StepReport(fmt.Sprintf("put endpoint , app id is : %v, endpoint id is  :%v, result is : %v", dt.AppId, endpointId, message),
		func() {
			message.IsEqual(ExpectMessage)
			code.IsEqual(ExpectCode)
		})

	return nil
}

// get endpoint , if param getEndpointId is empty, get endpoint by endpoint name in dt.Endpoints
func (dt *DataAPPTest) GetEndpoint(endpointFlag string, getEndpointId ...string) error {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")

	endpointId, err := dt.getEndpointId(endpointFlag, getEndpointId...)
	if err != nil {
		return err
	}
	pathparam := map[string]string{
		"org_id":      dt.pt.w.User.OrgId,
		"project_id":  dt.pt.w.User.ProjectId,
		"app_id":      dt.AppId,
		"endpoint_id": endpointId,
	}
	getEndpointResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["getEndpoint"], nil, pathparam, nil)

	dt.Endpoints[endpointFlag] = EndpointTest{
		EndpointId:         endpointId,
		EndpointMethod:     getEndpointResp.JSON().Path(EndpointMethodPath).String().Raw(),
		EndpointPath:       getEndpointResp.JSON().Path(EndpointPath).String().Raw(),
		EndpointServiceUrl: getEndpointResp.JSON().Path(EndpointServiceUrlPath).String().Raw(),
	}

	dt.pt.Reporter.StepReport(fmt.Sprintf("get endpoint , app id is : %v, endpoint id is  :%v,service_url is : %s , endpoint is : %s",
		dt.AppId,
		endpointId,
		dt.Endpoints[endpointFlag].EndpointServiceUrl,
		dt.Endpoints[endpointFlag].EndpointPath,
	),
		func() {
			assert.Equal(dt.pt.Reporter.T, http.StatusOK, getEndpointResp.Raw().StatusCode)
		})

	return nil
}

// test endpoint , if param testEndpointId is empty, test endpoint by endpoint name in dt.Endpoints
func (dt *DataAPPTest) TestEndpoint(endpointFlag string, testEndpointId ...string) error {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")

	endpointId, err := dt.getEndpointId(endpointFlag, testEndpointId...)
	if err != nil {
		return err
	}
	pathparam := map[string]string{
		"org_id":      dt.pt.w.User.OrgId,
		"project_id":  dt.pt.w.User.ProjectId,
		"app_id":      dt.AppId,
		"endpoint_id": endpointId,
	}
	// From 20230720, the args will be a list of list to support batch operation.
	body := map[string][][]common.EndpointBodyArgs{"args": {{{
		Name:  EndpointArgsName,
		Type:  EndpointArgsType,
		Value: EndpointArgsValue,
	}}}}

	testEndpointResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["testEndpoint"], body, pathparam, nil)

	if testEndpointResp.JSON().Path(TestEndpointCodePath).Number().Raw() == float64(http.StatusInternalServerError) {
		dt.RemainFlag = true
	}

	dt.pt.Reporter.StepReport(fmt.Sprintf("test endpoint , app id is : %v, endpoint id is  :%v,test resp is : %+v", dt.AppId, endpointId, testEndpointResp.JSON().Raw()),
		func() {
			testEndpointResp.JSON().Path(TestEndpointLimitPath).Number().IsEqual(EndpointRowsLimit)
			l4g.Info("test endpoint 's limit is %s", testEndpointResp.JSON().Path(TestEndpointLimitPath).Number().Raw())
			testEndpointResp.JSON().Path(TestEndpointCodePath).Number().IsEqual(ExpectCode)
			l4g.Info("test endpoint 's code is %s", testEndpointResp.JSON().Path(TestEndpointCodePath).Number().Raw())
			testEndpointResp.JSON().Path(TestEndpointRowsPath).Array().Length().IsEqual(EndpointRowsLimit)
			l4g.Info("test endpoint 's result rows is %+v", testEndpointResp.JSON().Path(TestEndpointRowsPath).Array().Raw())
		})
	return nil
}

// deploy endpoint , if param deployEndpointId is empty, deploy endpoint by endpoint name in dt.Endpoints
func (dt *DataAPPTest) DeployEndpoint(endpointFlag string, deployEndpointId ...string) error {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")

	endpointId, err := dt.getEndpointId(endpointFlag, deployEndpointId...)
	if err != nil {
		return err
	}
	pathparam := map[string]string{
		"org_id":      dt.pt.w.User.OrgId,
		"project_id":  dt.pt.w.User.ProjectId,
		"app_id":      dt.AppId,
		"endpoint_id": endpointId,
	}
	deployEndpointResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["deployEndpoint"], nil, pathparam, nil)

	message := deployEndpointResp.JSON().Path(MessagePath)
	code := deployEndpointResp.JSON().Path(CodePath)

	dt.pt.Reporter.StepReport(fmt.Sprintf("deploy endpoint , app id is : %v, endpoint id is  :%v,result is : %v", dt.AppId, endpointId, message),
		func() {
			message.IsEqual(ExpectMessage)
			code.IsEqual(ExpectCode)
		})

	return nil
}

func (dt *DataAPPTest) RunEndpoint(endpointFlag string, auth_method string, pathParam, queryParam map[string]string, body interface{}, expect_message ...string) *httpexpect.Response {
	// get regional service url
	ServiceUrl := dt.Endpoints[endpointFlag].EndpointServiceUrl
	if dt.AppType == DataAPPChat2QueryType {
		ServiceUrlList := strings.Split(dt.Endpoints[endpointFlag].EndpointServiceUrl, "//")
		ServiceUrl = fmt.Sprintf("https://%s.%s", dt.Region, ServiceUrlList[1])
	}
	URL := []string{ServiceUrl, dt.Endpoints[endpointFlag].EndpointPath}

	// send digest or basic auth request
	var RunEndpointResp *httpexpect.Response
	for i := 0; i < 40; i++ {
		if i > 0 {
			l4g.Info("Endpoint execution encountered http status %d, waiting for next retry, dataapp_id:%d, endpoint:%s:%s, times: %d.",
				RunEndpointResp.Raw().StatusCode, dt.AppId, auth_method, endpointFlag, i+1)
			time.Sleep(time.Second * 5)
		}
		switch auth_method {
		case "digest":
			{
				RunEndpointResp = util.SendRequest(dt.pt.Reporter.T, URL, dt.Endpoints[endpointFlag].EndpointMethod, body, pathParam, queryParam, jsonHeader, util.UseDigestTransport(dt.ak, dt.sk))
			}
		case "basic":
			{
				RunEndpointResp = util.SendRequest(dt.pt.Reporter.T, URL, dt.Endpoints[endpointFlag].EndpointMethod, body, pathParam, queryParam, jsonHeader, util.UseBasicAuthTransport(dt.ak, dt.sk))
			}
		}
		if RunEndpointResp.Raw().StatusCode != http.StatusUnauthorized {
			break
		}
	}

	if RunEndpointResp.Raw().StatusCode != http.StatusOK && RunEndpointResp.Raw().StatusCode != http.StatusBadRequest {
		dt.pt.Reporter.StepReport(fmt.Sprintf("RUN endpoint with %s Auth,  method is :%s , path param is : %+v, query param is : %+v , body is : %+v, resp is : %+v ",
			auth_method,
			dt.Endpoints[endpointFlag].EndpointMethod,
			pathParam,
			queryParam,
			body,
			RunEndpointResp.Body().Raw()),
			func() {
				assert.Equal(dt.pt.Reporter.T, http.StatusOK, RunEndpointResp.Raw().StatusCode)
			})
	} else {
		dt.pt.Reporter.StepReport(fmt.Sprintf("RUN endpoint with %s Auth,  method is :%s , path param is : %+v, query param is : %+v , body is : %+v, resp is : %+v ",
			auth_method,
			dt.Endpoints[endpointFlag].EndpointMethod,
			pathParam,
			queryParam,
			body,
			RunEndpointResp.JSON().Raw()),
			func() {
				assert.Equal(dt.pt.Reporter.T, http.StatusOK, RunEndpointResp.Raw().StatusCode)
				if len(expect_message) > 0 {
					assert.Contains(dt.pt.Reporter.T, RunEndpointResp.JSON().Path(DataMessagePath).String().Raw(), expect_message[0])
				}
			})
	}

	return RunEndpointResp
}

// check run endpoint result , for now it only has check rows limit case.
func (dt *DataAPPTest) CheckRunEndpointResult(resp *httpexpect.Response) {
	dt.pt.Reporter.StepReport(fmt.Sprintf("Check run endpoint's result , expect rows limit is  : %v, actual rows limit is : %v",
		EndpointRowsLimit,
		resp.JSON().Path(TestEndpointLimitPath).Number().Raw()),
		func() {
			assert.Equal(dt.pt.Reporter.T, true, dt.checkRowsLimit(resp))
		})
}

// undeploy endpoint , if param undeployEndpointId is empty, undeploy endpoint by endpoint name in dt.Endpoints
func (dt *DataAPPTest) UnDeployEndpoint(endpointFlag string, undeployEndpointId ...string) error {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")

	endpointId, err := dt.getEndpointId(endpointFlag, undeployEndpointId...)
	if err != nil {
		return err
	}
	pathparam := map[string]string{
		"org_id":      dt.pt.w.User.OrgId,
		"project_id":  dt.pt.w.User.ProjectId,
		"app_id":      dt.AppId,
		"endpoint_id": endpointId,
	}
	undeployEndpointResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["undeployEndpoint"], nil, pathparam, nil)
	message := undeployEndpointResp.JSON().Path(MessagePath)
	code := undeployEndpointResp.JSON().Path(CodePath)
	dt.pt.Reporter.StepReport(fmt.Sprintf("undeploy endpoint , app id is : %v, endpoint id is  :%v,result is : %v", dt.AppId, endpointId, message),
		func() {
			message.IsEqual(ExpectMessage)
			code.IsEqual(ExpectCode)
		})
	return nil
}

// delete endpoint , if param deleteEndpointId is empty, delete endpoint by endpoint name in dt.Endpoints
func (dt *DataAPPTest) DeleteEndpoint(endpointFlag string, deleteEndpointId ...string) error {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")

	endpointId, err := dt.getEndpointId(endpointFlag, deleteEndpointId...)
	if err != nil {
		return err
	}
	pathparam := map[string]string{
		"org_id":      dt.pt.w.User.OrgId,
		"project_id":  dt.pt.w.User.ProjectId,
		"app_id":      dt.AppId,
		"endpoint_id": endpointId,
	}
	deleteEndpointResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["deleteEndpoint"], nil, pathparam, nil)

	message := deleteEndpointResp.JSON().Path(MessagePath).String().Raw()
	dt.pt.Reporter.StepReport(fmt.Sprintf("deleteEndpoint , app id is : %v, endpoint id is  :%v, result is :%v", dt.AppId, endpointId, message),
		func() {
			assert.Equal(dt.pt.Reporter.T, http.StatusOK, deleteEndpointResp.Raw().StatusCode)
		})
	if deleteEndpointResp.Raw().StatusCode == 200 {
		return nil
	} else {
		return fmt.Errorf("delete endpoint failed, status code is %d,message is %s", deleteEndpointResp.Raw().StatusCode, message)
	}
}

func (dt *DataAPPTest) DeleteDataAPP() {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")

	pathParam := map[string]string{
		"org_id":     dt.pt.w.User.OrgId,
		"project_id": dt.pt.w.User.ProjectId,
		"app_id":     dt.AppId,
	}
	// delete Dataapp
	deleteDataAPPResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["deleteDataAPP"], nil, pathParam, nil)
	dt.pt.Reporter.StepReport(fmt.Sprintf("delete DataAPP , app id is  :%v", dt.AppId),
		func() {
			assert.Equal(dt.pt.Reporter.T, http.StatusOK, deleteDataAPPResp.Raw().StatusCode)
		})
}

func (dt *DataAPPTest) AutoGenerateEndpoint() {
	// sleep for 3 seconds
	util.SecondTimeWait(1, 3, "Wait For Region Message")
	// init config
	pathparam := map[string]string{
		"org_id":     dt.pt.w.User.OrgId,
		"project_id": dt.pt.w.User.ProjectId,
		"app_id":     dt.AppId,
	}
	configuraion := &common.AutoGenerateConfiguration{
		IsDeploy: true,
		TimeOut:  EndpointTimeOut,
		Tag:      EndpointTag,
	}
	APPClusters, err := dt.GetAPPClusters(dt.AppId)
	if err != nil {
		l4g.Error(err)
		allure.FailNow(err)
	}
	region, err := common.GetRegionofAPPCluster(APPClusters, dt.pt.w.Cluster.ClusterId)
	if err != nil {
		l4g.Error(err)
		allure.FailNow(err)
	}
	body := common.AutoGenerateEndpoint{
		ClusterId:     dt.pt.w.Cluster.ClusterId,
		Region:        region,
		DB:            EndpointSqlDBName,
		Table:         EndpointSqlTableName,
		Operations:    []string{"B-POST"},
		Configuration: configuraion,
	}
	autoGenerateEndpointResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["autoGenerateEndpoint"], body, pathparam, nil)

	dt.Endpoints[BatchPostEndpointName] = EndpointTest{
		EndpointId: fmt.Sprintf("%.0f", autoGenerateEndpointResp.JSON().Path(AutoGenerateEndpointId).Number().Raw()),
	}
	if dt.Endpoints[BatchPostEndpointName].EndpointId == "" || dt.Endpoints[BatchPostEndpointName].EndpointId == "0" {
		errorMsg := fmt.Errorf("auto generate endpoint failed, endpoint id is empty")
		l4g.Error(errorMsg)
		allure.FailNow(errorMsg)
	}
	message := autoGenerateEndpointResp.JSON().Path(MessagePath)
	code := autoGenerateEndpointResp.JSON().Path(CodePath)
	dt.pt.Reporter.StepReport(fmt.Sprintf("Auto generate endpoint , app id is : %v, endpoint id is  :%v", dt.AppId, dt.Endpoints[BatchPostEndpointName]),
		func() {
			message.IsEqual(ExpectMessage)
			code.IsEqual(ExpectCode)
		})
}

func (dt *DataAPPTest) LoadAPPEndpoints() {
	pathParam := map[string]string{
		"org_id":     dt.pt.w.User.OrgId,
		"project_id": dt.pt.w.User.ProjectId,
	}
	getDataAPPResp := dt.pt.w.DoWebAPIRequestByUrlInfo(dt.pt.URLInfoMap["getDataAPP"], nil, pathParam, nil)

	var APPList = common.DataAPPResp{}
	APPList, err := util.UnmarshalResult(getDataAPPResp, APPList)
	if err != nil {
		l4g.Info(fmt.Sprintf(err.Error()))
	}
	for _, app := range APPList.Data {
		appId := strconv.FormatUint(app.ID, 10)
		if appId == dt.AppId {
			for _, endpoint := range app.Endpoints {
				endpointFlag := endpoint.Name + fmt.Sprintf("%v", endpoint.Method)
				dt.Endpoints[endpointFlag] = EndpointTest{
					EndpointId:         strconv.FormatUint(endpoint.ID, 10),
					EndpointPath:       endpoint.Endpoint,
					EndpointMethod:     endpoint.Method,
					EndpointServiceUrl: app.BaseUrl,
				}
			}
		}
	}
	message := getDataAPPResp.JSON().Path(MessagePath)
	code := getDataAPPResp.JSON().Path(CodePath)
	dt.pt.Reporter.StepReport(fmt.Sprintf("Load app's all endpoints , app id is : %v, endpoints is  : %+v ", dt.AppId, dt.Endpoints),
		func() {
			message.IsEqual(ExpectMessage)
			code.IsEqual(ExpectCode)
		})
}

func (dt *DataAPPTest) SystemEndpointsRunScene() {
	postDataSummaryParam := map[string]string{
		"cluster_id": dt.pt.w.Cluster.ClusterId,
		"database":   EndpointSqlDBName,
	}
	// run post data summary
	var postDataSummaryResp *httpexpect.Response
	dt.pt.Reporter.StepReport("Post Create Data Summary",
		func() {
			postDataSummaryResp = dt.RunEndpoint(postDataSummaryFlag, "basic", nil, nil, postDataSummaryParam)
			dataSummaryId := postDataSummaryResp.JSON().Path(dataSummaryIdPath).Number().Raw()
			dt.pt.Reporter.StepReport(fmt.Sprintf("Post Create Data Summary , data summary id is :%v", dataSummaryId),
				func() {
					assert.Equal(dt.pt.Reporter.T, http.StatusOK, postDataSummaryResp.Raw().StatusCode)
					assert.NotEmpty(dt.pt.Reporter.T, dataSummaryId)
				})
		})

	// run get data summary
	dt.pt.Reporter.StepReport("Get Data Summary",
		func() {
			getDataSummaryResp := dt.RunEndpoint(getDataSummaryFlag, "basic", nil, postDataSummaryParam, nil)
			for round := 0; round < 30; round++ {
				util.SecondTimeWait(1, 10, "Wait For Create Data Summary Job Done")
				if getDataSummaryResp.JSON().Path(ResultStatusPath).String().Raw() == "done" {
					break
				}
				getDataSummaryResp = dt.RunEndpoint(getDataSummaryFlag, "basic", nil, postDataSummaryParam, nil)
			}
			dt.pt.Reporter.StepReport(fmt.Sprintf("Get Data Summary , status is : %v , resp is : %v",
				getDataSummaryResp.JSON().Path(ResultStatusPath).String().Raw(),
				getDataSummaryResp.Body().Raw(),
			),
				func() {
					assert.Equal(dt.pt.Reporter.T, "done", getDataSummaryResp.JSON().Path(ResultStatusPath).String().Raw())
				})
		})

	// run chat2data
	var jobId string
	dt.pt.Reporter.StepReport("Post Chat2Data V2",
		func() {
			Chat2DataParam := map[string]string{
				"cluster_id":   dt.pt.w.Cluster.ClusterId,
				"database":     EndpointSqlDBName,
				"raw_question": Chat2DataNaturalLanguage,
			}
			postChat2DataResp := dt.RunEndpoint(v2Chat2DataFlag, "basic", nil, nil, Chat2DataParam)
			jobId = postChat2DataResp.JSON().Path(jobIdPath).String().Raw()
			dt.pt.Reporter.StepReport(fmt.Sprintf("Post Chat2Data V2 , jobId is : %v", jobId),
				func() {
					assert.Equal(dt.pt.Reporter.T, http.StatusOK, postDataSummaryResp.Raw().StatusCode)
					assert.NotEmpty(dt.pt.Reporter.T, jobId)
				})
		})

	// run query job id
	var Chat2DataRows *httpexpect.Array
	dt.pt.Reporter.StepReport("Query Chat2Data V2 Result",
		func() {
			jobParam := map[string]string{
				"job_id": jobId,
			}
			getJobResp := dt.RunEndpoint(getJobFlag, "basic", jobParam, nil, nil)
			for round := 0; round < 12; round++ {
				util.SecondTimeWait(1, 10, "Wait For Chat2Data V2 Done")
				if getJobResp.JSON().Path(ResultStatusPath).String().Raw() == "done" {
					break
				}
				getJobResp = dt.RunEndpoint(getJobFlag, "basic", jobParam, nil, nil)
			}
			dt.pt.Reporter.StepReport(fmt.Sprintf("Query Chat2Data V2 job, resp is : %v", getJobResp.Raw()),
				func() {
					assert.Equal(dt.pt.Reporter.T, "done", getJobResp.JSON().Path(ResultStatusPath).String().Raw())
					Chat2DataRows = getJobResp.JSON().Path(Chat2DataDataPath).Array()
				})
		})

	// run v1 chat2data
	var V1Chat2DataResp *httpexpect.Response
	dt.pt.Reporter.StepReport("Query Chat2Data V1",
		func() {
			V1Chat2DataParam := map[string]string{
				"cluster_id":  dt.pt.w.Cluster.ClusterId,
				"database":    EndpointSqlDBName,
				"instruction": Chat2DataNaturalLanguage,
			}
			V1Chat2DataResp = dt.RunEndpoint(v1Chat2DataFlag, "basic", nil, nil, V1Chat2DataParam)
		})

	dt.pt.Reporter.StepReport("Compare Chat2Data V1 with Chat2Data V2 Result",
		func() {
			V1Chat2DataRows := V1Chat2DataResp.JSON().Path(TestEndpointRowsPath).Array()
			code := V1Chat2DataResp.JSON().Path(TestEndpointCodePath)
			dt.pt.Reporter.StepReport(fmt.Sprintf("V1 Chat2Data, instruction is : %s  , resp is : %v , compare sql result V1Chat2DataRows : %v with Chat2DataRows : %+v ",
				Chat2DataNaturalLanguage,
				V1Chat2DataResp.Raw(),
				V1Chat2DataRows,
				Chat2DataRows,
			),
				func() {
					assert.Equal(dt.pt.Reporter.T, http.StatusOK, V1Chat2DataResp.Raw().StatusCode)
					code.IsEqual(ExpectCode)
					assert.Equal(dt.pt.Reporter.T, true, dt.checkRowsLimit(V1Chat2DataResp))
				})
		})

}
