# frozen_string_literal: true require 'rails_helper' RSpec.describe LocationSearch::PointFinder do let(:user) { create(:user) } let(:service) { described_class.new(user, search_params) } let(:search_params) { { latitude: 52.5200, longitude: 13.4050 } } describe '#call' do context 'with valid coordinates' do let(:mock_matching_points) do [ { id: 1, timestamp: 1711814700, coordinates: [52.5201, 13.4051], distance_meters: 45.5, date: '2024-03-20T18:45:00Z' } ] end let(:mock_visits) do [ { timestamp: 1711814700, date: '2024-03-20T18:45:00Z', coordinates: [52.5201, 13.4051], distance_meters: 45.5, duration_estimate: '~25m', points_count: 1 } ] end before do allow_any_instance_of(LocationSearch::SpatialMatcher) .to receive(:find_points_near).and_return(mock_matching_points) allow_any_instance_of(LocationSearch::ResultAggregator) .to receive(:group_points_into_visits).and_return(mock_visits) end it 'returns search results with location data' do result = service.call expect(result[:locations]).to be_an(Array) expect(result[:locations].first).to include( coordinates: [52.5200, 13.4050], total_visits: 1 ) end it 'calls spatial matcher with correct coordinates and radius' do expect_any_instance_of(LocationSearch::SpatialMatcher) .to receive(:find_points_near) .with(user, 52.5200, 13.4050, 500, { date_from: nil, date_to: nil }) service.call end context 'with custom radius override' do let(:search_params) { { latitude: 52.5200, longitude: 13.4050, radius_override: 150 } } it 'uses custom radius when override provided' do expect_any_instance_of(LocationSearch::SpatialMatcher) .to receive(:find_points_near) .with(user, anything, anything, 150, anything) service.call end end context 'with date filtering' do let(:search_params) do { latitude: 52.5200, longitude: 13.4050, date_from: Date.parse('2024-01-01'), date_to: Date.parse('2024-03-31') } end it 'passes date filters to spatial matcher' do expect_any_instance_of(LocationSearch::SpatialMatcher) .to receive(:find_points_near) .with(user, anything, anything, anything, { date_from: Date.parse('2024-01-01'), date_to: Date.parse('2024-03-31') }) service.call end end context 'with limit parameter' do let(:search_params) { { latitude: 52.5200, longitude: 13.4050, limit: 10 } } let(:many_visits) { Array.new(15) { |i| { timestamp: i, date: "2024-01-#{i+1}T12:00:00Z" } } } before do allow_any_instance_of(LocationSearch::SpatialMatcher) .to receive(:find_points_near).and_return([{}]) allow_any_instance_of(LocationSearch::ResultAggregator) .to receive(:group_points_into_visits).and_return(many_visits) end it 'limits the number of visits returned' do result = service.call expect(result[:locations].first[:visits].length).to eq(10) end end end context 'when no matching points found' do let(:search_params) { { latitude: 52.5200, longitude: 13.4050 } } before do allow_any_instance_of(LocationSearch::SpatialMatcher) .to receive(:find_points_near).and_return([]) end it 'excludes locations with no visits' do result = service.call expect(result[:locations]).to be_empty expect(result[:total_locations]).to eq(0) end end context 'when coordinates are missing' do let(:search_params) { {} } it 'returns empty result without calling services' do expect(LocationSearch::SpatialMatcher).not_to receive(:new) result = service.call expect(result[:locations]).to be_empty end end context 'when only latitude is provided' do let(:search_params) { { latitude: 52.5200 } } it 'returns empty result' do result = service.call expect(result[:locations]).to be_empty end end context 'when only longitude is provided' do let(:search_params) { { longitude: 13.4050 } } it 'returns empty result' do result = service.call expect(result[:locations]).to be_empty end end end end