# frozen_string_literal: true

class Users::ImportData::Trips
  BATCH_SIZE = 1000

  def initialize(user, trips_data)
    @user = user
    @trips_data = trips_data
  end

  def call
    return 0 unless trips_data.is_a?(Array)

    Rails.logger.info "Importing #{trips_data.size} trips for user: #{user.email}"

    valid_trips = filter_and_prepare_trips

    if valid_trips.empty?
      Rails.logger.info "Trips import completed. Created: 0"
      return 0
    end

    deduplicated_trips = filter_existing_trips(valid_trips)

    if deduplicated_trips.size < valid_trips.size
      Rails.logger.debug "Skipped #{valid_trips.size - deduplicated_trips.size} duplicate trips"
    end

    total_created = bulk_import_trips(deduplicated_trips)

    Rails.logger.info "Trips import completed. Created: #{total_created}"
    total_created
  end

  private

  attr_reader :user, :trips_data

  def filter_and_prepare_trips
    valid_trips = []
    skipped_count = 0

    trips_data.each do |trip_data|
      next unless trip_data.is_a?(Hash)

      unless valid_trip_data?(trip_data)
        skipped_count += 1
        next
      end

      prepared_attributes = prepare_trip_attributes(trip_data)
      valid_trips << prepared_attributes if prepared_attributes
    end

    if skipped_count > 0
      Rails.logger.warn "Skipped #{skipped_count} trips with invalid or missing required data"
    end

    valid_trips
  end

  def prepare_trip_attributes(trip_data)
    attributes = trip_data.except('created_at', 'updated_at')

    attributes['user_id'] = user.id
    attributes['created_at'] = Time.current
    attributes['updated_at'] = Time.current

    attributes.symbolize_keys
  rescue StandardError => e
    ExceptionReporter.call(e, 'Failed to prepare trip attributes')

    nil
  end

  def filter_existing_trips(trips)
    return trips if trips.empty?

    existing_trips_lookup = {}
    user.trips.select(:name, :started_at, :ended_at).each do |trip|
      key = [trip.name, normalize_timestamp(trip.started_at), normalize_timestamp(trip.ended_at)]
      existing_trips_lookup[key] = true
    end

    filtered_trips = trips.reject do |trip|
      key = [trip[:name], normalize_timestamp(trip[:started_at]), normalize_timestamp(trip[:ended_at])]
      if existing_trips_lookup[key]
        Rails.logger.debug "Trip already exists: #{trip[:name]}"
        true
      else
        false
      end
    end

    filtered_trips
  end

  def normalize_timestamp(timestamp)
    case timestamp
    when String
      Time.parse(timestamp).utc.iso8601
    when Time, DateTime
      timestamp.utc.iso8601
    else
      timestamp.to_s
    end
  rescue StandardError
    timestamp.to_s
  end

  def bulk_import_trips(trips)
    total_created = 0

    trips.each_slice(BATCH_SIZE) do |batch|
      begin
        result = Trip.upsert_all(
          batch,
          returning: %w[id],
          on_duplicate: :skip
        )

        batch_created = result.count
        total_created += batch_created

        Rails.logger.debug "Processed batch of #{batch.size} trips, created #{batch_created}, total created: #{total_created}"

      rescue StandardError => e
        ExceptionReporter.call(e, 'Failed to process trip batch')
      end
    end

    total_created
  end

  def valid_trip_data?(trip_data)
    return false unless trip_data.is_a?(Hash)

    return false unless validate_trip_name(trip_data)
    return false unless validate_trip_started_at(trip_data)
    return false unless validate_trip_ended_at(trip_data)

    true
  rescue StandardError => e
    Rails.logger.debug "Trip validation failed: #{e.message} for data: #{trip_data.inspect}"
    false
  end


  def validate_trip_name(trip_data)
    if trip_data['name'].present?
      true
    else
      Rails.logger.debug 'Trip validation failed: Name can\'t be blank'
      false
    end
  end

  def validate_trip_started_at(trip_data)
    if trip_data['started_at'].present?
      true
    else
      Rails.logger.debug 'Trip validation failed: Started at can\'t be blank'
      false
    end
  end

  def validate_trip_ended_at(trip_data)
    if trip_data['ended_at'].present?
      true
    else
      Rails.logger.debug 'Trip validation failed: Ended at can\'t be blank'
      false
    end
  end
end
