require_relative "config/environment"
require "pp"

FN = Rails.root.join("public/json/jumbotron.json").to_s
puts "hello world, running jumbotron data collection, ouptut will be saved at: " + FN

H168 = 168
D100 = 100
D30 = 30
M60 = 60
DAY_ZERO = Time.parse("2020-02-20 00:00:00 +0800") #this day, we created SA/FA 2 stages.
HASH50 = "#" * 50
HASH52 = "#" * 52
SHOW_NUM_FALUTS = 20
$old_dts_count = 0
$old_dths_count = 0
$output = {}

def _parse_dth_log(dth)
  if dth.log[0] == "M" #FA
    errors = dth.log.split(HASH50)[2].strip().split("\n").drop(1)
    return errors.map { |x| "FA|" + x }
  else #SA #chinese
    if dth.log[0] == "#" #old format
      offset = 1
    else
      offset = 0
    end
    errors = dth.log.split(HASH52)[3 + offset].strip().split("\n").drop(1)
    return errors.map { |x| "SA|" + x }
  end
end

def calc_dths
  last14days_errors = {}
  the_date = Time.zone.now - 14.day
  #puts the_date
  dths = DeviceTestHistory.where("test_type=0 or test_type=3").where(created_at: the_date.beginning_of_day..Time.zone.now.end_of_day)

  dths.each do |dth|
    res = _parse_dth_log(dth)
    res.each do |key|
      if last14days_errors[key].nil?
        last14days_errors[key] = 1
      else
        last14days_errors[key] += 1
      end
    end
  end
  sorted = last14days_errors.sort_by { |x, y| [y, x] }
  last14days_errors_names = []
  last14days_errors_values = []
  sorted.each_with_index do |pair, i|
    last14days_errors_names[i] = pair[0]
    last14days_errors_values[i] = pair[1]
  end

  $output["last14days_errors_names"] = last14days_errors_names[0..SHOW_NUM_FALUTS]
  $output["last14days_errors_values"] = last14days_errors_values[0..SHOW_NUM_FALUTS]
end

def calc_pings
  if $output["pings"].nil?
    $output["pings"] = {}
    $output["pings"]["dates"] = []
    $output["pings"]["count"] = []
    $output["pings"]["dau"] = []
    $output["pings"]["daip"] = []
  end
  $output["today_dau"] = "undef"
  $output["today_daip"] = "undef"
  $output["today_ping_counts"] = "undef"

  #diff time: pings.uniq{|p| p.mac}.filter{|p| (p.created_at-p.hwtime).abs > 10}.each{|p| puts p.mac.to_s+" " + p.request_ip.to_s + " " +  (p.created_at-p.hwtime).to_s}
  0.upto(D30 - 1) do |i|
    the_date = Time.now - i.day
    date_key = the_date.strftime("%Y-%m-%d").to_s
    puts date_key + " process pings"
    if (not $output["pings"]["dates"].include? date_key) or i == 0
      $output["pings"]["dates"][i] = date_key
      pings = DeviceLogHistory.where(created_at: the_date.beginning_of_day..the_date.end_of_day)
      $output["pings"]["count"][i] = pings.count
      $output["pings"]["dau"][i] = pings.uniq { |p| p.mac }.count
      $output["pings"]["daip"][i] = pings.uniq { |p| p.request_ip }.count
    end

    if i == 0 and pings.count > 0
      today_macs = pings.uniq { |p| p.mac }
      $output["today_macs"] = today_macs.map { |q| q.mac }
      $output["today_dau"] = $output["today_macs"].count
      $output["today_ips"] = pings.uniq { |p| p.request_ip }.map { |q| q.request_ip }
      $output["today_daip"] = $output["today_ips"].count
      $output["today_ping_counts"] = $output["pings"]["count"][0]
      $output["today_ips"] = {}
      today_macs.each do |p|
        if $output["today_ips"][p.request_ip].nil?
          $output["today_ips"][p.request_ip] = 0
        end
        $output["today_ips"][p.request_ip] += 1
      end
    end
  end
end

