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