1# frozen_string_literal: true
  2
  3require_relative "admin_action_repo"
  4require_relative "admin_actions/add_invites"
  5require_relative "admin_actions/add_transaction"
  6require_relative "admin_actions/cancel"
  7require_relative "admin_actions/financial"
  8require_relative "admin_actions/reset_declines"
  9require_relative "admin_actions/set_trust_level"
 10require_relative "admin_actions/number_change"
 11require_relative "bill_plan_command"
 12require_relative "customer_info_form"
 13require_relative "financial_info"
 14require_relative "form_template"
 15
 16class AdminCommand
 17	def self.for(
 18		target_customer,
 19		customer_repo,
 20		admin_action_repo=AdminActionRepo.new
 21	)
 22		if target_customer
 23			new(target_customer, customer_repo, admin_action_repo)
 24		else
 25			NoUser.new(customer_repo, admin_action_repo, notice: "Customer Not Found")
 26		end
 27	end
 28
 29	class NoUser < AdminCommand
 30		def initialize(
 31			customer_repo,
 32			admin_action_repo=AdminActionRepo.new,
 33			notice: nil
 34		)
 35			@customer_repo = customer_repo
 36			@admin_action_repo = admin_action_repo
 37			@notice = notice
 38		end
 39
 40		def start(command_action=:execute)
 41			return Command.finish(@notice || "Done") if command_action == :complete
 42
 43			reply(
 44				FormTemplate.render("customer_picker", notice: @notice)
 45			).then { |response|
 46				new_context(response.form.field("q").value, response.action)
 47			}
 48		end
 49	end
 50
 51	def initialize(
 52		target_customer,
 53		customer_repo,
 54		admin_action_repo=AdminActionRepo.new
 55	)
 56		@target_customer = target_customer
 57		@customer_repo = customer_repo
 58		@admin_action_repo = admin_action_repo
 59	end
 60
 61	def start(command_action=:execute)
 62		AdminInfo.for(@target_customer).then { |info|
 63			if command_action == :complete
 64				Command.finish { |iq| iq.command << info.form }
 65			else
 66				reply(info.form)
 67			end
 68		}.then { |response| menu_or_done(response.action) }
 69	end
 70
 71	def reply(form)
 72		Command.reply { |reply|
 73			reply.allowed_actions = [:next, :complete]
 74			reply.command << form
 75		}
 76	end
 77
 78	def menu_or_done(command_action=:execute, notice: nil)
 79		return Command.finish("Done") if command_action == :complete
 80
 81		reply(FormTemplate.render("admin_menu", notice: notice)).then do |response|
 82			if response.form.field("action")
 83				handle(response.form.field("action").value, response.action)
 84			end
 85		end
 86	end
 87
 88	def handle(action, command_action)
 89		if respond_to?("action_#{action}")
 90			send("action_#{action}").then do |notice|
 91				menu_or_done(command_action, notice: notice)
 92			end
 93		else
 94			new_context(action)
 95		end
 96	end
 97
 98	def new_context(q, command_action=:execute)
 99		CustomerInfoForm.new(@customer_repo)
100			.parse_something(q).then do |new_customer|
101				AdminCommand.for(new_customer, @customer_repo, @admin_action_repo)
102					.then { |ac| ac.start(command_action) }
103			end
104	end
105
106	def action_info
107		# Refresh the data
108		new_context(@target_customer.customer_id)
109	end
110
111	def action_bill_plan
112		BillPlanCommand.for(@target_customer).call
113	end
114
115	class Undoable
116		def initialize(klass)
117			@klass = klass
118		end
119
120		def call(customer, admin_action_repo:, **)
121			@klass.for(customer, reply: method(:reply)).then { |action|
122				Command.customer.then { |actor|
123					action.with(actor_id: actor.customer_id).perform.then do |performed|
124						admin_action_repo.create(performed)
125					end
126				}
127			}.then { |action| "Action #{action.id}: #{action}" }
128		end
129
130		def reply(form=nil, note_type: nil, note_text: nil)
131			Command.reply { |reply|
132				reply.allowed_actions = [:next, :complete]
133				reply.command << form if form
134				reply.note_type = note_type if note_type
135				reply.note_text = note_text if note_text
136			}
137		end
138	end
139
140	class Simple
141		def initialize(klass)
142			@klass = klass
143		end
144
145		def call(customer_id, customer_repo:, **)
146			@klass.call(
147				customer_id,
148				reply: method(:reply),
149				customer_repo: customer_repo
150			).then { nil }
151		end
152
153		def reply(form=nil, note_type: nil, note_text: nil)
154			Command.reply { |reply|
155				reply.allowed_actions = [:next, :complete]
156				reply.command << form if form
157				reply.note_type = note_type if note_type
158				reply.note_text = note_text if note_text
159			}
160		end
161	end
162
163	class Undo
164		def self.for(target_customer, **)
165			AdminActionRepo.new
166				.find(1, customer_id: target_customer.customer_id)
167				.then { |actions|
168					raise "No actions found" if actions.empty?
169
170					actions.first.undo
171				}
172		end
173	end
174
175	[
176		[:cancel_account, Simple.new(AdminAction::CancelCustomer)],
177		[:financial, Simple.new(AdminAction::Financial)],
178		[:undo, Undoable.new(Undo)],
179		[:reset_declines, Undoable.new(AdminAction::ResetDeclines::Command)],
180		[:set_trust_level, Undoable.new(AdminAction::SetTrustLevel::Command)],
181		[:add_invites, Undoable.new(AdminAction::AddInvites::Command)],
182		[:number_change, Undoable.new(AdminAction::NumberChange::Command)],
183		[:add_transaction, Undoable.new(AdminAction::AddTransaction::Command)]
184	].each do |action, handler|
185		define_method("action_#{action}") do
186			handler.call(
187				@target_customer,
188				admin_action_repo: @admin_action_repo,
189				customer_repo: @customer_repo
190			)
191		end
192	end
193end