require 'net/http'
require 'uri'
require 'json'
require 'securerandom'

class LibreAuth
  attr_accessor :name, :owner_id, :version, :url, :session_id, :enckey, :hash

  def initialize(name, owner_id, version, url)
    @name = name
    @owner_id = owner_id
    @version = version
    @url = url.sub(%r{/$}, '') + '/'
    @session_id = nil
    @enckey = nil
    @hash = ''
  end

  def init(enckey = nil)
    @enckey = (enckey || SecureRandom.hex(18))[0, 35]
    res = req('type' => 'init', 'ver' => @version, 'enckey' => @enckey, 'hash' => @hash)
    raise res['message'] unless res['success']
    @session_id = res['sessionid']
    res
  end

  def login(user, pass, hwid = '')
    auth('type' => 'login', 'username' => user, 'pass' => pass, 'hwid' => hwid)
  end

  def license(key, hwid = '')
    auth('type' => 'license', 'key' => key, 'hwid' => hwid)
  end

  def register(user, pass, key, hwid = '')
    auth('type' => 'register', 'username' => user, 'pass' => pass, 'key' => key, 'hwid' => hwid)
  end

  private

  def auth(extra)
    res = req(extra)
    raise res['message'] unless res['success']
    res['info'] || res
  end

  def req(extra)
    data = extra.merge('name' => @name, 'ownerid' => @owner_id)
    data['sessionid'] = @session_id if @session_id
    uri = URI(@url)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'
    http.open_timeout = 30
    http.read_timeout = 30
    req = Net::HTTP::Post.new(uri)
    req.set_form_data(data)
    res = http.request(req)
    raise 'Rate limited' if res.code.to_i == 429
    JSON.parse(res.body)
  end
end
