# frozen_string_literal: true

require File.join(File.expand_path('../../../../test', __dir__), 'test_helper')

module MasterfilesApp
  class TestLocationInteractor < MiniTestWithHooks
    include MasterfilesApp::LocationFactory

    def repo
      interactor.send(:repo)
    end

    def test_repo
      repo = interactor.send(:repo)
      assert repo.is_a?(MasterfilesApp::LocationRepo)
    end

    def test_location
      MasterfilesApp::LocationRepo.any_instance.stubs(:find_location).returns(fake_location)
      entity = interactor.send(:location, 1)
      assert entity.is_a?(OpenStruct)
    end

    def test_create_location
      parent_id = create_location
      attrs = fake_location.to_h.except(:id)
      res = interactor.create_location(parent_id, attrs)
      assert res.success, "#{res.message} : #{res.errors.inspect}"
      assert_instance_of(OpenStruct, res.instance)
      assert res.instance.id.nonzero?
    end

    def test_create_location_fail
      parent_id = create_location
      attrs = fake_location(location_long_code: nil).to_h.except(:id)
      res = interactor.create_location(parent_id, attrs)
      refute res.success, 'should fail validation'
      assert_equal ['must be filled'], res.errors[:location_long_code]
    end

    def test_update_location
      id = create_location
      attrs = interactor.send(:repo).find_hash(:locations, id).except(:id)
      attrs[:location_long_code] = 'a_change'
      res = interactor.update_location(id, attrs)
      assert res.success, "#{res.message} : #{res.errors.inspect}"
      assert_instance_of(OpenStruct, res.instance)
      assert_equal 'a_change', repo.get(:locations, :location_long_code, id)
    end

    def test_update_location_fail
      id = create_location
      attrs = interactor.send(:repo).find_hash(:locations, id).reject { |k, _| %i[id location_long_code].include?(k) }
      res = interactor.update_location(id, attrs)
      refute res.success, "#{res.message} : #{res.errors.inspect}"
      assert_equal ['is missing'], res.errors[:location_long_code]
    end

    def test_delete_location
      id = create_location(force_create: true)
      assert_count_changed(:locations, -1) do
        res = interactor.delete_location(id)
        assert res.success, res.message
      end
    end

    private

    def location_attrs
      location_storage_type_id = create_location_storage_type
      location_type_id = create_location_type
      location_assignment_id = create_location_assignment
      location_storage_definition_id = create_location_storage_definition

      {
        id: 1,
        primary_storage_type_id: location_storage_type_id,
        location_type_id: location_type_id,
        primary_assignment_id: location_assignment_id,
        location_long_code: Faker::Lorem.unique.word,
        location_description: 'ABC',
        has_single_container: false,
        virtual_location: false,
        consumption_area: false,
        location_short_code: 'ABC',
        can_be_moved: false,
        print_code: 'ABC',
        location_storage_definition_id: location_storage_definition_id,
        can_store_stock: false,
        units_in_location: 1,
        maximum_units: 1,
        contains_row_positions: false,
        is_row_position: false,
        active: true,
        assignment_code: 'ABC',
        storage_type_code: 'ABC',
        location_type_code: 'ABC',
        parent_id: nil,
        path_array: ['ABC'],
        path_string: 'ABC',
        loading: false,
        unloading: false,
        fixed_storage_rule: false,
        is_full: false,
        is_empty: false,
        bin_storage_rule_id: 1,
        sequence_number: 1,
        open: false,
        closed: false,
        not_available: false
      }
    end

    def fake_location(overrides = {})
      Location.new(location_attrs.merge(overrides))
    end

    def interactor
      @interactor ||= LocationInteractor.new(current_user, {}, {}, {})
    end
  end
end
