# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Imports::Create do
  let(:user) { create(:user) }
  let(:service) { described_class.new(user, import) }

  describe '#call' do
    describe 'status transitions' do
      let(:import) { create(:import, source: 'owntracks', status: 'created') }
      let(:file_path) { Rails.root.join('spec/fixtures/files/owntracks/2024-03.rec') }

      before do
        import.file.attach(io: File.open(file_path), filename: '2024-03.rec', content_type: 'application/octet-stream')
      end

      it 'sets status to processing at start' do
        service.call

        expect(import.reload.status).to eq('processing').or eq('completed')
      end

      it 'updates the import source' do
        service.call

        expect(import.reload.source).to eq('owntracks')
      end

      it 'resets points counter cache' do
        allow(User).to receive(:reset_counters)

        service.call

        expect(User).to have_received(:reset_counters).with(user.id, :points)
      end


      context 'when import succeeds' do
        it 'sets status to completed' do
          service.call
          expect(import.reload.status).to eq('completed')
        end
      end

      context 'when import fails' do
        before do
          allow(OwnTracks::Importer).to receive(:new).with(import, user.id, kind_of(String)).and_raise(StandardError)
        end

        it 'sets status to failed' do
          service.call
          expect(import.reload.status).to eq('failed')
        end
      end
    end

    context 'when source is google_semantic_history' do
      let(:import) { create(:import, source: 'google_semantic_history') }
      let(:file_path) { Rails.root.join('spec/fixtures/files/google/semantic_history.json') }
      let(:file) { Rack::Test::UploadedFile.new(file_path, 'application/json') }

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

      it 'calls the GoogleMaps::SemanticHistoryImporter' do
        expect(GoogleMaps::SemanticHistoryImporter).to \
          receive(:new).with(import, user.id, kind_of(String)).and_return(double(call: true))
        service.call
      end

      it 'updates the import points count' do
        expect { service.call }.to have_enqueued_job(Import::UpdatePointsCountJob).with(import.id)
      end
    end

    context 'when source is google_phone_takeout' do
      let(:import) { create(:import, source: 'google_phone_takeout') }
      let(:file_path) { Rails.root.join('spec/fixtures/files/google/phone-takeout_w_3_duplicates.json') }

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

      it 'calls the GoogleMaps::PhoneTakeoutImporter' do
        expect(GoogleMaps::PhoneTakeoutImporter).to \
          receive(:new).with(import, user.id, kind_of(String)).and_return(double(call: true))
        service.call
      end
    end

    context 'when source is owntracks' do
      let(:import) { create(:import, source: 'owntracks', name: '2024-03.rec') }
      let(:file_path) { Rails.root.join('spec/fixtures/files/owntracks/2024-03.rec') }
      let(:file) { Rack::Test::UploadedFile.new(file_path, 'application/octet-stream') }

      before do
        import.file.attach(io: File.open(file_path), filename: '2024-03.rec', content_type: 'application/octet-stream')
      end

      it 'calls the OwnTracks::Importer' do
        expect(OwnTracks::Importer).to \
          receive(:new).with(import, user.id, kind_of(String)).and_return(double(call: true))
        service.call
      end

      context 'when import is successful' do
        it 'schedules stats creating' do
          Sidekiq::Testing.inline! do
            expect { service.call }.to \
              have_enqueued_job(Stats::CalculatingJob).with(user.id, 2024, 3)
          end
        end

        it 'schedules visit suggesting' do
          Sidekiq::Testing.inline! do
            expect { service.call }.to have_enqueued_job(VisitSuggestingJob)
          end
        end
      end

      context 'when import fails' do
        before do
          allow(OwnTracks::Importer).to receive(:new).with(import, user.id, kind_of(String)).and_raise(StandardError)
        end

        context 'when self-hosted' do
          before do
            allow(DawarichSettings).to receive(:self_hosted?).and_return(true)
          end

          after do
            allow(DawarichSettings).to receive(:self_hosted?).and_call_original
          end

          it 'creates a failed notification' do
            service.call

            expect(user.notifications.last.content).to \
              include('Import "2024-03.rec" failed: StandardError, stacktrace: ')
          end
        end

        context 'when not self-hosted' do
          before do
            allow(DawarichSettings).to receive(:self_hosted?).and_return(false)
          end

          after do
            allow(DawarichSettings).to receive(:self_hosted?).and_call_original
          end

          it 'does not create a failed notification' do
            service.call

            expect(user.notifications.last.content).to \
              include('Import "2024-03.rec" failed, please contact us at hi@dawarich.com')
          end
        end
      end
    end

    context 'when source is gpx' do
      let(:import) { create(:import, source: 'gpx') }
      let(:file_path) { Rails.root.join('spec/fixtures/files/gpx/gpx_track_single_segment.gpx') }
      let(:file) { Rack::Test::UploadedFile.new(file_path, 'application/octet-stream') }

      before do
        import.file.attach(io: File.open(file_path), filename: 'gpx_track_single_segment.gpx',
                           content_type: 'application/octet-stream')
      end

      it 'calls the Gpx::TrackImporter' do
        expect(Gpx::TrackImporter).to \
          receive(:new).with(import, user.id, kind_of(String)).and_return(double(call: true))
        service.call
      end
    end

    context 'when source is geojson' do
      let(:import) { create(:import, source: 'geojson') }
      let(:file_path) { Rails.root.join('spec/fixtures/files/geojson/export.json') }

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

      it 'calls the Geojson::Importer' do
        expect(Geojson::Importer).to \
          receive(:new).with(import, user.id, kind_of(String)).and_return(double(call: true))
        service.call
      end
    end

    context 'when source is immich_api' do
      let(:import) { create(:import, source: 'immich_api') }
      let(:file_path) { Rails.root.join('spec/fixtures/files/immich/geodata.json') }

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

      it 'calls the Photos::Importer' do
        expect(Photos::Importer).to \
          receive(:new).with(import, user.id, kind_of(String)).and_return(double(call: true))

        service.call
      end
    end

    context 'when source is photoprism_api' do
      let(:import) { create(:import, source: 'photoprism_api') }
      let(:file_path) { Rails.root.join('spec/fixtures/files/immich/geodata.json') }

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

      it 'calls the Photos::Importer' do
        expect(Photos::Importer).to \
          receive(:new).with(import, user.id, kind_of(String)).and_return(double(call: true))
        service.call
      end
    end
  end
end
