-- Portal Pro :: Core/Commands.lua

local ADDON_NAME, PP = ...
local U = PP.U

local Commands = PP:NewModule("Commands")

local ACCENT = "|cff4C9AFF"
local R = "|r"

local handlers = {}

local function usage()
	PP:Print("Commands:")
	local lines = {
		{ "",             "toggle the window" },
		{ "compact",      "toggle the slim bar" },
		{ "on / off",     "enable or disable chat detection" },
		{ "leads",        "list the current queue" },
		{ "clear",        "clear the lead queue" },
		{ "price <city> <amount>", "set a price, e.g. /pp price sw 12g" },
		{ "prices",       "show current pricing" },
		{ "market [mins]", "what the competition is charging" },
		{ "paid <name> <amount> [city]", "record a payment by hand" },
		{ "free",         "toggle free-cast mode (stop logging portals)" },
		{ "oops",         "untrack the portal you just cast" },
		{ "stats",        "print a session summary" },
		{ "export",       "dump the ledger as CSV" },
		{ "test <text>",  "score a message against the lead rules" },
		{ "debug",        "toggle verbose logging" },
		{ "sandbox",      "open the test-harness panel" },
		{ "version",      "show the version" },
	}
	for _, line in ipairs(lines) do
		print(("  %s/pp %s%s  -  %s"):format(ACCENT, line[1], R, line[2]))
	end
end

handlers[""] = function()
	PP.UI:Toggle()
end

handlers["help"] = usage

handlers["compact"] = function()
	if PP.CompactBar:IsShown() then
		PP.profile.ui.compact = false
		PP.CompactBar:Hide()
	else
		PP.profile.ui.compact = true
		PP.UI:Hide()
		PP.CompactBar:Show()
	end
end

handlers["on"] = function()
	PP.profile.detection.enabled = true
	PP:Print("Detection " .. ACCENT .. "enabled" .. R .. ".")
	PP.UI:RefreshCurrentTab()
end

handlers["off"] = function()
	PP.profile.detection.enabled = false
	PP:Print("Detection " .. ACCENT .. "disabled" .. R .. ".")
	PP.UI:RefreshCurrentTab()
end

