# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Imports::SourceDetector do
  let(:detector) { described_class.new(file_content, filename) }
  let(:filename) { nil }

  describe '#detect_source' do
    context 'with Google Semantic History format' do
      let(:file_content) { file_fixture('google/semantic_history.json').read }

      it 'detects google_semantic_history format' do
        expect(detector.detect_source).to eq(:google_semantic_history)
      end
    end

    context 'with Google Records format' do
      let(:file_content) { file_fixture('google/records.json').read }

      it 'detects google_records format' do
        expect(detector.detect_source).to eq(:google_records)
      end
    end

    context 'with Google Phone Takeout format' do
      let(:file_content) { file_fixture('google/phone-takeout_w_3_duplicates.json').read }

      it 'detects google_phone_takeout format' do
        expect(detector.detect_source).to eq(:google_phone_takeout)
      end
    end

    context 'with Google Phone Takeout array format' do
      let(:file_content) { file_fixture('google/location-history.json').read }

      it 'detects google_phone_takeout format' do
        expect(detector.detect_source).to eq(:google_phone_takeout)
      end
    end

    context 'with GeoJSON format' do
      let(:file_content) { file_fixture('geojson/export.json').read }

      it 'detects geojson format' do
        expect(detector.detect_source).to eq(:geojson)
      end
    end

    context 'with OwnTracks REC file' do
      let(:file_content) { file_fixture('owntracks/2024-03.rec').read }
      let(:filename) { 'test.rec' }

      it 'detects owntracks format' do
        expect(detector.detect_source).to eq(:owntracks)
      end
    end

    context 'with OwnTracks content without .rec extension' do
      let(:file_content) { '{"_type":"location","lat":52.225,"lon":13.332}' }
      let(:filename) { 'test.json' }

      it 'detects owntracks format based on content' do
        expect(detector.detect_source).to eq(:owntracks)
      end
    end

    context 'with GPX file' do
      let(:file_content) { file_fixture('gpx/gpx_track_single_segment.gpx').read }
      let(:filename) { 'test.gpx' }

      it 'detects gpx format' do
        expect(detector.detect_source).to eq(:gpx)
      end
    end

    context 'with invalid JSON' do
      let(:file_content) { 'invalid json content' }

      it 'returns nil for invalid JSON' do
        expect(detector.detect_source).to be_nil
      end
    end

    context 'with unknown JSON format' do
      let(:file_content) { '{"unknown": "format", "data": []}' }

      it 'returns nil for unknown format' do
        expect(detector.detect_source).to be_nil
      end
    end

    context 'with empty content' do
      let(:file_content) { '' }

      it 'returns nil for empty content' do
        expect(detector.detect_source).to be_nil
      end
    end
  end

  describe '#detect_source!' do
    context 'with valid format' do
      let(:file_content) { file_fixture('google/records.json').read }

      it 'returns the detected format' do
        expect(detector.detect_source!).to eq(:google_records)
      end
    end

    context 'with unknown format' do
      let(:file_content) { '{"unknown": "format"}' }

      it 'raises UnknownSourceError' do
        expect { detector.detect_source! }.to raise_error(
          Imports::SourceDetector::UnknownSourceError,
          'Unable to detect file format'
        )
      end
    end
  end

  describe '.new_from_file_header' do
    context 'with Google Records file' do
      let(:fixture_path) { file_fixture('google/records.json').to_s }

      it 'detects source correctly from file path' do
        detector = described_class.new_from_file_header(fixture_path)
        expect(detector.detect_source).to eq(:google_records)
      end

      it 'can detect source efficiently from file' do
        detector = described_class.new_from_file_header(fixture_path)

        # Verify it can detect correctly using file-based approach
        expect(detector.detect_source).to eq(:google_records)
      end
    end

    context 'with GeoJSON file' do
      let(:fixture_path) { file_fixture('geojson/export.json').to_s }

      it 'detects source correctly from file path' do
        detector = described_class.new_from_file_header(fixture_path)
        expect(detector.detect_source).to eq(:geojson)
      end
    end
  end

  describe 'detection accuracy with real fixture files' do
    shared_examples 'detects format correctly' do |expected_format, fixture_path|
      it "detects #{expected_format} format for #{fixture_path}" do
        file_content = file_fixture(fixture_path).read
        filename = File.basename(fixture_path)
        detector = described_class.new(file_content, filename)

        expect(detector.detect_source).to eq(expected_format)
      end
    end

    # Test various Google Semantic History variations
    include_examples 'detects format correctly', :google_semantic_history, 'google/location-history/with_activitySegment_with_startLocation.json'
    include_examples 'detects format correctly', :google_semantic_history, 'google/location-history/with_placeVisit_with_location_with_coordinates.json'

    # Test GeoJSON variations
    include_examples 'detects format correctly', :geojson, 'geojson/export_same_points.json'
    include_examples 'detects format correctly', :geojson, 'geojson/gpslogger_example.json'

    # Test GPX files
    include_examples 'detects format correctly', :gpx, 'gpx/arc_example.gpx'
    include_examples 'detects format correctly', :gpx, 'gpx/garmin_example.gpx'
    include_examples 'detects format correctly', :gpx, 'gpx/gpx_track_multiple_segments.gpx'
  end
end
