package main

import (
	"context"
	"log"

	"github.com/tidbcloud/dataservices/idl/pbgen/proto/dataapi"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

/*
	func testEndpoint(apiKey string) {
		header := map[string]string{"test-email": apiKey}
		url := host + "/api/v1/dataservices/orgs/" + strconv.Itoa(orgId) + "/projects/" + strconv.Itoa(projectId) + "/apps"
		reqStruct := &entity.CreateDataAppParam{
			AppName:          "autotest app",
			AppType:          entity.DataAppTypeDataapi,
			ClusterId:        90909,
			DeploymentRegion: "central",
		}

		resp, code, err := httpclient.PostWithHeader(url, reqStruct, &header)
		if err != nil {
			log.Error("fail to get response ", zap.Error(err))
		}
		log.Info("resp code is  " + strconv.Itoa(code) + " body is " + resp)
		data := Data{}
		json2.Unmarshal([]byte(resp), &data)
		log.Info(fmt.Sprintf("id###########:%v", data.Data))
		return fmt.Sprintf("%v", data.Data)
	}
*/

const (
	AUTH0TOKEN = ""
)

func main() {

	addr := "127.0.0.1:10001"
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	dataapiClient := dataapi.NewDataAPIServiceClient(conn)

	ctx := context.Background()
	// ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	// defer cancel()

	var (
		// orgId     uint64 = 240007
		projectId uint64 = 73950
		clusterId uint64 = 3059032
	)
	// database := "sample_data"
	// testGetDatabaseMeta(ctx, dataapiClient, projectId, clusterId, database)
	// testGetClusterMeta(ctx, dataapiClient, projectId, clusterId)
	// return
	// testShowAPIKey(ctx, dataapiClient)
	// return
	// Test delete apikey
	// testDeleteAPIKey(ctx, dataapiClient, 30002)
	// return
	// // Test apikey
	// testCreateAPIKey(ctx, dataapiClient)
	// return

	// Test data app manager interface(create, show, delete)
	testClusterPrivatelink(ctx, dataapiClient)
	// testDataAppManagerInterface(ctx, dataapiClient)
	return

	// Test ParseOneStmt interface
	// testParseOneStmt(ctx, dataapiClient)
	// return

	// caseSqlList := []string{
	// 	"select id from t1 union (select `rank` as id from sample_data.global_fortune_500_2018_2022 limit 3)",
	// 	"select id from test.t1 union (select `rank` as id from sample_data.global_fortune_500_2018_2022 limit 3)",
	// 	"SELECT 1 UNION SELECT 2",
	// 	"SELECT * FROM test.t1, more.t2, gharchive_dev.github_events WHERE type='IssuesEvent' limit 10",
	// }
	// caseSqlList = []string{
	// 	"SELECT 1 UNION SELECT 2",
	// 	"SELECT 1 UNION SELECT 2",
	// }
	// testExecSqlWithSession(ctx, dataapiClient, projectId, clusterId, caseSqlList)
	// return
	testSqlList := []string{
		"create database if not exists test_createdatabase",
		"show databases",
		"show tables",
		"select * from github_events limit 10",
		"update github_events  set created_at=now() where id='14819357068'",
		"show create database test_createdatabase",
		"use test_createdatabase",
		"CREATE TABLE IF NOT EXISTS test_tasks (task_id INT AUTO_INCREMENT, start_date DATE,  PRIMARY KEY (task_id))",
		"show create table test_tasks",
		"desc test_tasks",
		"alter table test_tasks rename as test_tasks1",
		"alter table test_tasks1 rename as test_tasks",
		"drop database if exists test_createdatabase",
	}

	testSqlList = []string{
		"create database if not exists test_createdatabase",
		"drop database if exists test_createdatabase",
	}
	testExecSqlWithSession(ctx, dataapiClient, projectId, clusterId, testSqlList)
	// testExecSql(ctx, dataapiClient, projectId, clusterId, testSqlList)
	// errSqlList := []string{
	// 	"show databases123",
	// 	"show tables321",
	// 	"select * from github_events_no_exist limit 10",
	// }
	// testExecSqlWithSession(ctx, dataapiClient, projectId, clusterId, errSqlList)

	testExecSql(ctx, dataapiClient)
}

func testGetClusterMeta(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient, projectId uint64, clusterId uint64) {
	req := &dataapi.GetClusterMetaReq{
		ProjectId: projectId,
		ClusterId: clusterId,
		Credential: &dataapi.Credential{
			Type: dataapi.CrtType_AUTH0,
			Key:  AUTH0TOKEN,
		},
	}
	res, err := dataapiClient.GetClusterMeta(ctx, req)
	if err != nil {
		log.Fatalf("err: %v", err)
	}
	log.Printf("GetClusterMeta: %s", res)
}
func testClusterPrivatelink(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient) {
	req := &dataapi.GetClusterStatusReq{ClusterIds: []uint64{3119056, 3779052, 3841045}}
	res, err := dataapiClient.GetClusterStatus(ctx, req)
	if err != nil {
		log.Fatal(err)
	}
	log.Print(res)
}

func testDataAppManagerInterface(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient) {

	var (
		orgId     uint64 = 240007
		projectId uint64 = 253477
		clusterId uint64 = 2939317
		appType          = "chat2query"
		operator         = "fangdong.jia@pingcap.com"
	)

	// Create Data App
	createReq := &dataapi.CreateDataAppReq{
		OrgId:     orgId,
		ProjectId: projectId,
		AppType:   appType,
		CreatedBy: operator,
	}
	// First create app
	createResp, err := dataapiClient.CreateDataApp(ctx, createReq)
	if err != nil {
		log.Fatalf("CreateDataApp first failed, err:%v", err)
	} else if createResp.BaseResp.ErrCode != 0 {
		log.Fatalf("CreateDataApp first failed, base resp:%+v", *createResp.BaseResp)
	}
	log.Printf("CreateDataApp first succeed, app_info: %+v", *createResp.AppInfo)

	// Second create app
	createResp, err = dataapiClient.CreateDataApp(ctx, createReq)
	if err != nil {
		log.Fatalf("CreateDataApp second failed, err:%v", err)
	} else if createResp.BaseResp.ErrCode != 0 {
		log.Fatalf("CreateDataApp second failed, base resp:%+v", *createResp.BaseResp)
	}
	log.Printf("CreateDataApp second succeed, app_info: %+v", *createResp.AppInfo)

	// Show Data App
	showReq := &dataapi.ShowDataAppReq{
		AppId: createResp.AppInfo.Id,
		// AppId: 1,
	}
	showResp, err := dataapiClient.ShowDataApp(ctx, showReq)
	if err != nil {
		log.Fatalf("ShowDataApp failed, err:%v", err)
	} else if showResp.BaseResp.ErrCode != 0 {
		log.Fatalf("ShowDataApp failed, base resp:%+v", *showResp.BaseResp)
	}
	log.Printf("ShowDataApp succeed, app_info: %+v", *showResp.AppInfo)

	// List Data App
	listReq := &dataapi.ListDataAppReq{
		ProjectId: projectId,
		AppTypes:  []string{appType},
	}
	listResp, err := dataapiClient.ListDataApp(ctx, listReq)
	if err != nil {
		log.Fatalf("ListDataApp failed, err:%v", err)
	} else if listResp.BaseResp.ErrCode != 0 {
		log.Fatalf("ListDataApp failed, base resp:%+v", *listResp.BaseResp)
	}
	log.Printf("ListDataApp succeed, app_list: %+v", listResp.GetAppList())

	// Create apikey
	apikey, err := dataapiClient.CreateAPIKey(ctx, &dataapi.CreateAPIKeyReq{
		DataappId:   listResp.AppList[0].Id,
		Description: "chat2data auto create",
		CreatedBy:   operator,
		Source:      dataapi.APIKeySource_DataAPI_Source_Chat2Query_Console,
	})
	if err != nil {
		log.Fatalf("CreateAPIKey failed, err:%v", err)
	} else if apikey.BaseResp.ErrCode != 0 {
		log.Fatalf("CreateAPIKey failed, base resp:%+v", *apikey.BaseResp)
	}
	log.Printf("CreateAPIKey succeed, apikey: %+v", apikey)

	// Code example
	codeExample, err := dataapiClient.EndpointCodeExample(ctx, &dataapi.EndpointCodeExampleReq{
		ProjectId:    projectId,
		ClusterId:    clusterId,
		EndpointType: "chat2data",
	})
	if err != nil {
		log.Fatalf("EndpointCodeExample failed, err:%v", err)
	} else if codeExample.BaseResp.ErrCode != 0 {
		log.Fatalf("EndpointCodeExample failed, base resp:%+v", *codeExample.BaseResp)
	}
	log.Printf("EndpointCodeExample succeed, code: %s", codeExample.Code)

	return

	// Delete Data App
	delReq := &dataapi.DeleteDataAppReq{
		AppId: createResp.AppInfo.Id,
	}
	delResp, err := dataapiClient.DeleteDataApp(ctx, delReq)
	if err != nil {
		log.Fatalf("DeleteDataApp failed, err:%v", err)
	} else if delResp.BaseResp.ErrCode != 0 {
		log.Fatalf("DeleteDataApp failed, base resp:%+v", *delResp.BaseResp)
	}
	log.Printf("DeleteDataApp succeed, app_id:%d", createResp.AppInfo.Id)

	// Code example
	codeExample, err = dataapiClient.EndpointCodeExample(ctx, &dataapi.EndpointCodeExampleReq{
		ProjectId:    projectId,
		ClusterId:    clusterId,
		EndpointType: "chat2data",
	})
	if err != nil {
		log.Fatalf("EndpointCodeExample failed, err:%v", err)
	} else if codeExample.BaseResp.ErrCode != 0 {
		log.Fatalf("EndpointCodeExample failed, base resp:%+v", *codeExample.BaseResp)
	}
	log.Printf("EndpointCodeExample succeed, code: %s", codeExample.Code)

	// List Data App
	listReq = &dataapi.ListDataAppReq{
		ProjectId: projectId,
		AppTypes:  []string{appType},
	}
	listResp, err = dataapiClient.ListDataApp(ctx, listReq)
	if err != nil {
		log.Fatalf("ListDataApp failed, err:%v", err)
	} else if listResp.BaseResp.ErrCode != 0 {
		log.Fatalf("ListDataApp failed, base resp:%+v", *listResp.BaseResp)
	}
	log.Printf("ListDataApp succeed, app_list: %+v", listResp.GetAppList())

}
func testShowAPIKey(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient) {
	showReq := &dataapi.ShowAPIKeyReq{
		ApikeyId: 30006,
	}
	showResp, err := dataapiClient.ShowAPIKey(ctx, showReq)
	if err != nil {
		log.Fatalf("ShowAPIKey failed, err:%v", err)
	} else if showResp.BaseResp.ErrCode != 0 {
		log.Fatalf("ShowAPIKey failed, base resp:%+v", *showResp.BaseResp)
	}
	log.Printf("ShowAPIKey succeed, raw_key: %+v", showResp.RawKey)
}
func testCreateAPIKey(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient) {
	// Create Data App
	createReq := &dataapi.CreateDataAppReq{
		OrgId:     30061,
		ProjectId: 43563,
		AppType:   "chat2query",
		CreatedBy: "hongmeng.lv@pingcap.com",
	}
	createResp, err := dataapiClient.CreateDataApp(ctx, createReq)
	if err != nil {
		log.Fatalf("CreateDataApp failed, err:%v", err)
	} else if createResp.BaseResp.ErrCode != 0 {
		log.Fatalf("CreateDataApp failed, base resp:%+v", *createResp.BaseResp)
	}
	log.Printf("CreateDataApp succeed, app_info: %+v", *createResp.AppInfo)

	// Show Data App
	showReq := &dataapi.ShowDataAppReq{
		AppId: createResp.AppInfo.Id,
	}
	showResp, err := dataapiClient.ShowDataApp(ctx, showReq)
	if err != nil {
		log.Fatalf("ShowDataApp failed, err:%v", err)
	} else if showResp.BaseResp.ErrCode != 0 {
		log.Fatalf("ShowDataApp failed, base resp:%+v", *showResp.BaseResp)
	}
	log.Printf("ShowDataApp succeed, app_info: %+v", *showResp.AppInfo)

	// Create Apikey
	appid := showResp.AppInfo.Id
	extid := showResp.AppInfo.ExternalAppId
	createApiResp, err := dataapiClient.CreateAPIKey(ctx, &dataapi.CreateAPIKeyReq{
		DataappId:    appid,
		DataappExtId: extid,
		Description:  "auto test",
		CreatedBy:    "hongmeng.lv@pingcap.com",
		Source:       dataapi.APIKeySource_DataAPI_Source_Chat2Query_Console,
	})
	if err != nil {
		log.Fatalf("CreateAPIKey failed, err:%v", err)
	} else if createApiResp.BaseResp.ErrCode != 0 {
		log.Fatalf("CreateAPIKey failed, base resp:%+v", *createApiResp.BaseResp)
	}
	log.Printf("CreateAPIKey succeed, apikey: %+v", createApiResp.AccessKey)

	// Show Apikey
	listApikeyResp, err := dataapiClient.ListAPIKey(ctx, &dataapi.ListAPIKeyReq{
		DataappId: appid,
		Source:    dataapi.APIKeySource_DataAPI_Source_Chat2Query_Console,
	})
	if err != nil {
		log.Fatalf("ListApikey failed, err:%v", err)
	} else if listApikeyResp.BaseResp.ErrCode != 0 {
		log.Fatalf("ListApikey failed, base resp:%+v", *listApikeyResp.BaseResp)
	}
	log.Printf("ListApikey succeed, apikeys: %+v", listApikeyResp.Apikeys)

	//	Auth
	authResp, err := dataapiClient.AuthAPIKey(ctx, &dataapi.AuthAPIKeyReq{
		DataappExtId: extid,
		// ApiKey:       createApiResp.RawApiKey,
	})
	if err != nil {
		log.Fatalf("AuthApikey failed, err:%v", err)
	} else if authResp.BaseResp.ErrCode != 0 {
		log.Fatalf("AuthApikey failed, base resp:%+v", *authResp.BaseResp)
	}
	log.Printf("AuthApikey succeed, result: %+v", authResp.AuthFlag)
}

func testDeleteAPIKey(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient, apikeyId uint64) {
	//	Delete apikey
	deleteAPIKeyResp, err := dataapiClient.DeleteAPIKey(ctx, &dataapi.DeleteAPIKeyReq{
		ApikeyId:  apikeyId,
		CreatedBy: "hongmeng.lv@pingcap.com",
	})
	if err != nil {
		log.Fatalf("DeleteApikey failed, err:%v", err)
	} else if deleteAPIKeyResp.BaseResp.ErrCode != 0 {
		log.Fatalf("DeleteApikey failed, base resp:%+v", *deleteAPIKeyResp.BaseResp)
	}
	log.Printf("DeleteApikey succeed")
}

func testGetDatabaseMeta(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient, projectId uint64, clusterId uint64, database string) {
	req := &dataapi.GetDatabaseMetaReq{
		ProjectId: projectId,
		ClusterId: clusterId,
		Database:  database,
		Credential: &dataapi.Credential{
			Type: dataapi.CrtType_AUTH0,
			Key:  AUTH0TOKEN,
		},
	}
	res, err := dataapiClient.GetDatabaseMeta(ctx, req)
	if err != nil {
		log.Fatalf("err: %v", err)
	}
	log.Printf("GetDatabaseMeta: %s", res)
}

func testExecSqlWithSession(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient,
	projectId uint64, clusterId uint64, sqlList []string) {

	// Create Session
	req := &dataapi.CreateSessionReq{
		ProjectId: projectId,
		ClusterId: clusterId,
		Database:  "sample_data",
		ExpireSec: 100,
		Credential: &dataapi.Credential{
			Type: dataapi.CrtType_AUTH0,
			Key:  AUTH0TOKEN,
		},
	}
	res, err := dataapiClient.CreateSession(ctx, req)
	if err != nil {
		log.Fatalf("CreatSession err: %v", err)
	}
	log.Printf("CreateSession: %s", res)

	sessionId := res.SessionId

	for _, sql := range sqlList {
		// Run Sql
		runReq := &dataapi.BasicEndpointReq{
			ClusterId: clusterId,
			SessionId: sessionId,
			Sql:       sql,
			LimitRows: 10,
		}
		runRes, err := dataapiClient.ExecSqlWithSession(ctx, runReq)
		if err != nil {
			log.Fatalf("err: %v", err)
		}
		log.Printf("Exec Sql: %+v", runRes)

	}

	// Close Session
	closeReq := &dataapi.CloseSessionReq{
		ClusterId: clusterId,
		SessionId: sessionId,
	}
	closeRes, err := dataapiClient.CloseSession(ctx, closeReq)
	if err != nil {
		log.Fatalf("CloseSession err: %v", err)
	}
	log.Printf("CloseSession: %s", closeRes)

}
func testExecSql(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient) {
	req := &dataapi.BasicEndpointReq{
		ProjectId: 73950,
		ClusterId: 3059032,
		Database:  "sample_data",
		Sql:       "select * from github_events limit 1",
		Credential: &dataapi.Credential{
			Type: dataapi.CrtType_AUTH0,
			Key:  AUTH0TOKEN,
		},
	}
	res, err := dataapiClient.ExecSqlDirectly(ctx, req)
	if err != nil {
		log.Fatalf("err: %v", err)
	}
	log.Printf("Exec Sql: %s", res)
}

func testParseOneStmt(ctx context.Context, dataapiClient dataapi.DataAPIServiceClient) {

	sqlList := []string{
		"select * from user where name = ${name}",
	}
	for _, sql := range sqlList {
		log.Printf("ParseOneStmt sql: %s", sql)
		req := &dataapi.ParseOneStmtReq{Sql: sql}
		resp, err := dataapiClient.ParseOneStmt(ctx, req)
		if err != nil {
			log.Printf("ParseOneStmt failed, sql: %s, err: %v", sql, err)
			continue
		}
		log.Printf("ParseOneStmt succeed, resp: %+v", *resp)
	}
}
