require 'fhir_client' FHIR.logger.level = Logger::ERROR

namespace :fhir do

desc 'console'
task :console, [] do
  exec('ruby bin/console')
end

#
# Prerequisites & Assumptions:
#
#  1. Running SMART-on-FHIR (DSTU2 branch) server  [http://example/fhir]
#  2. Running OpenID Connect server [http://example:8080/openid-connect-server-webapp]
#  3. Configured client under OpenID Connect server:
#     a. Create a system scope if necessary. SMART-on-FHIR requires 'fhir_complete' scope.
#     b. Add the scope created in (a) to client.
#     c. Add the FHIR server URL to the list of allowed redirect URIs (required?)
#     d. Ensure client has 'client credentials' grant type
#     d. Whitelist the client
#  4. 'client_id' and 'client_secret' variables are the name and secret of the client created in (3)
#  5. :authorize_url is the authorization endpoint of the OpenID connect server
#  6. :token_url is the token endpoint of the OpenID connect server
#
desc 'OAuth2 Example'
task :oauth2, [:url, :client_id, :client_secret] do |_t, args|
  client = FHIR::Client.new(args.url)
  client_id = args.client_id
  client_secret = args.client_secret
  options = client.get_oauth2_metadata_from_conformance
  if options.empty?
    puts 'This server does not support the expected OAuth2 extensions.'
  else
    client.set_oauth2_auth(client_id, client_secret, options[:authorize_url], options[:token_url])
    reply = client.read_feed(FHIR::Patient)
    puts reply.body
  end
end

desc 'count all resources for a given server'
task :count, [:url, :display_zero, :include_all] do |_t, args|
  client = FHIR::Client.new(args.url)
  client.try_conformance_formats(FHIR::Formats::ResourceFormat::RESOURCE_JSON)
  display_zero = (args.display_zero == 'true')
  include_all = (args.include_all == 'true')
  counts = {}
  fhir_resources.each do |klass|
    reply = client.read_feed(klass)
    total = reply.resource.nil? ? 0 : reply.resource.total
    total = reply.resource.each.reduce(0) { |s| s + 1 } if total.nil? && include_all
    total = 'n/a' if total.nil?
    if total.to_s != "0" || display_zero
      counts[klass.name.demodulize.to_s] = total.to_s
    end
  end
  format = "  %-35s %7s\n"
  printf format, 'Resource', 'Count'
  printf format, '--------', '-----'
  counts.each do |key, value|
    printf format, key, value
  end
end

desc 'delete all resources for a given server'
task :clean, [:url] do |_t, args|
  client = FHIR::Client.new(args.url)
  client.try_conformance_formats(FHIR::Formats::ResourceFormat::RESOURCE_JSON)
  fhir_resources.each do |klass|
    puts "Reading #{klass.name.demodulize}..."
    skipped = []
    reply = client.read_feed(klass)
    while !reply.nil? && !reply.resource.nil? && reply.resource.total > 0
      puts "  Cleaning #{reply.resource.entry.length} #{klass.name.demodulize} resources..."
      reply.resource.entry.each do |entry|
        unless entry.resource.nil?
          del_reply = client.destroy(klass, entry.resource.id)
          skipped << "#{klass.name.demodulize}/#{entry.resource.id}" if [405, 409].include?(del_reply.code)
        end
      end
      if skipped.empty?
        reply = client.read_feed(klass)
      else
        puts "  *** Unable to delete some #{klass.name.demodulize}s ***"
        reply = nil
      end
    end
  end
  puts 'Done cleaning.'
  Rake::Task['fhir:count'].invoke(args.url)
end

def fhir_resources
  FHIR::RESOURCES.map { |r| Object.const_get("FHIR::#{r}") }
end

end