package log

import (
	"regexp"

	"github.com/pingcap/errors"
	"github.com/pingcap/tidb/util/execdetails"

	"github.com/pingcap-inc/clinic/pkg/slow_query/variable"
)

//nolint:varcheck
var (
	// delimiterRE tokenizes the following string into walkable with extracted delimiter + key.
	// string:
	// ` %{key}, %{key/2}`
	// into:
	// [["", "key" ], [", ", "key/2"]]
	ordinalIndicator     = "/"
	fixedLengthIndicator = "#"

	skipFieldPrefix      = "?"
	appendFieldPrefix    = "+"
	indirectFieldPrefix  = "&"
	appendIndirectPrefix = "+&"
	indirectAppendPrefix = "&+"
	greedySuffix         = "->"
	pointerFieldPrefix   = "*"
	dataTypeIndicator    = "|"
	dataTypeSeparator    = "\\|" // Needed for regexp

	numberRE = "\\d{1,2}"
	alphaRE  = "[[:alpha:]]*"

	delimiterRE = regexp.MustCompile(`(?s)(.*?)%\{([^}]*?)}`)
	suffixRE    = regexp.MustCompile("(.+?)" + // group 1 for key name
		"(" + ordinalIndicator + "(" + numberRE + ")" + ")?" + // group 2, 3 for ordinal
		"(" + fixedLengthIndicator + "(" + numberRE + ")" + ")?" + // group 4, 5 for fixed length
		"(" + greedySuffix + ")?" + // group 6 for greedy
		"(" + dataTypeSeparator + "(" + alphaRE + ")?" + ")?$") // group 7,8 for data type separator and data type

	defaultJoinString = " "

	errParsingFailure            = errors.New("parsing failure")
	errInvalidTokenizer          = errors.New("invalid dissect tokenizer")
	errEmpty                     = errors.New("empty string provided")
	errMixedPrefixIndirectAppend = errors.New("mixed prefix `&+`")
	errMixedPrefixAppendIndirect = errors.New("mixed prefix `&+`")
	errEmptyKey                  = errors.New("empty key")
	errInvalidDatatype           = errors.New("invalid data type")
	errMissingDatatype           = errors.New("missing data type")
)

type LogType string

//nolint:varcheck
const (
	timestamp = "timestamp"

	level = "level"

	message = "msg"

	standardType   LogType = "log"
	tiflashErrType LogType = "tiflashErr"
	stderrType     LogType = "stderr"
	slowQueryType  LogType = "slowquery"
)

var SlowQueryFullCols = []string{
	variable.SlowLogTimeStr,
	variable.SlowLogTxnStartTSStr,
	variable.SlowLogUserStr,
	variable.SlowLogHostStr,
	variable.SlowLogConnIDStr,
	variable.SlowLogExecRetryCount,
	variable.SlowLogExecRetryTime,
	variable.SlowLogQueryTimeStr,
	variable.SlowLogParseTimeStr,
	variable.SlowLogCompileTimeStr,
	variable.SlowLogRewriteTimeStr,
	variable.SlowLogPreprocSubQueriesStr,
	variable.SlowLogPreProcSubQueryTimeStr,
	variable.SlowLogOptimizeTimeStr,
	variable.SlowLogWaitTSTimeStr,
	execdetails.PreWriteTimeStr,
	execdetails.WaitPrewriteBinlogTimeStr,
	execdetails.CommitTimeStr,
	execdetails.GetCommitTSTimeStr,
	execdetails.CommitBackoffTimeStr,
	execdetails.BackoffTypesStr,
	execdetails.ResolveLockTimeStr,
	execdetails.LocalLatchWaitTimeStr,
	execdetails.WriteKeysStr,
	execdetails.WriteSizeStr,
	execdetails.PrewriteRegionStr,
	execdetails.TxnRetryStr,
	execdetails.CopTimeStr,
	execdetails.ProcessTimeStr,
	execdetails.WaitTimeStr,
	execdetails.BackoffTimeStr,
	execdetails.LockKeysTimeStr,
	execdetails.RequestCountStr,
	execdetails.TotalKeysStr,
	execdetails.ProcessKeysStr,
	execdetails.RocksdbDeleteSkippedCountStr,
	execdetails.RocksdbKeySkippedCountStr,
	execdetails.RocksdbBlockCacheHitCountStr,
	execdetails.RocksdbBlockReadCountStr,
	execdetails.RocksdbBlockReadByteStr,
	variable.SlowLogDBStr,
	variable.SlowLogIndexNamesStr,
	variable.SlowLogIsInternalStr,
	variable.SlowLogDigestStr,
	variable.SlowLogStatsInfoStr,
	variable.SlowLogCopProcAvg,
	variable.SlowLogCopProcP90,
	variable.SlowLogCopProcMax,
	variable.SlowLogCopProcAddr,
	variable.SlowLogCopWaitAvg,
	variable.SlowLogCopWaitP90,
	variable.SlowLogCopWaitMax,
	variable.SlowLogCopWaitAddr,
	variable.SlowLogMemMax,
	variable.SlowLogDiskMax,
	variable.SlowLogKVTotal,
	variable.SlowLogPDTotal,
	variable.SlowLogBackoffTotal,
	variable.SlowLogWriteSQLRespTotal,
	variable.SlowLogResultRows,
	variable.SlowLogBackoffDetail,
	variable.SlowLogPrepared,
	variable.SlowLogSucc,
	variable.SlowLogIsExplicitTxn,
	variable.SlowLogPlanFromCache,
	variable.SlowLogPlanFromBinding,
	variable.SlowLogPlan,
	variable.SlowLogPlanDigest,
	variable.SlowLogPrevStmt,
	variable.SlowLogQuerySQLStr,
	variable.SlowLogBinaryPlan,
	// TableTiDBHotRegionsCols
}

