#!/usr/bin/env ruby
# SPDX-License-Identifier: MulanPSL-2.0+
# Copyright (c) 2020 Huawei Technologies Co., Ltd. All rights reserved.
# frozen_string_literal: true

# Usage:
#       es-find key=val ...
#       es-find -r "start_time=2021-01-01T00:00:00+0800,2021-01-01T23:59:59+0800;..."
#       es-find tbox_group=vm-2p8g -c suite,job_state
# if given multi keys, they create AND conditions
# if given val1,val2,... for a key, they create OR conditions
# Eg: query (testbox is xxx or yyy) and (suite is aaa) and (user is bbb).
#       es-find testbox=xxx,yyy suite=aaa user=bbb

require 'yaml'
require 'optparse'
require 'json'
require_relative '../lib/es_query.rb'
require_relative '../container/defconfig.rb'
require_relative '../lib/constants.rb'

def parse_argv
  items = {}
  ARGV.each do |item|
    key, value = item.split('=')
    if key && value
      value_list = value.split(',')
      items[key] = value_list.length > 1 ? value_list : value
    end
  end
  items
end

# output:
#   eg:
#   {
#     start_time => {
#       gte: '2020-09-10T01:50:00+0800',
#       lte: '2020-09-10T01:53:00+0800'
#     },
#     ...
#   }
def prase_range(range)
  range_hash = {}
  keyword_list = range.split(';')
  keyword_list.each do |keyword|
    key, value = keyword.split('=')
    check_range_args(key, value)
    range_hash[key] = assign_range(value)
  end

  range_hash
end

def check_range_args(key, value)
  unless key && value
    warn "error: range value of \"#{key}\" missing", "tips: should give the input of -r like:
    \"#{key}=2021-01-01T00:00:00+0800,2021-01-01T23:59:59+0800\" "
    exit
  end
  unless value =~ /^\d+-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d+/
    warn "error: incorrect format \"#{key}=#{value}\"", "tips: should give the input of -r like:
    \"#{key}=2021-01-01T00:00:00+0800,2021-01-01T23:59:59+0800\" "
    exit
  end
end

def assign_range(value)
  range_value = {}
  value_list = value.split(',')
  if value_list.length > 1
    range_value[:gte] = value_list[0]
    range_value[:lte] = value_list[1]
  else
    range_value[:gte] = value
  end

  range_value
end

options = { nr_jobs: 10, desc_keyword: 'start_time' }
range = nil
count = nil

es = ESQuery.new(ES_HOSTS)

opt_parser = OptionParser.new do |opts|
  opts.banner = 'Usage: es-find [options] search_key1=val1[,val2..] ..'

  opts.separator 'search_key can be id, suite, os, etc.'
  opts.separator ''

  opts.on('-n', '--nr-jobs NUM', Integer, 'max jobs, default 10.') do |n|
    if n.to_i <= 0
      puts 'The value of the -n option must be a positive number.'
      exit(-1)
    end
    options[:nr_jobs] = n.to_i
  end

  opts.on('-d', '--desc-keyword KEYWORD', 'order by keyword: start_time|end_time|...') do |d|
    options[:desc_keyword] = d
  end

  opts.on('-r', '--range KEYWORD', 'range by keyword: start_time|end_time|...') do |r|
    range = r
  end

  opts.on('-c', '--count KEYWORD', 'count keyword: suite|job_state|testbox|id|...') do |c|
    count = c
  end

  opts.on('--reg', 'fuzzy matching') do
    options[:regexp] = true
  end

  opts.on_tail('--keyword', 'check all available search_keys') do
    available_search_key = es.query_mapping
    available_search_key.each do |key|
      puts "    #{key}"
    end
    exit
  end

  opts.on_tail('-h', '--help', 'show this message') do
    puts opts
    exit
  end
end

opt_parser.parse!(ARGV)
items = parse_argv
items[:range] = prase_range(range) if range

if count
  count_keywords = count.split(',')
  query_result = es.query_fields(count_keywords, items)
else
  query_result = es.multi_field_query(
    items,
    size: options[:nr_jobs],
    desc_keyword: options[:desc_keyword],
    regexp: options[:regexp]
  )
end
json_string = JSON.pretty_generate(query_result)
puts json_string