handlers["leads"] = function()
	local queue = PP.Leads.queue
	if #queue == 0 then
		PP:Print("No leads waiting.")
		return
	end
	PP:Print(("%d lead(s):"):format(#queue))
	for _, lead in ipairs(queue) do
		print(("  %s%s%s - %s (%s, %s ago)"):format(
			ACCENT, lead.name, R,
			lead.dest and lead.dest.name or "unknown destination",
			lead.channelLabel or lead.channel,
			U.Ago(lead.ts)))
	end
end

handlers["clear"] = function()
	PP.Leads:Clear()
	PP:Print("Lead queue cleared.")
end

handlers["price"] = function(args)
	local key, amount = args:match("^(%S+)%s+(.+)$")
	if not key then
		PP:Warn("Usage: /pp price <city> <amount>   e.g.  /pp price sw 12g")
		return
	end

	local dest = PP.Dest:Resolve(U.Normalize(key))
	if not dest then
		PP:Warn("Unknown city: " .. key)
		return
	end

	local copper = U.ParseMoney(amount)
	if not copper then
		PP:Warn("Couldn't read that amount. Try 12g, 5g50s, or 250s.")
		return
	end

	PP.Dest:SetPrice(dest.key, copper)
	PP:Print(("%s is now %s."):format(dest.name, U.MoneyPlain(copper)))
end

handlers["prices"] = function()
	PP:Print("Pricing:")
	print(("  default  %s"):format(U.MoneyPlain(PP.profile.prices.default)))
	for _, dest in ipairs(PP.Dest:Available()) do
		local explicit = PP.profile.prices[dest.key]
		print(("  %-14s %s%s"):format(dest.name, U.MoneyPlain(PP.Dest:Price(dest)),
			explicit and "" or "  (default)"))
	end
end

--- Manual entry, for a payment the automatic capture missed.
handlers["paid"] = function(args)
	local name, rest = args:match("^(%S+)%s+(.+)$")
	if not name then
		PP:Warn("Usage: /pp paid <name> <amount> [city]   e.g.  /pp paid Shekza 10g uc")
		return
	end

	local amountStr, cityStr = rest:match("^(%S+)%s*(.*)$")
	local copper = U.ParseMoney(amountStr)
	if not copper then
		PP:Warn("Couldn't read that amount. Try 10g, 5g50s, or 250s.")
		return
	end

	local dest
	if cityStr and cityStr ~= "" then
		dest = PP.Dest:Resolve(U.Normalize(cityStr))
	end

	PP.Ledger:RecordPayment(name, copper, dest and dest.key or nil, "manual", "entered by hand")
	-- Go through the real event so the lead queue and stats react as they would to a
	-- captured trade.
	PP:Fire("PAYMENT_RECEIVED", name, copper, dest and dest.key or nil)

	PP:Print(("Recorded %s from %s%s."):format(
		U.MoneyPlain(copper), name, dest and (" for " .. dest.name) or ""))
end

handlers["market"] = function(args)
	local window = tonumber(args) and tonumber(args) * 60 or 3600
	local summary = PP.Market:Summary(window)

	PP:Print(("Market, last %s:"):format(U.Duration(window)))
	if summary.ask.median then
		print(("  competition  %s median from %d mage(s), %s to %s"):format(
			U.MoneyPlain(summary.ask.median), summary.ask.advertisers,
			U.MoneyPlain(summary.ask.low), U.MoneyPlain(summary.ask.high)))
	else
		print("  competition  no adverts seen")
	end
	if summary.bid.median then
		print(("  demand       %s median from %d customer(s)"):format(
			U.MoneyPlain(summary.bid.median), summary.bid.advertisers))
	else
		print("  demand       no customer offers seen")
	end
	print(("  your price   %s"):format(U.MoneyPlain(PP.profile.prices.default)))

	for _, dest in ipairs(PP.Dest:Available()) do
		local verdict, delta = PP.Market:CompareToMarket(dest.key, window)
		if verdict then
			print(("  %-14s %s (%s%s)"):format(dest.name, U.MoneyPlain(PP.Dest:Price(dest)),
				verdict, verdict == "at" and "" or " by " .. U.MoneyPlain(math.abs(delta))))
		end
	end
end

handlers["free"] = function()
	PP.CastTracker:ToggleFreeMode()
	PP.UI:RefreshCurrentTab()
end

--- For the moment you realise the portal you just opened shouldn't have been billed.
handlers["oops"] = function()
	local ok, message = PP.CastTracker:UntrackLast()
	if ok then PP:Print(message) else PP:Warn(message) end
end

handlers["stats"] = function()
	local totals = PP.Stats:Totals("session")
	local funnel = PP.Stats:Funnel()
	local portals, teleports = PP.CastTracker:CountSince(PP.Stats:SessionStart())

	PP:Print("Session summary:")
	print(("  active     %s"):format(U.Duration(PP.Stats:ActiveSeconds())))
	print(("  gross      %s"):format(U.MoneyPlain(totals.gross)))
	print(("  refunds    %s"):format(U.MoneyPlain(totals.refunds)))
	print(("  reagents   %s"):format(U.MoneyPlain(totals.reagents)))
	print(("  net        %s"):format(U.MoneyPlain(totals.net)))
	print(("  gold/hour  %s"):format(U.MoneyPlain(PP.Stats:GoldPerHour("session"))))
	print(("  casts      %d portals, %d teleports"):format(portals, teleports))
	print(("  funnel     %d leads -> %d whispered -> %d invited -> %d paid"):format(
		funnel.leads, funnel.whispers, funnel.invites, funnel.paid))
end

handlers["export"] = function()
	PP:Print("Ledger CSV follows. Use the Export button on the Ledger tab for a copyable box.")
	print(PP.Ledger:ExportCSV())
end

handlers["test"] = function(args)
	if args == "" then
		PP:Warn("Usage: /pp test lf port to sw")
		return
	end
	local score, dest, reasons = PP.Leads:Score(args)
	PP:Print(("Score %d (threshold 3) - %s"):format(score, score >= 3 and "MATCH" or "no match"))
	if dest then print("  destination: " .. dest.name) end
	for _, reason in ipairs(reasons) do print("  " .. reason) end
end

handlers["debug"] = function()
	PP.global.debug = not PP.global.debug
	PP:Print("Debug logging " .. (PP.global.debug and "on" or "off") .. ".")
end

handlers["sandbox"] = function()
	PP.Sandbox:Toggle()
end

handlers["version"] = function()
	PP:Print(("version %s - Classic Era build"):format(PP.version))
	local outdated, newest = PP.Comms:IsOutdated()
	if outdated then
		print(("  |cff34D399%s|r is available - seen from %s"):format(
			newest, PP.Comms.newestFrom or "another player"))
	else
		print("  " .. (select(1, PP.Comms:StatusText())))
	end
end

function Commands:OnEnable()
	SLASH_PORTALPRO1 = "/pp"
	SLASH_PORTALPRO2 = "/portalpro"

	SlashCmdList["PORTALPRO"] = function(input)
		input = U.Trim(input or "")
		local command, rest = input:match("^(%S*)%s*(.*)$")
		command = (command or ""):lower()

		local handler = handlers[command]
		if handler then
			handler(rest or "")
		else
			PP:Warn("Unknown command: " .. command)
			usage()
		end
	end
end
