# frozen_string_literal: true

require 'rails_helper'

RSpec.describe GoogleMaps::SemanticHistoryImporter do
  describe '#call' do
    subject(:parser) { described_class.new(import, user.id).call }

    let(:user) { create(:user) }
    let!(:import) { create(:import, user:) }
    let(:file_path) { Rails.root.join("spec/fixtures/files/google/location-history/#{file_name}.json") }

    before do
      import.file.attach(
        io: File.open(file_path),
        filename: 'semantic_history.json',
        content_type: 'application/json'
      )
    end

    context 'when activitySegment is present' do
      context 'when startLocation is blank' do
        let(:file_name) { 'with_activitySegment_without_startLocation' }

        it 'creates a point' do
          expect { parser }.to change(Point, :count).by(1)
          expect(Point.last.lonlat.to_s).to eq('POINT (12.3411111 12.3411111)')
        end

        context 'when waypointPath is blank' do
          let(:file_name) { 'with_activitySegment_without_startLocation_without_waypointPath' }

          it 'does not create a point' do
            expect { parser }.not_to change(Point, :count)
          end
        end
      end

      context 'when startLocation is present' do
        let(:file_name) { 'with_activitySegment_with_startLocation' }

        it 'creates a point' do
          expect { parser }.to change(Point, :count).by(1)
          expect(Point.last.lonlat.to_s).to eq('POINT (12.3422222 12.3422222)')
        end

        context 'with different timestamp formats' do
          context 'when timestamp is in ISO format' do
            let(:file_name) { 'with_activitySegment_with_startLocation_with_iso_timestamp' }

            it 'creates a point' do
              expect { parser }.to change(Point, :count).by(1)
              expect(Point.last.lonlat.to_s).to eq('POINT (12.3433333 12.3433333)')
            end
          end

          context 'when timestamp is in seconds format' do
            let(:file_name) { 'with_activitySegment_with_startLocation_timestamp_in_seconds_format' }

            it 'creates a point' do
              expect { parser }.to change(Point, :count).by(1)
              expect(Point.last.lonlat.to_s).to eq('POINT (12.3444444 12.3444444)')
            end
          end

          context 'when timestamp is in milliseconds format' do
            let(:file_name) { 'with_activitySegment_with_startLocation_timestamp_in_milliseconds_format' }

            it 'creates a point' do
              expect { parser }.to change(Point, :count).by(1)
              expect(Point.last.lonlat.to_s).to eq('POINT (12.3455555 12.3455555)')
            end
          end

          context 'when timestampMs is used' do
            let(:file_name) { 'with_activitySegment_with_startLocation_timestampMs' }

            it 'creates a point' do
              expect { parser }.to change(Point, :count).by(1)
              expect(Point.last.lonlat.to_s).to eq('POINT (12.3466666 12.3466666)')
            end
          end
        end
      end
    end

    context 'when placeVisit is present' do
      context 'when location with coordinates is present' do
        let(:file_name) { 'with_placeVisit_with_location_with_coordinates' }

        it 'creates a point' do
          expect { parser }.to change(Point, :count).by(1)
          expect(Point.last.lonlat.to_s).to eq('POINT (12.3477777 12.3477777)')
        end

        context 'with different timestamp formats' do
          context 'when timestamp is in ISO format' do
            let(:file_name) { 'with_placeVisit_with_location_with_coordinates_with_iso_timestamp' }

            it 'creates a point' do
              expect { parser }.to change(Point, :count).by(1)
              expect(Point.last.lonlat.to_s).to eq('POINT (12.3488888 12.3488888)')
            end
          end

          context 'when timestamp is in seconds format' do
            let(:file_name) { 'with_placeVisit_with_location_with_coordinates_with_seconds_timestamp' }

            it 'creates a point' do
              expect { parser }.to change(Point, :count).by(1)
              expect(Point.last.lonlat.to_s).to eq('POINT (12.3499999 12.3499999)')
            end
          end

          context 'when timestamp is in milliseconds format' do
            let(:file_name) { 'with_placeVisit_with_location_with_coordinates_with_milliseconds_timestamp' }

            it 'creates a point' do
              expect { parser }.to change(Point, :count).by(1)
              expect(Point.last.lonlat.to_s).to eq('POINT (12.3511111 12.3511111)')
            end
          end

          context 'when timestampMs is used' do
            let(:file_name) { 'with_placeVisit_with_location_with_coordinates_with_timestampMs' }

            it 'creates a point' do
              expect { parser }.to change(Point, :count).by(1)
              expect(Point.last.lonlat.to_s).to eq('POINT (12.3522222 12.3522222)')
            end
          end
        end
      end

      context 'when location with coordinates is blank' do
        let(:file_name) { 'with_placeVisit_without_location_with_coordinates' }

        it 'does not create a point' do
          expect { parser }.not_to change(Point, :count)
        end

        context 'when otherCandidateLocations is present' do
          let(:file_name) { 'with_placeVisit_without_location_with_coordinates_with_otherCandidateLocations' }

          it 'creates a point' do
            expect { parser }.to change(Point, :count).by(1)
            expect(Point.last.lonlat.to_s).to eq('POINT (12.3533333 12.3533333)')
          end
        end
      end
    end
  end
end
