# frozen_string_literal: true

module Archivable
  extend ActiveSupport::Concern

  included do
    belongs_to :raw_data_archive,
               class_name: 'Points::RawDataArchive',
               optional: true

    scope :archived, -> { where(raw_data_archived: true) }
    scope :not_archived, -> { where(raw_data_archived: false) }
    scope :with_archived_raw_data, lambda {
      includes(raw_data_archive: { file_attachment: :blob })
    }
  end

  # Main method: Get raw_data with fallback to archive
  # Use this instead of point.raw_data when you need archived data
  def raw_data_with_archive
    return raw_data if raw_data.present? || !raw_data_archived?

    fetch_archived_raw_data
  end

  # Restore archived data back to database column
  def restore_raw_data!(value)
    update!(
      raw_data: value,
      raw_data_archived: false,
      raw_data_archive_id: nil
    )
  end

  private

  def fetch_archived_raw_data
    # Check temporary restore cache first (for migrations)
    cached = check_temporary_restore_cache
    return cached if cached

    fetch_from_archive_file
  rescue StandardError => e
    handle_archive_fetch_error(e)
  end

  def check_temporary_restore_cache
    return nil unless respond_to?(:timestamp)

    recorded_time = Time.at(timestamp)
    cache_key = "raw_data:temp:#{user_id}:#{recorded_time.year}:#{recorded_time.month}:#{id}"
    Rails.cache.read(cache_key)
  end

  def fetch_from_archive_file
    return {} unless raw_data_archive&.file&.attached?

    # Download and search through JSONL
    compressed_content = raw_data_archive.file.blob.download
    io = StringIO.new(compressed_content)
    gz = Zlib::GzipReader.new(io)

    begin
      result = nil
      gz.each_line do |line|
        data = JSON.parse(line)
        if data['id'] == id
          result = data['raw_data']
          break
        end
      end
      result || {}
    ensure
      gz.close
    end
  end

  def handle_archive_fetch_error(error)
    ExceptionReporter.call(error, "Failed to fetch archived raw_data for Point ID #{id}")

    {} # Graceful degradation
  end
end
