package dataapisvc

import (
	"context"
	"fmt"
	"log"
	"strings"

	"github.com/tidbcloud/dataservices/idl/pbgen/proto/dataapi"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

var (
	dataapiClient dataapi.DataAPIServiceClient
)

func InitDataAPI(addr string) error {
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
		return err
	}
	//defer conn.Close()

	dataapiClient = dataapi.NewDataAPIServiceClient(conn)
	return nil
}

func TryExecSQL(ctx context.Context, projectID, clusterID uint64, database, sql string) (*dataapi.ExecSqlResp, error) {
	req := &dataapi.BasicEndpointReq{
		ProjectId: projectID,
		ClusterId: clusterID,
		Database:  database,
		Sql:       sql,
	}
	tilog.Info(ctx, "request dataapi with payload", zap.Any("payload", req))
	resp, err := dataapiClient.ExecSqlDirectly(ctx, req)
	if err != nil {
		tilog.Error(ctx, "failed to execute SQL by dataapisvc", zap.Error(err))
		return nil, err
	}
	tilog.Info(ctx, "try exec sql", zap.String("sql", sql), zap.Any("resp", resp))
	if resp.BaseResp.ErrCode != 0 {
		return nil, fmt.Errorf("failed to execute sql: %s", resp.BaseResp)
	}
	if resp.Code != 0 {
		return nil, fmt.Errorf("failed to execute sql: %s, %d", resp.Message, resp.Code)
	}

	return resp, nil
}

func formatColumnName(cols []string) []string {
	retList := make([]string, len(cols))
	for index, col := range cols {
		retList[index] = fmt.Sprintf("`%s`", col)
	}
	return retList
}

func GenTableLines(ctx context.Context, projectID int64, clusterID int64, dbName string) (string, error) {
	req := &dataapi.GetDatabaseMetaReq{
		ProjectId: uint64(projectID),
		ClusterId: uint64(clusterID),
		Database:  dbName,
	}
	resp, err := dataapiClient.GetDatabaseMeta(ctx, req)
	tilog.Info(
		ctx, "get database meta", zap.Any("resp", resp), zap.Error(err), zap.Int64("projectID", projectID),
		zap.Int64("clusterID", clusterID), zap.String("dbName", dbName),
	)
	if err != nil {
		return "", err
	}
	var tableLines []string
	for _, meta := range resp.Metas {
		meta.Columns = formatColumnName(meta.Columns)
		line := "Table " + dbName + "." + meta.GetTable() + ", columns = [" + strings.Join(meta.Columns, ", ") + "]"
		tableLines = append(tableLines, line)
	}

	return strings.Join(tableLines, "\n"), nil
}
