// fixme(xuyifan02): slowquery storage

package debug

import (
	"fmt"
	"sort"
	"strconv"
	"strings"

	"github.com/pingcap/dbaas/central/model/debug/slowquery"
)

const timestampKey = "timestamp"

// GetColumnNames return keys of json query body
func (m *Model) GetColumnNames() []string {
	res := make([]string, 0, len(slowquery.ColumnNames))
	for c := range slowquery.ColumnNames {
		res = append(res, c)
	}
	sort.Strings(res)
	return res
}

func (m *Model) Query(clusterID uint64, beginTime int, endTime int, db []string, limit int, text string, orderBy string, isDesc bool, plans []string, digest string, fields string) ([]slowquery.Log, error) {
	//reqFields := strings.Split(fields, ",")
	//selectStmt, err := genSelectColumns(reqFields)
	//if err != nil {
	//	return nil, err
	//}
	//
	//slowQueryTable := genTableName(clusterID)
	//
	//tx := m.slowQueryDB.
	//	Table(slowQueryTable).
	//	Select(selectStmt).
	//	Where("`Time` >= FROM_UNIXTIME(?) AND `Time` <= FROM_UNIXTIME(?)", beginTime, endTime)
	//
	//if limit > 0 {
	//	tx = tx.Limit(limit)
	//}
	//
	//if text != "" {
	//	lowerStr := strings.ToLower(text)
	//	arr := strings.Fields(lowerStr)
	//	for _, v := range arr {
	//		tx = tx.Where(
	//			"CAST(`Txn_start_ts` AS CHAR) REGEXP ? OR LOWER(`Digest`) REGEXP ? OR LOWER(CONVERT(`Prev_stmt` USING utf8)) REGEXP ? OR LOWER(CONVERT(`Query` USING utf8)) REGEXP ?",
	//			v, v, v, v,
	//		)
	//	}
	//}
	//
	//if len(db) > 0 {
	//	tx = tx.Where("`DB` IN (?)", db)
	//}
	//
	//if orderBy == "" {
	//	orderBy = timestampKey
	//}
	//
	//orderStmt, err := genOrderStmt(orderBy, isDesc)
	//if err != nil {
	//	return nil, err
	//}
	//
	//tx = tx.Order(orderStmt)
	//
	//if len(plans) > 0 {
	//	tx = tx.Where("`Plan_digest` IN (?)", plans)
	//}
	//
	//if len(digest) > 0 {
	//	tx = tx.Where("`Digest` = ?", digest)
	//}
	//
	//var results []slowquery.Log
	//err = tx.Find(&results).Error
	//if err != nil {
	//	return nil, err
	//}

	return []slowquery.Log{}, nil
}

func (m *Model) GetDetail(clusterID, id uint64) (*slowquery.Log, error) {
	//var result slowquery.Log
	//slowQueryTable := genTableName(clusterID)
	//var selectStatements []string
	//for _, s := range slowquery.SelectColumns {
	//	selectStatements = append(selectStatements, s)
	//}
	//err := m.slowQueryDB.
	//	Table(slowQueryTable).
	//	Select(strings.Join(selectStatements, ",")).
	//	Where("`id` = ?", id).
	//	First(&result).Error
	//if err != nil {
	//	return nil, err
	//}

	return &slowquery.Log{}, nil
}

func (m *Model) GetDatabases(clusterID uint64, beginTime int, endTime int) ([]string, error) {
	//// since distinct query is quite slow in mysql, and we have tiflash, thus we use group by here
	//var res []string
	//slowQueryTable := genTableName(clusterID)
	//err := m.slowQueryDB.
	//	Table(slowQueryTable).
	//	Select("`DB`").
	//	Where("`Time` BETWEEN FROM_UNIXTIME(?) AND FROM_UNIXTIME(?)", beginTime, endTime).
	//	Where("`DB` IS NOT NULL").
	//	Group(`DB`).
	//	Find(&res).Error
	//if err != nil {
	//	return nil, err
	//}

	return []string{}, nil
}

//nolint
func genSelectColumns(reqJSONColumns []string) (string, error) {
	if len(reqJSONColumns) < 1 || reqJSONColumns[0] != "*" {
		// Must have "id" column and "timestamp" column.
		reqJSONColumns = append(reqJSONColumns, "id", timestampKey)
	}

	jsonColumns := map[string]struct{}{}
	for _, reqJSONColumn := range reqJSONColumns {
		if _, exists := slowquery.ColumnNames[reqJSONColumn]; exists {
			jsonColumns[reqJSONColumn] = struct{}{}
		}
	}
	if len(jsonColumns) == 0 {
		return "", fmt.Errorf("invalid columns, columns: %q", reqJSONColumns)
	}

	res := make([]string, 0, len(jsonColumns))
	for c := range jsonColumns {
		res = append(res, slowquery.SelectColumns[c])
	}

	return strings.Join(res, ","), nil
}

//nolint
func genTableName(clusterID uint64) string {
	return "tidb" + strconv.FormatUint(clusterID, 10)
}

//nolint
func genOrderStmt(orderBy string, isDesc bool) (string, error) {
	var order string
	// to handle the special case: timestamp
	// Order by column instead of expression, see related optimization in TiDB: https://github.com/pingcap/tidb/pull/20750
	if orderBy == timestampKey {
		order = "Time"
	} else {
		if _, exists := slowquery.ColumnNames[orderBy]; !exists {
			return "", fmt.Errorf("invalid columns, column: %q", orderBy)
		}
		order = slowquery.ColumnNames[orderBy]
	}

	if isDesc {
		order = fmt.Sprintf("`%s` DESC", order)
	} else {
		order = fmt.Sprintf("`%s` ASC", order)
	}

	return order, nil
}
