package debugportal

import (
	"context"

	"github.com/pingcap/dbaas/central/model/debug/slowquery"
	"github.com/tidbcloud/idl/pbgen/proto/central"
)

func (service *debugPortalService) GetSlowQueryFields(ctx context.Context, _ *central.GetSlowQueryFieldsReq) (*central.GetSlowQueryFieldsResp, error) {
	if err := service.authN(ctx); err != nil {
		return nil, err
	}

	columns := service.model.GetColumnNames()
	return &central.GetSlowQueryFieldsResp{
		Columns: columns,
	}, nil
}

func (service *debugPortalService) QuerySlowQueries(ctx context.Context, req *central.QuerySlowQueriesReq) (*central.QuerySlowQueriesResp, error) {
	if err := service.authN(ctx); err != nil {
		return nil, err
	}

	res, err := service.model.Query(req.ClusterId, int(req.Body.BeginTime), int(req.Body.EndTime), req.Body.Db, int(req.Body.Limit), req.Body.Text, req.Body.OrderBy, req.Body.Desc, req.Body.Plans, req.Body.Digest, req.Body.Fields)
	if err != nil {
		return nil, err
	}

	mappedRes := make([]*central.SlowQueryDetails, 0, len(res))
	for _, l := range res {
		mapped := dbModelToResponseModel(&l)
		mappedRes = append(mappedRes, mapped)
	}

	return &central.QuerySlowQueriesResp{Logs: mappedRes}, nil
}

func (service *debugPortalService) GetSlowQueryDetails(ctx context.Context, req *central.GetSlowQueryDetailsReq) (*central.GetSlowQueryDetailsResp, error) {
	if err := service.authN(ctx); err != nil {
		return nil, err
	}

	res, err := service.model.GetDetail(req.ClusterId, req.Id)
	if err != nil {
		return nil, err
	}

	mapped := dbModelToResponseModel(res)

	return &central.GetSlowQueryDetailsResp{Log: mapped}, nil
}

func (service *debugPortalService) GetSlowQueryDatabases(ctx context.Context, req *central.GetSlowQueryDatabasesReq) (*central.GetSlowQueryDatabasesResp, error) {
	if err := service.authN(ctx); err != nil {
		return nil, err
	}

	res, err := service.model.GetDatabases(req.ClusterId, int(req.BeginTime), int(req.EndTime))
	if err != nil {
		return nil, err
	}

	return &central.GetSlowQueryDatabasesResp{Dbs: res}, nil
}

func boolToInt(b bool) int32 {
	if b {
		return 1
	}
	return 0
}

func dbModelToResponseModel(l *slowquery.Log) *central.SlowQueryDetails {
	return &central.SlowQueryDetails{
		Id:                        l.ID,
		Digest:                    l.Digest,
		Query:                     l.Query,
		Instance:                  l.Instance,
		Db:                        l.DB,
		ConnectionId:              l.ConnectionID,
		Success:                   boolToInt(l.Success),
		Timestamp:                 l.Timestamp,
		QueryTime:                 l.QueryTime,
		ParseTime:                 l.ParseTime,
		CompileTime:               l.CompileTime,
		RewriteTime:               l.RewriteTime,
		PreprocSubqueriesTime:     l.PreprocSubqueriesTime,
		OptimizeTime:              l.OptimizeTime,
		WaitTs:                    l.WaitTime,
		CopTime:                   l.CopTime,
		LockKeysTime:              l.LockKeysTime,
		WriteSqlResponseTotal:     l.WriteRespTime,
		ExecRetryTime:             l.ExecRetryTime,
		MemoryMax:                 int32(l.MemoryMax),
		DiskMax:                   int32(l.DiskMax),
		TxnStartTs:                l.TxnStartTS,
		PrevStmt:                  l.PrevStmt,
		Plan:                      l.Plan,
		IsInternal:                boolToInt(l.IsInternal),
		IndexNames:                l.IndexNames,
		Stats:                     l.Stats,
		BackoffTypes:              l.BackoffTypes,
		User:                      l.User,
		Host:                      l.Host,
		ProcessTime:               l.ProcessTime,
		WaitTime:                  l.WaitTime,
		BackoffTime:               l.BackoffTime,
		GetCommitTsTime:           l.GetCommitTSTime,
		LocalLatchWaitTime:        l.LocalLatchWaitTime,
		ResolveLockTime:           l.ResolveLockTime,
		PrewriteTime:              l.PrewriteTime,
		WaitPrewriteBinlogTime:    l.WaitPreWriteBinlogTime,
		CommitTime:                l.CommitTime,
		CommitBackoffTime:         l.CommitBackoffTime,
		CopProcAvg:                l.CopProcAvg,
		CopProcP90:                l.CopProcP90,
		CopProcMax:                l.CopWaitMax,
		CopWaitAvg:                l.CopWaitAvg,
		CopWaitP90:                l.CopWaitP90,
		CopWaitMax:                l.CopWaitMax,
		WriteKeys:                 int32(l.WriteKeys),
		WriteSize:                 int32(l.WriteSize),
		PrewriteRegion:            int32(l.PrewriteRegion),
		TxnRetry:                  int32(l.TxnRetry),
		RequestCount:              int32(l.RequestCount),
		ProcessKeys:               int32(l.ProcessKeys),
		TotalKeys:                 int32(l.TotalKeys),
		CopProcAddr:               l.CopProcAddr,
		CopWaitAddr:               l.CopWaitAddr,
		RocksdbDeleteSkippedCount: int32(l.RocksdbDeleteSkippedCount),
		RocksdbKeySkippedCount:    int32(l.RocksdbKeySkippedCount),
		RocksdbBlockCacheHitCount: int32(l.RocksdbBlockCacheHitCount),
		RocksdbBlockReadCount:     int32(l.RocksdbBlockReadCount),
		RocksdbBlockReadByte:      int32(l.RocksdbBlockReadByte),
	}
}
