require 'openapi_client'
require 'date'
require 'json'
require 'pry'

MONTHS = %w[
  Jan
  Feb
  Mar
  Apr
  May
  Jun
  Jul
  Aug
  Sep
  Oct
  Nov
  Dec
]

BEGIN_YEAR = 2016
CURRENT_YEAR = Date.today.year
YEAR_RANGE = (BEGIN_YEAR..CURRENT_YEAR).to_a

class MicrosoftCvrfClient
  attr_accessor :ids, :api_instance, :api_version, :api_key

  def initialize(api_instance = OpenapiClient::DefaultApi.new, api_version = 'api_version_example', api_key = 'api_key_example')
    @ids = YEAR_RANGE.map { |y| MONTHS.map { |m| "#{y}-#{m}" } }.flatten.reject {|id| id == '2016-Feb' || id == '2016-Mar'}
    @api_instance = api_instance
    @api_version = api_version
    @api_key = api_key
  end

  def get_id(id)
    api_instance.cvrf_id_get(api_version, api_key, id)
  rescue OpenapiClient::ApiError => e
    puts "Exception when calling DefaultApi->cvrf_id_get: #{e}"
  end

  # from 2019 on msft uses @remediations instead of @threats it seems
  def get_remediation_str_for_vuln(vuln)
    vuln.remediations.select { |t| t.type == 1 }.first.description.value
  end

  # THREAT STRING SPECIFIC METHODS
  # response from get_id()
  def cves_threat_strs(response)
    response.vulnerability.map do |vuln| 
      threat_str = get_threat_str_for_vuln(vuln) || get_remediation_str_for_vuln(vuln) #see if this fixes 2019-Feb+
      split_t_str_arr = split_threat_str(threat_str)
      hashed_t_str = threat_str_arr_to_hash(split_t_str_arr)
      vuln_hash = { :cve_id => vuln.cve, :exploitability_info => hashed_t_str }
      threat_str_hash_to_json(vuln_hash)
    end
  end

  def get_threat_str_for_vuln(vuln)
    vuln.threats.select { |t| t.type == 1 }.first.description.value
  end

  def split_threat_str(threat_str)
    threat_str.split(";")
  end

  def threat_str_arr_to_hash(split_threat_str_arr)
    arr_of_hash = split_threat_str_arr.map do |e|
      spl_str = e.split(":")
      k = spl_str[0]
      v = spl_str[1]
      { k => v }
    end
    arr_of_hash.reduce Hash.new, :merge
  end

  def threat_str_hash_to_json(threat_str_hash)
    JSON.parse(threat_str_hash.to_json)
  end

  def exploited_yes_vulns(bulletin_vuln_json)
    bulletin_vuln_json.select do |vuln_info|
      vuln_info["exploitability_info"]["Exploited"] == "Yes"
    end
  end

  def exploitation_detected_vulns(bulletin_vuln_json)
    bulletin_vuln_json.select do |vuln_info|
      exploit_info = vuln_info['exploitability_info']
      check_latest = exploit_info["Latest Software Release"] == "Exploitation Detected"
      check_oldest = exploit_info["Oldest Software Release"] == "Exploitation Detected"
      check_latest || check_oldest
    end
  end

  def exploited_vulns_only(bulletin_id)
    r = get_id(bulletin_id)
    vuln = cves_threat_strs(r)
    exploited_yes = exploited_yes_vulns(vuln)
    exploitation_detected = exploitation_detected_vulns(vuln)
    {
      :bulletin_id => bulletin_id,
      :exploited_yes_cve => exploited_yes,
      :exploitation_detected_cve => exploitation_detected
    }
  end
end