def calc_dts
  #init zeros
  weekly_heatmap = Array.new(7) { Array.new(24, 0) }
  hours_barchart = Array.new(24, 0)
  wday_barchart = Array.new(7, 0)
  hundred_hours_barchart = Array.new(H168, 0)
  last100days = Array.new(D100, 0)
  last100days_dates = Array.new(D100, 0)
  last30days_dates = Array.new(D30, 0)
  last60months = Array.new(M60, 0)
  last60months_months = Array.new(M60, 0)
  last30day_sa0 = Array.new(D30, 0)
  last30day_sa1 = Array.new(D30, 0)
  last30day_fa0 = Array.new(D30, 0)
  last30day_fa1 = Array.new(D30, 0)
  last30day_sa1_ratio = Array.new(D30, 0)
  last30day_fa1_ratio = Array.new(D30, 0)

  all_dts = DeviceTestHistory.distinct
  dts = DeviceTest.where(created_at: DAY_ZERO..Time.zone.now.end_of_day).all
  today_dts = DeviceTestHistory.where(created_at: Time.zone.now.beginning_of_day..Time.zone.now.end_of_day)
  week_dts = DeviceTestHistory.where(created_at: Time.zone.now.beginning_of_week..Time.zone.now.end_of_day)
  month_dts = DeviceTestHistory.where(created_at: Time.zone.now.beginning_of_month..Time.zone.now.end_of_day)

  # After 2020-3-31, mac is uniqueness records in device_tests table
  $output["grand_uniq_mac_count"] = DeviceTest.distinct.count('mac')
  $output["count"] = DeviceTest.distinct.count('mac') # FIXEME: Not found 'count' usage anywhere.
  $output["all_sa_count"] =  DeviceTestHistory.where("sn=?", "SA").distinct.count('mac')
  $output["all_fa_count"] = DeviceTestHistory.where("sn<>?", "SA").distinct.count('mac')
  $output["month_sa_count"] = month_dts.distinct.where("sn=?", "SA").count('mac')
  $output["month_fa_count"] = month_dts.distinct.where("sn<>?", "SA").count('mac')
  $output["week_sa_count"] = week_dts.distinct.where("sn=?", "SA").count('mac')
  $output["week_fa_count"] = week_dts.distinct.where("sn<>?", "SA").count('mac')
  $output["today_sa_count"] = today_dts.distinct.where("sn=?", "SA").count('mac')
  $output["today_fa_count"] = today_dts.distinct.where("sn<>?", "SA").count('mac')

  now = Time.new
  d = Date.today
  all_dts.each do |dt|
    #puts dt.created_at
    hour = dt.created_at.hour
    wday = dt.created_at.wday
    diff_months = ((now.year - dt.created_at.year) * 12 + (now.month - dt.created_at.month)).to_i
    diff_days = (Date.parse(now.to_s) - Date.parse(dt.created_at.strftime("%Y-%m-%d"))).to_i
    diff_hours = ((now - dt.created_at) / 3600).to_i

    if diff_hours < H168
      hundred_hours_barchart[H168 - diff_hours - 1] += 1
    end

    if diff_days < D100
      last100days[D100 - diff_days - 1] += 1
    end

    if diff_days < D30
      if dt.sn.downcase == "sa" and dt.result == 0
        last30day_sa0[diff_days] += 1
      elsif dt.sn.downcase == "sa" and dt.result > 0
        last30day_sa1[diff_days] += 1
      elsif dt.sn.downcase != "sa" and dt.result == 0
        last30day_fa0[diff_days] += 1
      elsif dt.sn.downcase != "sa" and dt.result > 0
        last30day_fa1[diff_days] += 1
      end
    end

    if diff_months < M60
      last60months[M60 - diff_months - 1] += 1
    end

    weekly_heatmap[wday][hour] += 1
    hours_barchart[hour] += 1
    wday_barchart[wday] += 1
  end

  0.upto(D100 - 1) do |i|
    last100days_dates[i] = (d - D100 + 1 + i).to_s
  end

  0.upto(D30 - 1) do |i|
    last30days_dates[i] = (d - D30 + 1 + i).to_s

    if (last30day_sa0[i] + last30day_sa1[i]) == 0
      last30day_sa1_ratio[i] = 0.0
    else
      last30day_sa1_ratio[i] = ((last30day_sa1[i].to_f / (last30day_sa0[i].to_f + last30day_sa1[i].to_f)) * 100.0).round(1)
    end

    if (last30day_fa0[i] + last30day_fa1[i]) == 0
      last30day_fa1_ratio[i] = 0.0
    else
      last30day_fa1_ratio[i] = ((last30day_fa1[i].to_f / (last30day_fa0[i].to_f + last30day_fa1[i].to_f)) * 100.0).round(1)
    end
  end

  0.upto(M60 - 1) do |i|
    last60months_months[i] = (d.prev_month(M60 + 1 - i)).to_s
  end

  $output["created_at"] = Time.now
  $output["weekly_heatmap"] = weekly_heatmap
  $output["hours_barchart"] = hours_barchart
  $output["wday_barchart"] = wday_barchart
  $output["hundred_hours_barchart"] = hundred_hours_barchart
  $output["last100days"] = last100days
  $output["last100days_dates"] = last100days_dates
  $output["last60months"] = last60months
  $output["last60months_months"] = last60months_months
  $output["last30days_dates"] = last30days_dates.reverse
  $output["last30day_sa0"] = last30day_sa0
  $output["last30day_sa1"] = last30day_sa1
  $output["last30day_fa0"] = last30day_fa0
  $output["last30day_fa1"] = last30day_fa1
  $output["last30day_sa1_ratio"] = last30day_sa1_ratio
  $output["last30day_fa1_ratio"] = last30day_fa1_ratio
  $output["last_25_items"] = dts.last(300).reverse
end

if __FILE__ == $0
  Process.daemon if ARGV.include?("-D")
  old_pid = File.read("/tmp/ascleway_bg_data_cal.pid").to_i rescue 0
  if old_pid > 0
    begin
      Process.kill("QUIT", old_pid)
      puts "Kill old running daemon."
    rescue Errno::ESRCH
      puts "No such process to kill."
    end
  end

  File.open("/tmp/ascleway_bg_data_cal.pid", "w") do |f|
    f.puts "#{Process.pid}"
  end
  old_json = ""
  $output = {}
  idx = 0
  while true
    calc_dts()
    calc_dths()
    if idx % 10 == 1 #every 0
      calc_pings()
    end
    new_json = $output.to_json

    if new_json != old_json
      puts new_json
      old_json = new_json
      file = File.open(FN, "w")
      file.puts(new_json)
      file.close
    else
      puts "no change in json"
    end

    idx += 1
    sleep(60)
  end
end
