# frozen_string_literal: true

require "bigdecimal/util"

require_relative "low_balance"
require_relative "transaction"

class SIMOrder
	def self.for(customer, price:, **kwargs)
		price = price.to_i / 100.to_d
		return new(customer, price: price, **kwargs) if customer.balance >= price

		LowBalance::AutoTopUp.for(customer, price).then do |top_up|
			if top_up.can_top_up?
				WithTopUp.new(customer, self, price: price, top_up: top_up, **kwargs)
			else
				PleaseTopUp.new(price: price, **kwargs)
			end
		end
	end

	def self.label
		"SIM"
	end

	def self.fillable_fields
		[
			{
				type: "text-multi",
				label: "Shipping Address",
				var: "addr",
				required: true
			}
		]
	end

	def initialize(customer, price:, plan:)
		@customer = customer
		@price = price
		@plan = plan
		@sim_repo = SIMRepo.new(db: DB)
	end

	def form
		FormTemplate.render(
			"order_sim/with_balance",
			price: @price,
			plan: @plan,
			label: self.class.label,
			fillable_fields: self.class.fillable_fields
		)
	end

	def complete(iq)
		addr = Array(iq.form.field("addr").value).join("\n")
		EMPromise.resolve(nil).then { commit }.then do |sim|
			@customer.stanza_from(Blather::Stanza::Message.new(
				Blather::JID.new(""), # Doesn't matter, sgx is set to direct target
				"SIM ORDER: #{sim.iccid}\n#{addr}"
			))
			Command.finish(
				"You will receive an notice from support when your SIM ships."
			)
		end
	end

protected

	def commit
		DB.transaction do
			sim = @sim_repo.available.sync
			@sim_repo.put_owner(sim, @customer, self.class.label)
			keepgo_tx = @sim_repo.refill(sim, amount_mb: 1024).sync
			raise "SIM activation failed" unless keepgo_tx["ack"] == "success"

			transaction(sim, keepgo_tx).insert_tx
			sim
		end
	end

	def transaction(sim, keepgo_tx)
		Transaction.new(
			customer_id: @customer.customer_id,
			transaction_id: keepgo_tx["transaction_id"],
			amount: -@price,
			note: "#{self.class.label} Activation #{sim.iccid}"
		)
	end

	class ESIM < SIMOrder
		def self.label
			"eSIM"
		end

		def self.fillable_fields
			[]
		end

		def complete(_)
			EMPromise.resolve(nil).then { commit }.then do |sim|
				Command.finish do |reply|
					oob = OOB.find_or_create(reply.command)
					oob.url = sim.lpa_code
					oob.desc = "LPA Activation Code"
					reply.command << FormTemplate.render(
						"order_sim/esim_complete", sim: sim
					)
				end
			end
		end
	end

	class WithTopUp
		def initialize(customer, continue, price:, plan:, top_up:)
			@customer = customer
			@price = price
			@plan = plan
			@top_up = top_up
			@continue = continue
		end

		def form
			FormTemplate.render(
				"order_sim/with_top_up",
				price: @price,
				plan: @plan,
				top_up_amount: @top_up.top_up_amount,
				label: @continue.label,
				fillable_fields: @continue.fillable_fields
			)
		end

		def complete(iq)
			@top_up.notify!.then do |amount|
				if amount.positive?
					@continue.new(@customer, price: @price, plan: @plan).complete(iq)
				else
					Command.finish("Could not top up", type: :error)
				end
			end
		end
	end

	class PleaseTopUp
		def initialize(price:, plan:)
			@price = price
			@plan = plan
		end

		def form
			FormTemplate.render(
				"order_sim/please_top_up",
				price: @price,
				plan: @plan
			)
		end

		def complete(_)
			Command.finish
		end
	end
end
