require 'active_job/arguments'

module EventStore
  class Event < RailsEventStoreActiveRecord::Event
    module WithGlobalId
      module_function

      YAML = ActiveRecord::Coders::YAMLColumn.new(Hash)

      class << self
        delegate :serialize, :deserialize, to: 'ActiveJob::Arguments'
      end

      class SerializationEventError < StandardError
        include Bugsnag::MetaData

        def initialize(object:, error:)
          self.bugsnag_meta_data = { object: object.as_json }

          super error
        end
      end

      # we have to wrap it into array, because ActiveJob::Arguments.serialize
      # andActiveJob::Arguments.deserialize work only on arrays and they are
      # the only public exposed api
      def dump(obj)
        YAML.dump serialize([obj]).first
      rescue URI::InvalidURIError, URI::GID::MissingModelIdError => error
        raise SerializationEventError, object: obj, error: error
      end

      def load(str)
        deserialize([YAML.load(str)]).first.symbolize_keys
      end
    end

    serialize :data, WithGlobalId
    # Can't really use ActiveJob::Arguments because it does not support Time type
    # and metadata contain timestamp when the event was created
    # https://github.com/rails/rails/issues/18519
    # serialize :metadata, WithGlobalId

    attr_readonly :provider_id

    validates :provider_id, presence: true

    before_validation :provider_id_from_metadata

    belongs_to :account, foreign_key: :provider_id, inverse_of: :events

    alias provider account

    private

    def provider_id_from_metadata
      self.provider_id ||= metadata.try!(:fetch, :provider_id, nil)
    end
  end
end
