module Semian::Adapter

def acquire_semian_resource(scope:, adapter:, &block)

def acquire_semian_resource(scope:, adapter:, &block)
  return yield if resource_already_acquired?
  semian_resource.acquire(scope: scope, adapter: adapter, resource: self) do
    mark_resource_as_acquired(&block)
  end
rescue ::Semian::OpenCircuitError => error
  last_error = semian_resource.circuit_breaker.last_error
  message = "#{error.message} caused by #{last_error.message}"
  last_error = nil unless last_error.is_a?(Exception) # Net::HTTPServerError is not an exception
  raise self.class::CircuitOpenError.new(semian_identifier, message), cause: last_error
rescue ::Semian::BaseError => error
  raise self.class::ResourceBusyError.new(semian_identifier, error.message)
rescue *resource_exceptions => error
  error.semian_identifier = semian_identifier if error.respond_to?(:semian_identifier=)
  raise
end

def clear_semian_resource

def clear_semian_resource
  @semian_resource = nil
end

def mark_resource_as_acquired

def mark_resource_as_acquired
  previous = @resource_acquired
  @resource_acquired = true
  yield
ensure
  @resource_acquired = previous
end

def raw_semian_options

def raw_semian_options
  raise NotImplementedError, "Semian adapters must implement a `raw_semian_options` method"
end

def resource_already_acquired?

def resource_already_acquired?
  @resource_acquired
end

def resource_exceptions

def resource_exceptions
  raise NotImplementedError, "Semian adapters must implement a `resource_exceptions` method"
end

def semian_identifier

def semian_identifier
  raise NotImplementedError, "Semian adapters must implement a `semian_identifier` method"
end

def semian_options

def semian_options
  return @semian_options if defined? @semian_options
  options = raw_semian_options
  symbolized_options = options && options.transform_keys(&:to_sym) # rubocop:disable Style/SafeNavigation
  symbolized_options.tap do
    @semian_options = symbolized_options if !symbolized_options || !symbolized_options.fetch(:dynamic, false)
  end
end

def semian_resource

def semian_resource
  return @semian_resource if @semian_resource
  case semian_options
  when false
    @semian_resource = UnprotectedResource.new(semian_identifier)
  when nil
    Semian.logger.info("Semian is not configured for #{self.class.name}: #{semian_identifier}")
    @semian_resource = UnprotectedResource.new(semian_identifier)
  else
    options = semian_options.dup
    options.delete(:name)
    options[:consumer] = self
    options[:exceptions] ||= []
    options[:exceptions] += resource_exceptions
    resource = ::Semian.retrieve_or_register(semian_identifier, **options)
    @semian_resource = resource unless options.fetch(:dynamic, false)
    resource
  end
end