require 'rails_helper'
require 'test_graph_helper'
require "#{Rails.root}/app/helpers/related_item_helper.rb"
include RelatedItemHelper

describe 'RelatedItemHelper module' do
  before(:each) do
    @death_star = create(:test_model_node)

    # different_targets: has_many inbound relationship
    @alderaan = create(:test_model_target_node)
    @dantooine = create(:test_model_target_node)
    @tatooine = create(:test_model_target_node)
    @death_star.different_targets = [@alderaan, @dantooine]

    @death_star.save

    @user = create(:user)
    allow_any_instance_of(User).to receive(:can).and_return(true)
  end

  context 'relatables' do
    it 'returns a list of relatable nodes for a given relationship type' do
      res = relatables(@death_star, 'TEST_MODEL_DIFFERENT_TARGET_HAS', 'both', @user)
      expect(res.keys).to eq(%i[different_targets])
      res_uuids = res[:different_targets].map { |x| x[:uuid] }

      expect(res_uuids.length).to eq(3)
      expect(res_uuids).to include(@alderaan.uuid)
      expect(res_uuids).to include(@dantooine.uuid)
      expect(res_uuids).to include(@tatooine.uuid)
    end

    it 'flags departmental nodes as such' do
      @dantooine.asset_owner = create(:departmental_repo)
      @dantooine.save
      res = relatables(@death_star, 'TEST_MODEL_DIFFERENT_TARGET_HAS', 'both', @user)
      alderaan_h = res[:different_targets].select { |x| x[:uuid] == @alderaan.uuid }.first
      dantooine_h = res[:different_targets].select { |x| x[:uuid] == @dantooine.uuid }.first
      tatooine_h = res[:different_targets].select { |x| x[:uuid] == @tatooine.uuid }.first

      expect(alderaan_h[:departmental]).to eq(false)
      expect(dantooine_h[:departmental]).to eq(true)
      expect(tatooine_h[:departmental]).to eq(false)
    end

    it 'excludes non-relatable nodes' do
      @dantooine.non_relatable = 'Y'
      @dantooine.save
      res = relatables(@death_star, 'TEST_MODEL_DIFFERENT_TARGET_HAS', 'both', @user)
      res_uuids = res[:different_targets].map { |x| x[:uuid] }

      expect(res_uuids.length).to eq(2)
      expect(res_uuids).to include(@alderaan.uuid)
      expect(res_uuids).to include(@tatooine.uuid)
    end

    it 'excludes nodes the user cannot see' do
      allow_any_instance_of(User).to receive(:can).with(:read, @dantooine).and_return(false)
      res = relatables(@death_star, 'TEST_MODEL_DIFFERENT_TARGET_HAS', 'both', @user)
      res_uuids = res[:different_targets].map { |x| x[:uuid] }

      expect(res_uuids.length).to eq(2)
      expect(res_uuids).to include(@alderaan.uuid)
      expect(res_uuids).to include(@tatooine.uuid)
    end

    it 'flags the nodes that are in fact related' do
      res = relatables(@death_star, 'TEST_MODEL_DIFFERENT_TARGET_HAS', 'both', @user)
      res = res[:different_targets].to_a.select { |x| x[:is_related] }
      res_uuids = res.map { |x| x[:uuid] }

      expect(res_uuids.length).to eq(2)
      expect(res_uuids).to include(@alderaan.uuid)
      expect(res_uuids).to include(@dantooine.uuid)
      expect(res_uuids).to_not include(@tatooine.uuid)
    end

    it 'returns multiple associations' do
      res = relatables(@death_star, 'TEST_MODEL_TWO_WAY_TARGET', 'both', @user)
      expect(res.keys.length).to eq(2)
      expect(res.keys).to include(:two_way_targets_inbound)
      expect(res.keys).to include(:two_way_targets_outbound)
    end

    it 'gets only "out" associations when given "outbound"' do
      res = relatables(@death_star, 'TEST_MODEL_TWO_WAY_TARGET', 'outbound', @user)
      expect(res.keys).to eq(%i[two_way_targets_outbound])
    end

    it 'gets only "in" associations when given "inbound"' do
      res = relatables(@death_star, 'TEST_MODEL_TWO_WAY_TARGET', 'inbound', @user)
      expect(res.keys).to eq(%i[two_way_targets_inbound])
    end
  end

  # context 'related_nodes_for' do
  #   it 'returns the nodes related to the target node for a given relationship type' do
  #     res = related_nodes_for(@death_star, 'TEST_MODEL_DIFFERENT_TARGET_HAS', 'both', @user)
  #     expect(res.keys).to eq(%i[different_targets])
  #     expect(res[:different_targets].length).to eq(2)
  #     expect(res[:different_targets]).to include(@alderaan)
  #     expect(res[:different_targets]).to include(@dantooine)
  #     expect(res[:different_targets]).to_not include(@tatooine)
  #   end

  #   it 'excludes nodes the user cannot see' do
  #     allow_any_instance_of(User).to receive(:can).with(:read, @dantooine).and_return(false)
  #     res = related_nodes_for(@death_star, 'TEST_MODEL_DIFFERENT_TARGET_HAS', 'both', @user)
  #     expect(res[:different_targets].length).to eq(1)
  #     expect(res[:different_targets]).to include(@alderaan)
  #   end

  #   it 'returns multiple associations' do
  #     res = related_nodes_for(@death_star, 'TEST_MODEL_TWO_WAY_TARGET', 'both', @user)
  #     expect(res.keys.length).to eq(2)
  #     expect(res.keys).to include(:two_way_targets_inbound)
  #     expect(res.keys).to include(:two_way_targets_outbound)
  #   end

  #   it 'gets only "out" associations when given "outbound"' do
  #     res = related_nodes_for(@death_star, 'TEST_MODEL_TWO_WAY_TARGET', 'outbound', @user)
  #     expect(res.keys).to eq(%i[two_way_targets_outbound])
  #   end

  #   it 'gets only "in" associations when given "inbound"' do
  #     res = related_nodes_for(@death_star, 'TEST_MODEL_TWO_WAY_TARGET', 'inbound', @user)
  #     expect(res.keys).to eq(%i[two_way_targets_inbound])
  #   end
  # end

  context 'related_model_names' do
    it 'returns the model that can be targeted by a relationship type' do
      res = related_model_names(@death_star, 'TEST_MODEL_HAS_TARGET')
      expect(res.keys).to eq(%i[target])
      expect(res[:target]).to eq('TestModelTargetNode')
    end

    it 'returns multiple models where multiple associations exist' do
      res = related_model_names(@death_star, 'TEST_MODEL_TWO_WAY_TARGET')
      expect(res[:two_way_targets_inbound]).to eq('TestModelTargetNode')
      expect(res[:two_way_targets_outbound]).to eq('TestModelUnusualNode')
    end

    it 'returns only "in" associations when given "inbound"' do
      res = related_model_names(@death_star, 'TEST_MODEL_TWO_WAY_TARGET', 'inbound')
      expect(res.keys).to eq(%i[two_way_targets_inbound])
      expect(res.values).to eq(['TestModelTargetNode'])
    end

    it 'returns only "out" associations when given "outbound"' do
      res = related_model_names(@death_star, 'TEST_MODEL_TWO_WAY_TARGET', 'outbound')
      expect(res.keys).to eq(%i[two_way_targets_outbound])
      expect(res.values).to eq(['TestModelUnusualNode'])
    end
  end
end
