package central

import (
	"context"
	"encoding/json"
	"fmt"
	"message-service/commons/config"
	"message-service/commons/grpc"
	"message-service/commons/httpclient"
	"message-service/internal/bean/dto"
	"net/http"
	"time"

	"github.com/tidbcloud/dataservices/idl/pbgen/proto/dataapi"
	"github.com/tidbcloud/tiinf/errs"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/patrickmn/go-cache"
)

const (
	sqlEditorGetMetaPathFormatter = "/api/v1/dataapps/sqleditor/orgs/%s/projects/%s/clusters/%s/dbs/%s/%s/meta"
	sqlEditorColumnsCacheKey      = "columns|%s|%s|%s|%s|%s"
	sqlEditorDatabaseCacheKey     = "database|%s|%s|%s"
)

var columnsCache = cache.New(15*time.Minute, 60*time.Second)

func GetSqlEditorTableColumns(ctx context.Context, param *dto.SqlEditorGetColumnParam) ([]string, error) {
	cacheKey := fmt.Sprintf(sqlEditorColumnsCacheKey, param.OrgID, param.ProjectID, param.ClusterID, param.DbName, param.TableName)
	cachedColumns, exist := columnsCache.Get(cacheKey)
	if exist {
		columns, ok := cachedColumns.([]string)
		if ok {
			return columns, nil
		}
	}

	columns, err := DoGetSqlEditorTableColumns(ctx, param)
	if err != nil {
		return columns, err
	}

	columnsCache.SetDefault(cacheKey, columns)

	return columns, nil

}

func DoGetSqlEditorTableColumns(ctx context.Context, param *dto.SqlEditorGetColumnParam) ([]string, error) {
	tilog.Info(ctx, "get sql editor table columns request", zap.Any("param", param))

	path := fmt.Sprintf(sqlEditorGetMetaPathFormatter, param.OrgID, param.ProjectID, param.ClusterID, param.DbName, param.TableName)
	url := config.Global().MessageSvcConf.SqlEditorEndpoint + path

	body, code, err := httpclient.Get(url)

	tilog.Info(ctx, "get sql editor table columns response", zap.Int("'code", code), zap.String("body", body), zap.Any("err", err))

	if err != nil || code != http.StatusOK {
		tilog.Error(ctx, "get sql editor table columns response error", zap.Any("err", err))
		return nil, errs.ErrInternalHTTP
	}
	var result dto.SqlEditorGetColumnResult
	err = json.Unmarshal([]byte(body), &result)
	if err != nil {
		tilog.Error(ctx, "get sql editor table columns unmarshal body error", zap.String("body", body), zap.Any("err", err))
		return nil, err
	}
	if result.Code != http.StatusOK {
		tilog.Error(ctx, "get sql editor table columns return biz failed", zap.String("body", body))
		return nil, errs.ErrInternalHTTP
	}

	dataColumns := result.Data.Columns
	var retColumns []string
	for _, column := range dataColumns {
		retColumns = append(retColumns, column.Col)
	}

	return retColumns, nil
}

func getSqlEditorClusterColumns(ctx context.Context, projectID uint64, clusterID uint64) ([]*dataapi.TableMeta, error) {
	req := &dataapi.GetClusterMetaReq{
		ProjectId: projectID,
		ClusterId: clusterID,
	}
	resp, err := grpc.GetClusterMeta(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp.GetMetas(), nil
}
func getSqlEditorDatabaseColumns(ctx context.Context, projectID uint64, clusterID uint64, database string) ([]*dataapi.TableMeta, error) {
	req := &dataapi.GetDatabaseMetaReq{
		ProjectId: projectID,
		ClusterId: clusterID,
		Database:  database,
	}
	resp, err := grpc.GetDatabaseMeta(ctx, req)
	if err != nil {
		return nil, err
	}
	return resp.GetMetas(), nil
}
