# frozen_string_literal: true

require "cbor"
require "json"

require_relative "geo_code"

class GeoCodeRepo
	def initialize(memcache: MEMCACHE)
		@memcache = memcache
	end

	# @param q [String]
	# @return [EMPromise<GeoCode>]
	def find(q)
		req(q, locate: q)
	end

	# @param lat [Float]
	# @param lon [Float]
	# @return [EMPromise<GeoCode>]
	def reverse(lat, lon)
		req("reverse_#{lat}_#{lon}", latt: lat, longt: lon)
	end

protected

	# @param cache_key [String]
	# @param query [Hash]
	# @return [EMPromise<GeoCode>]
	def req(cache_key, **query)
		cache(cache_key) {
			EM::HttpRequest.new(
				"https://geocoder.ca/",
				tls: { verify_peer: true }
			).aget(query: { json: 1, **query }).then { |res|
				json = JSON.parse(res.response)
				raise "Geocode Failure" unless json["latt"] && json["longt"]

				json
			}
		}.then(&GeoCode.method(:for))
	end

	def cache(k, &blk)
		k = "geocode_#{k.gsub(/ /, '%20')}"
		promise = EMPromise.new
		@memcache.get(k, &promise.method(:fulfill))
		promise.then { |cbor|
			CBOR.decode(cbor)
		}.catch(&blk).then { |result|
			@memcache.set(k, result.to_cbor)
			result
		}
	end
end
