require_relative 'helper'

class MxHeroAPITest < MiniTest::Unit::TestCase

  def setup
    @api = MxHero::API::Client.new(username: TEST_API_USER, password: TEST_API_PASSWORD, verbose: false, api_url: TEST_API_URL)
  end

  def domain
    TEST_API_DOMAIN
  end

  def test_verbose
    api = MxHero::API::Client.new
    assert ! api.verbose?, 'Verbose is false by default'

    api.verbose = true
    assert api.verbose?, 'Verbose state must be changed'
  end

  def test_update_rule
    VCR.use_cassette('update_rule') do
      rules = obtain_rules(domain)
      existing_rule = rules.first
      updated_rule = existing_rule.clone
      
      property = updated_rule[:properties].find { |property| property[:propertyKey] == 'return.message' }
      property[:propertyValue] = 'another content'
      updated_rule[:name] = updated_rule[:name] + ' more name'

      assert @api.update_rule(updated_rule), 'the rule not must be updated'

      rule = @api.domain_rule(updated_rule[:domain], updated_rule[:id])
      assert updated_rule, rule
    end
  end

  def test_domain_rule
    VCR.use_cassette('domain_rule') do
      rules = obtain_rules(domain)
      one_rule = rules.first
      rule = @api.domain_rule(domain, one_rule[:id])
      assert one_rule[:id], rule[:id]
      assert one_rule, rule
      assert domain, rule[:domain]
    end
  end

  def test_rules_for_domain
    VCR.use_cassette('rules_for_domain') do
      response = @api.rules_for_domain(domain)
      assert response.code == 200
      rules = response.msg
      assert rules.is_a? Array
    end
  end

  def test_rules_for_domain_filter_component
    VCR.use_cassette('rules_for_domain_by_component') do
      component = 'org.mxhero.feature.signature'
      response = @api.rules_for_domain(domain, component)
      assert response.code == 200
      rules = response.msg
      assert rules.all? { |rule| rule[:component] == component }, "All the rules must be of component type #{component}"
    end
  end

  def test_domains
    VCR.use_cassette('domains') do
      domains = @api.domains
      assert domains.key?(:elements)
      assert domains.key?(:totalElements)
      assert domains.key?(:totalPages)
      assert domains.key?(:actualPage)
    end
  end

  def test_domain_by_id
    VCR.use_cassette('domain_by_id') do
      id = domain
      tesla_domain = @api.domain_by_id(id)
      assert tesla_domain.key?(:domain)
      assert tesla_domain.key?(:server)
      assert tesla_domain.key?(:creationDate)
      assert tesla_domain.key?(:aliases)
      assert tesla_domain.key?(:ldap)
    end
  end

  def test_domain_by_id_not_found
    VCR.use_cassette('domain_by_id_not_found') do
      id = "test.notfound.com"
      tesla_domain = @api.domain_by_id(id)
      assert tesla_domain[:status] == 404
    end
  end

  def test_domain_by_id_param_could_not_be_nil
    assert_raises(RuntimeError) { @api.domain_by_id }
  end

  def test_accounts_by_domain
    VCR.use_cassette('accounts_from_domain') do
      response = @api.accounts_by_domain(domain)
      must_have_the_keys(response, %w( elements totalElements totalPages actualPage ))
      response[:elements].each do |account|
        must_have_the_keys(account, %w( account domain createdDate updatedDate group aliases dataSource ) )
        account[:aliases].each { |t_alias| must_have_the_keys(t_alias, %w( name domain dataSource )) }
      end
    end
  end

  def test_accounts_without_group
    VCR.use_cassette('accounts_without_group') do
      response = @api.accounts_by_domain(domain, without_group: true)
      assert response.key? :elements
      account = response[:elements].first
      start_with = account[:account][0..2]
      
      response = @api.accounts_by_domain(domain, without_group: true, account: start_with)
      assert response[:totalElements] >= 1
      find_account = response[:elements].first
      assert_equal start_with, find_account[:account][0..2]
    end
  end

  def test_accounts_by_domain_filtered
    VCR.use_cassette('accounts_filtered') do
      # The test environment have 4 accounts: 
      # agent.smith, john.doe, test, test1, test2
      response = @api.accounts_by_domain(domain, account: 'test')
      assert_equal 3, response[:elements].count
      response = @api.accounts_by_domain(domain, account: 'john.doe')
      assert_equal 1, response[:elements].count
      response = @api.accounts_by_domain(domain, account: 'test1')
      assert_equal 1, response[:elements].count
    end
  end

  def test_accounts_by_domain_paginated
    VCR.use_cassette('accounts_from_domain_paginated') do
      response = @api.accounts_by_domain(domain, limit: 4, offset: 1)
      must_have_the_keys(response, %w( elements totalElements totalPages actualPage ))
      assert_equal 4, response[:elements].count
      assert_equal 1, response[:actualPage]
    end
  end

  def test_delete_rule
    VCR.use_cassette('delete_rule') do
      rules = obtain_rules(domain)
      one_rule = rules.first      
      response = @api.delete_rule(domain, one_rule[:id])
      assert response
    end
  end
  
  #def test_try_to_create_rule_that_alredy_exist
  #  VCR.use_cassette('create_rule_alredy_exist') do
  #    response = @api.create_rule(create_rule_msg)
  #    #assert_equal 201, response.code
  #    new_response = @api.create_rule(create_rule_msg)
  #    assert_equal 500, new_response.code
  #    assert_equal "rules.already.exists.for.component", new_response.msg[:developerMessage]
  #  end
  #end
  
  def test_create_rule_for_domain
    VCR.use_cassette('create_rule_for_domain') do
      delete_all_rules  
      response = @api.create_rule_for_domain(domain, rule)
      assert response.code == 201
      new_response = @api.create_rule_for_domain(domain, rule)
      assert new_response.code == 500
      assert_equal "rules.already.exists.for.component", new_response.msg[:developerMessage]
    end
  end

  def test_account_properties
    VCR.use_cassette('account_properties') do 
      account = 'test'
      response = @api.account_properties(domain, account)
      assert_equal 200, response.code
      assert response.is_a? MxHero::API::Response
      properties = response.msg
      %w( email fax lastname mobile name opt1 opt2 opt3 telephone ).each do |property| 
        assert properties.key? property
      end
    end
  end

  def test_account_propertes_not_found
    VCR.use_cassette('account_properties_not_found') do 
      begin
        account = 'xxxxx'
        response = @api.account_properties(domain, account)
        assert_equal 404, response.code
        assert response.is_a? MxHero::API::Response
      rescue
        flunk 'error!'
      end
    end
  end

  def test_update_account_properties
    VCR.use_cassette('update_account_properties') do 
      account = 'test'
      response = @api.account_properties(domain, account)
      properties = response.msg
      properties['lastname'] = ( properties['lastname'] || '' ) + ' CHANGED' 
      properties['name']     = ( properties['name'] || '' ) + ' CHANGED' 
      properties['fax']      = nil
      response = @api.update_account_properties(domain, account, properties)
      assert_equal 200, response.code

      response = @api.account_properties(domain, account)
      assert_equal properties['lastname'], response.msg['lastname']
      assert_equal properties['name'], response.msg['name']
      assert_equal properties['fax'], response.msg['fax']
    end
  end

  private
  
  def delete_all_rules
    response = @api.rules_for_domain(domain)
    response.msg.each do |rule| 
      @api.delete_rule(domain, rule[:id]) 
    end
  end

  def obtain_rules(domain)
    response = @api.rules_for_domain(domain)
    if response.msg.nil? || response.msg.empty? 
      created = @api.create_rule_for_domain(domain, rule)
      return [ created.msg ]
    end
    response.msg
  end

  def must_have_the_keys(hash, keys)
    keys.each do |key|
      assert hash.key?(key.to_sym), "must have the key #{key}"
    end
  end

  def rule_msg_with_domain(domain)
    msg = create_rule_msg
    msg[:domain] = domain
    msg
  end

  def random_name
    (0...15).map{ ('a'..'z').to_a[rand(26)] }.join
  end

  def create_rule_msg(name = nil)
    {
      #"domain" => "tesla.com",
      twoWays: false,
      enabled: true,
      name: name || "Email footer",
      created: 1369682598000,
      fromDirection:  { directionType: "domain", domain: domain, freeValue: domain },
      toDirection:    { directionType: "domain", domain: domain, freeValue: domain },
      properties: [{ propertyKey: "return.message", propertyValue: "footer content" }],
      component: "org.mxhero.feature.disclaimer"
    }
  end

  def rule
    { :domain => domain, 
      :twoWays => false, 
      :enabled => true, 
      :name => "The rules for sales", 
      :created => "1375998105095", 
      :fromDirection => { :id => nil, 
                          :directionType => "domain", 
                          :freeValue => domain, 
                          :domain => domain, 
                          :account => nil, :group => nil }, 
      :toDirection => { :id => nil, 
                        :directionType => "anyone", 
                        :freeValue => "Anyone", 
                        :domain => domain, 
                        :account => nil, :group => nil}, 
      :properties => [
        { :propertyKey => "return.message", 
          :propertyValue => "<hr /><p><em><span style=\"color:green\">Think before you print and save a tree.</span></em></p>" }, 
        { :propertyKey => "return.message.plain", 
          :propertyValue => "\r\n----------------\r\nThink before you print and save a tree.r\n\r\n"}, 
        { :propertyKey => "interParsing", 
          :propertyValue => true}
      ], 
      :component => "org.mxhero.feature.disclaimer" }
  end

 end