require "./lib/apocrodentia"
require "test/unit"
require_relative "../classes.rb"



class TestPerception < BaseBehaviorTestCase


  def setup
    super
    @perceiver = Traveller.new
    @perceiver2 = Traveller.new
    @discoverable = Traveller.new 
    @item = SomeItem.new
    @test_data = {perception_account: {39 => 19, 10 => 2}, known_object_ids: [12,3,42], perception_lvl: 1}
    test_init_gauges
  end



  def test_perceiver_no_longer_sees_items_added_to_inventory
    @perceiver2.now_sees @item
    assert @perceiver2.can_see?(@item)
    self.world.trigger AR::Events::ItemAddedToInventory, ({item: @item, inventory_owner: @perceiver})
    self.world.events_engine.tick! 
    
    assert !@perceiver2.can_see?(@item)
  end



  def test_perception_automatically_initializes_perception_accounts_for_discoverable
    assert_nil @perceiver.perception_account[@discoverable.id] 
    assert_equal @perceiver.perception_for(@discoverable), 0
    assert_equal @perceiver.perception_account[@discoverable.id], 0
  end

  def test_perception_correctly_indicates_seeing_potential
    assert @perceiver.potential_to_see? @discoverable
    @discoverable.discovery_threshold = 1
    assert_false @perceiver.potential_to_see? @discoverable 
  end

  def test_perception_correctly_indicates_known_objects_state
    assert_false @perceiver.can_see? @discoverable
    @perceiver.known_object_ids.push @discoverable.id
    assert @perceiver.can_see? @discoverable
  end

  def test_perceiver_emits_discovery_made_event_when_perception_account_crosses_threshold
    setup_perceiver_cannot_see
    e = AR::Events::PerceptionAccountChangedEvent.new perceiver: @perceiver, discoverable: @discoverable, change: 10

    results = e.resolve!
    evnt = results.select{|evt| evt.class == AR::Events::DiscoveryMadeEvent}.last 

    assert_not_nil evnt
    assert_equal evnt.perceiver, @perceiver
    assert_equal evnt.discovered, @discoverable
  end

  def test_perceiver_emits_discovery_lost_event_when_perception_account_goes_below_threshold
    setup_perceiver_can_see
    @perceiver.known_object_ids.push @discoverable.id
    e = AR::Events::PerceptionAccountChangedEvent.new perceiver: @perceiver, discoverable: @discoverable, change: -6

    results = e.resolve!
    evnt = results.select{|evt| evt.class == AR::Events::DiscoveryLostEvent}.last 

    assert_not_nil evnt, "a discovery lost event should have been emitted"
    assert_equal evnt.perceiver, @perceiver
    assert_equal evnt.undiscovered, @discoverable
  end

  def test_perceiver_adds_to_known_objects_when_discovery_made
    assert_false @perceiver.can_see?(@discoverable) 
    e = AR::Events::DiscoveryMadeEvent.new perceiver: @perceiver, discovered: @discoverable
    results = e.resolve!
    assert @perceiver.can_see?(@discoverable)
  end

  def test_perceiver_removes_from_known_objects_and_perception_account_when_discovery_lost
    @perceiver.known_object_ids.push(@discoverable.id)
    @perceiver.change_perception_for @discoverable, 10
    assert @perceiver.can_see?(@discoverable) 
    e = AR::Events::DiscoveryLostEvent.new perceiver: @perceiver, undiscovered: @discoverable
    results = e.resolve!
    assert results.empty?, "\n=============\n#{results} should be empty\n==========".colorize(:light_red)
    assert_false @perceiver.can_see?(@discoverable)
  end

  def test_perceiver_emits_discovery_lost_when_object_dies
    @perceiver.known_object_ids.push(@discoverable.id)
    assert @perceiver.can_see?(@discoverable) 
    self.world.events_engine.trigger AR::Events::ARObjectDied, ar_object: @discoverable
    self.world.events_engine.tick!
    assert !@perceiver.can_see?(@discoverable) 
  end



  #sets up ability for threshold to be crossed negatively
  def setup_perceiver_can_see 
    @perceiver.change_perception_for @discoverable, 10
    @discoverable.discovery_threshold = 5
  end

  #sets up ability for threshold to be crossed positively
  def setup_perceiver_cannot_see
    @perceiver.change_perception_for @discoverable, 5
    @discoverable.discovery_threshold = 10 
  end

end
