# frozen_string_literal: true

require 'rspec'

if ENV['CI']
  require 'codeclimate-test-reporter'
  CodeClimate::TestReporter.start
else
  require 'simplecov'
  SimpleCov.start
end

ENV['HIVE_ENVIRONMENT'] ||= 'test'
ENV['HIVE_CONFIG'] = File.expand_path('../configs', __FILE__)
$LOAD_PATH << File.expand_path('../../lib', __FILE__)
$LOAD_PATH << File.expand_path('../helper_lib', __FILE__)

require 'hive'
require 'webmock/rspec'
require 'json'
# ENV['HIVE_CONFIG'] = File.expand_path('../config_with_hivemind', __FILE__)
SPEC_HOME = File.expand_path('..', __FILE__)

# Reset the hive with a new configuration file
def reset_hive(options = {})
  ENV['HIVE_CONFIG'] = File.expand_path(options[:config] || 'config_default', SPEC_HOME)

  Hive.module_eval do
    # Reload settings
    Chamber.load(
      basepath: ENV['HIVE_CONFIG'],
      namespaces: { environment: 'test' }
    )

    # Force reconnection to Hive Mind
    @hive_mind = nil
  end
end

# JSON representations for a device in Hive Mind
def hive_mind_device(options)
  id = options[:id] || 1
  {
    id: id,
    device_type: options[:device_type] || 'Mobile',
    operating_system_name: options[:os] || 'android',
    operating_system_os_name: options[:os_name] || 'Lollipop',
    operating_system_version: options[:os_version] || '1.2.3',
    serial: "serial#{id}",
    model: options[:model] || 'Test Model',
    brand: options[:brand] || 'Test Brand'
  }
end

# Mock Android Device API
def android_device(options)
  id = options[:id] || 1
  dev = DeviceAPI::Android::Device.new(
    serial: "serial#{id}",
    state: 'device',
    version: options[:os_version] || '1.2.3'
  )
  allow(dev).to receive(:wifi_mac_address) { options[:wifi_mac_addresss] || format('00:11:22:33:44:%02d', id) }
  allow(dev).to receive(:ip_address)       { options[:ip_address] || format('192.168.100.%d', id) }
  allow(dev).to receive(:manufacturer)     { options[:brand] || 'Test Brand' }
  allow(dev).to receive(:model)            { options[:model] || 'Test Model' }
  allow(dev).to receive(:type)             { options[:type] || 'Mobile' }
  allow(dev).to receive(:imei)             { options[:imei] || format('123456%d', id) }
  allow(dev).to receive(:version)          { options[:os_version] || '1.2.3' }
  allow(dev).to receive(:os_name)          { options[:os_name] || 'Lollipop' }
  allow(dev).to receive(:get_device_type)  { :default }
  dev.instance_variable_set(:@remote, options[:remote] ? true : false)
  dev
end

# Mock iOS Device API
def ios_device(options)
  id = options[:id] || 1
  dev = DeviceAPI::IOS::Device.new(
    serial: "serial#{id}",
    state: 'device',
    version: options[:os_version] || '1.2.3'
  )
  allow(dev).to receive(:wifi_mac_address) { options[:wifi_mac_addresss] || format('00:11:22:33:44:%02d', id) }
  allow(dev).to receive(:ip_address)       { options[:ip_address] || format('192.168.100.%d', id) }
  allow(dev).to receive(:manufacturer)     { options[:brand] || 'Apple' }
  allow(dev).to receive(:model)            { options[:model] || 'Test Model' }
  allow(dev).to receive(:type)             { options[:type] || 'Mobile' }
  allow(dev).to receive(:imei)             { options[:imei] || format('123456%d', id) }
  allow(dev).to receive(:version)          { options[:os_version] || '1.2.3' }
  allow(dev).to receive(:get_device_type)  { :default }
  dev
end

# Set up mocked devices in Hive Mind and ADB
# Usage:
#
#     mock_devices id: <hive id to set in Hive Mind>,
#                  hm_devices: <list of devices in Hive Mind>,
#                  adb_devices: <list of devices to be detected by ADB>,
#                  mac: <mac address of hive (optional)>,
#                  register_fail: <true = return 500 error on registration>,
#                  poll_fail: <true = return 500 error on poll>
#
# hm_devices and adb_devices are arrays of elements generated by the
# hm_device and adb_device methods defined above.
def mock_devices(options)
  mac = format('11:22:33:44:55:%02d', options[:id])
  escaped_mac = mac.gsub /:/, '%3A'
  allow(Mac).to receive(:addrs) { [mac] }

  if options[:register_fail]
    stub_request(:put, 'http://hivemind/api/devices/update_state.json')
      .to_return(status: 500, body: '{}', headers: {})

    stub_request(:post, 'http://hivemind/api/devices/register.json')
      .with(body: /%5Bmacs%5D%5B%5D=#{escaped_mac}/)
      .to_return(status: 500, body: '', headers: {})
  else
    stub_request(:post, 'http://hivemind/api/devices/register.json')
      .with(body: /%5Bmacs%5D%5B%5D=#{escaped_mac}/)
      .to_return(status: 200, body: { id: options[:id], connected_devices: options[:hm_devices] }.to_json, headers: {})

    stub_request(:put, 'http://hivemind/api/devices/poll.json')
      .with(body: /%5Bdevice_id%5D=#{options[:id]}/)
      .to_return(status: 200, body: '{}', headers: {})

    stub_request(:put, 'http://hivemind/api/devices/update_state.json')
      .with(body: /%5Bdevice_id%5D=#{options[:id]}/)
      .to_return(status: 200, body: '{}', headers: {})

  end

  if options[:poll_fail]
    stub_request(:put, 'http://hivemind/api/devices/poll.json')
      .with(body: /id%5D=#{options[:id]}/)
      .to_return(status: 500, body: '{}', headers: {})
  else
    stub_request(:put, 'http://hivemind/api/devices/poll.json')
      .with(body: /id%5D=#{options[:id]}/)
      .to_return(status: 200, body: { connected_devices: options[:hm_devices] }.to_json, headers: {})
  end
  allow(DeviceAPI::Android).to receive(:devices) { options[:adb_devices] }
end

RSpec.configure do |config|
  config.before(:each) do
    stub_request(:post, 'http://hivemind/api/device_statistics/upload.json')
      .to_return(status: 200, body: '{}', headers: {})

    stub_request(:put, 'http://hivemind/api/plugin/hive/connect.json')
      .to_return(status: 200, body: '{}', headers: {})
  end
end

require 'hive/log'
module Hive
  class Log
    def info(msg); end

    def warn(msg); end

    def debug(msg); end

    def fatal(msg); end

    def unknown(msg); end

    def error(msg); end

    def clear(msg); end
  end
end
