# frozen_string_literal: true

require "em-http"
require "em-synchrony/em-http" # For apost vs post
require "json"
require "lazy_object"
require "value_semantics/monkey_patched"

require_relative "sim"

class SIMRepo
	value_semantics do
		db Anything(), default: LazyObject.new { DB }
	end

	KEEPGO_HEADERS = {
		"Accept" => "application/json",
		"apiKey" => CONFIG[:keepgo][:api_key],
		"accessToken" => CONFIG[:keepgo][:access_token]
	}.freeze

	def all(start_page=1)
		req("lines").aget(
			head: KEEPGO_HEADERS, query: { page: start_page, per_page: 1000 }
		).then { |req|
			result = JSON.parse(req.response)
			sims = result.dig("sim_cards", "items")&.map(&SIM.method(:extract))

			next sims if result.dig("sim_cards", "last_page") == start_page
			next [] if !sims || sims.empty?

			all(start_page + 1).then { |next_page| sims + next_page }
		}
	end

	def find(iccid)
		req("line/#{iccid}/get_details").aget(head: KEEPGO_HEADERS).then { |req|
			SIM.extract(JSON.parse(req.response)&.dig("sim_card"))
		}
	end

	def refill(sim, **kwargs)
		iccid = sim.is_a?(String) ? sim : sim.iccid

		req("line/#{iccid}/refill").apost(
			head: KEEPGO_HEADERS.merge("Content-Type" => "application/json"),
			body: kwargs.to_json
		).then { |req| JSON.parse(req.response) }
	end

	def owned_by(customer)
		customer = customer.customer_id if customer.respond_to?(:customer_id)
		promise = db.query_defer(<<~SQL, [customer])
			SELECT iccid, nickname FROM sims WHERE customer_id=$1
		SQL
		promise.then { |result|
			EMPromise.all(result.map { |row|
				find(row["iccid"]).then { |sim| sim.with(nickname: row["nickname"]) }
			})
		}
	end

	def put_owner(sim, customer, nickname=nil)
		db.exec(<<~SQL, [customer.customer_id, sim.iccid, nickname])
			UPDATE sims SET customer_id=$1, nickname=COALESCE($3, nickname) WHERE iccid=$2 AND customer_id IS NULL
		SQL
	end

	def available
		db.query_defer(<<~SQL).then { |r| find(r.first["iccid"]) }
			SELECT iccid FROM sims WHERE customer_id IS NULL LIMIT 1
		SQL
	end

protected

	def req(path)
		EM::HttpRequest.new(
			"https://myaccount.keepgo.com/api/v2/#{path}",
			tls: { verify_peer: true }
		)
	end
end