func SlowQueryFullColsLookup() map[string]int {
	lookup := make(map[string]int)
	for idx, col := range SlowQueryFullCols {
		lookup[col] = idx
	}
	return lookup
}

var (
	// es index definition for normal log
	//nolint:misspell
	logmapping = `{
  "settings": {
    "number_of_shards": 2
  },
  "mappings": {
    "properties": {
      "cluster_id": {
        "type": "keyword",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "level": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword", "ignore_above": 256}
        }
      },
      "message": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword", "ignore_above": 256}
        }
      },
      "component": {
        "type": "keyword"
      },
      "type": {
        "type": "keyword"
      },
      "host": {
        "type": "keyword"
      },
      "instanceid": {
        "type": "keyword"
      },
      "packageid": {
        "type": "keyword"
      },
      "timestamp": {
        "type": "date"
      },
      "filename": {
        "type": "keyword"
      }
    }
  }
}`
	// es index definition for slow query log
	// only include part of the fields.
	//nolint:misspell
	SlowQueryLogMapping = `{
  "settings": {
    "number_of_shards": 1
  },
  "mappings": {
    "properties": {
      "cluster_id": {
        "type": "keyword",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "message": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword", "ignore_above": 256}
        }
      },
      "digest": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "backoff_time": {
        "type": "float"
      },
      "backoff_types": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "commit_backoff_time": {
        "type": "float"
      },
      "commit_time": {
        "type": "float"
      },
      "connection_id": {
        "type": "long"
      },
      "cop_proc_addr": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "cop_proc_avg": {
        "type": "float"
      },
      "cop_proc_max": {
        "type": "float"
      },
      "cop_proc_p90": {
        "type": "float"
      },
      "cop_time": {
        "type": "float"
      },
      "cop_wait_addr": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "cop_wait_avg": {
        "type": "float"
      },
      "cop_wait_max": {
        "type": "float"
      },
      "cop_wait_p90": {
        "type": "float"
      },
      "disk_max": {
        "type": "long"
      },
      "exec_retry_time": {
        "type": "float"
      },
      "get_commit_ts_time": {
        "type": "float"
      },
      "index_names": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "is_internal": {
        "type": "long"
      },
      "local_latch_wait_time": {
        "type": "float"
      },
      "lock_keys_time": {
        "type": "float"
      },
      "memory_max": {
        "type": "long"
      },
      "optimize_time": {
        "type": "float"
      },
      "parse_time": {
        "type": "float"
      },
      "plan": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "preproc_subqueries_time": {
        "type": "float"
      },
      "prev_stmt": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "prewrite_region": {
        "type": "long"
      },
      "prewrite_time": {
        "type": "float"
      },
      "process_keys": {
        "type": "long"
      },
      "process_time": {
        "type": "float"
      },
      "query": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "query_time": {
        "type": "float"
      },
      "request_count": {
        "type": "long"
      },
      "resolve_lock_time": {
        "type": "float"
      },
      "rewrite_time": {
        "type": "float"
      },
      "rocksdb_block_cache_hit_count": {
        "type": "long"
      },
      "rocksdb_block_read_byte": {
        "type": "long"
      },
      "rocksdb_delete_skipped_count": {
        "type": "long"
      },
      "rocksdb_key_skipped_count": {
        "type": "long"
      },
      "stats": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "success": {
        "type": "long"
      },
      "total_keys": {
        "type": "long"
      },
      "txn_retry": {
        "type": "long"
      },
      "txn_start_ts": {
        "type": "keyword",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "user": {
        "type": "keyword",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "wait_prewrite_binlog_time": {
        "type": "float"
      },
      "wait_time": {
        "type": "float"
      },
      "wait_ts": {
        "type": "float"
      },
      "write_keys": {
        "type": "long"
      },
      "write_size": {
        "type": "long"
      },
      "write_sql_response_total": {
        "type": "float"
      },
      "db": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "plan_digest": {
        "type": "text",
        "fields": {
          "keyword": {"type": "keyword","ignore_above": 512}
        }
      },
      "component": {
        "type": "keyword"
      },
      "type": {
        "type": "keyword"
      },
      "host": {
        "type": "keyword"
      },
      "instanceid": {
        "type": "keyword"
      },
      "packageid": {
        "type": "keyword"
      },
      "timestamp": {
        "type": "date"
      }
    }
  }
}`
)
