-- MarketWatch Tutorial.lua
-- Forced first-run tutorial. Addon stays locked (main window unreachable)
-- until this is completed once per ACCOUNT (db.global, not db.profile).
-- Chat capture keeps running in the background the whole time - only the
-- UI is gated.

MW = MW or {}
MW.UI = MW.UI or {}
MW.Tutorial = {}

local IMG_PATH = "Interface\\AddOns\\MarketWatch\\Images\\Tutorial\\"

local TUTORIAL_PAGES = {
	{ image = "Tut0", text = "Pressing any of the category buttons, will apply a filter showing only results from that specific category, \"All\" is for everything combined" },
	{ image = "Tut1", text = "Right-Clicking on any of the active listings, you will get a dropdown with different options" },
	{ image = "Tut2", text = "Bottom-right corner of the addon contains the different Configurable modules, you manage Saved Listings, Blacklists, and Keywords from there" },
	{ image = "Tut3", text = "In Config, you adjust which categories you want to track, the Addon Size, Lifetime of the messages (How Long they Stay Cached), and The sources from which to scan for new incoming listings" },
	{ image = "Tut4", text = "Adding a Keyword, will automatically scan every listing and will highlight in Red, each message that contains that keyword, for example if you want to buy \"Primordial's\" you Type \"Primordial\" or \"Primo\" and it will highlight it for you." },
	{ image = "Tut5", text = "Blacklists are self-explanatory, you can blacklist anyone which will resolve into all messages from that sender being hidden" },
	{ image = "Tut6", text = "Saved listings is the place, where you can save different deals that you might plan to purchase/sell in the future, just for safekeeping" },
}

local QUIZ_QUESTION = "How do you Blacklist Someone?"
local QUIZ_ANSWERS = {
	"By Calling Police",
	"By Right-Clicking his Name",
	"By walking my Dog",
	"I no Speak Englies",
}
local QUIZ_CORRECT_INDEX = 2

local MAX_ATTEMPTS = 10
local WARNING_AT_ATTEMPT = 5
local LOCKOUT_SECONDS = 300 -- 5 minutes

--------------------------------------------------------------------
-- Generic fade helper. Manual OnUpdate-driven alpha tween rather than
-- UIFrameFadeIn/Out, for consistent, predictable callback behavior with
-- the rest of this addon's animation code (title weave, border glow).
--------------------------------------------------------------------
local function FadeFrame(frame, fromAlpha, toAlpha, duration, onComplete)
	frame:SetAlpha(fromAlpha)
	frame:Show()

	local elapsedTotal = 0
	local ticker = CreateFrame("Frame")
	ticker:SetScript("OnUpdate", function(self, elapsed)
		elapsedTotal = elapsedTotal + elapsed
		local t = math.min(elapsedTotal / duration, 1)
		frame:SetAlpha(fromAlpha + (toAlpha - fromAlpha) * t)
		if t >= 1 then
			self:SetScript("OnUpdate", nil)
			if onComplete then onComplete() end
		end
	end)
end

--------------------------------------------------------------------
-- Lock Overlay
--------------------------------------------------------------------
local lockFrame
local startBtn

-- Now lives INSIDE MarketWatchFrame (as a covering child) instead of its
-- own floating popup, so the "locked" state reads as part of the main
-- window rather than a separate box.
local function BuildLockOverlay()
	if lockFrame then return end

	local mainFrame = _G["MarketWatchFrame"]
	if not mainFrame then return end

	-- Parented to UIParent, not mainFrame, so this is always rendered at true
	-- 100% scale regardless of whatever scale the user has set for the main
	-- tracker (Config isn't gated by the lock, so a still-locked user could
	-- otherwise open Config and change the scale, shrinking/hiding this
	-- overlay's button along with it).
	lockFrame = CreateFrame("Frame", "MW_LockOverlay", UIParent)
	-- Explicit strata is required here - this frame no longer inherits one
	-- from a parent (see the UIParent reparenting note above), and every
	-- other popup in this addon (Blacklist/Keyword/Copy/Saved Listings/the
	-- ending sequence) already sets its own strata rather than relying on
	-- inheritance, for exactly this reason: without it, this can render
	-- BEHIND the main window's own content instead of on top of it.
	lockFrame:SetFrameStrata("FULLSCREEN_DIALOG")
	lockFrame:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 16, -40)
	lockFrame:SetPoint("BOTTOMRIGHT", mainFrame, "BOTTOMRIGHT", -16, 16)
	lockFrame:SetFrameLevel(mainFrame:GetFrameLevel() + 50)
	lockFrame:EnableMouse(true)

	-- dragging the covered area still moves the whole window
	lockFrame:RegisterForDrag("LeftButton")
	lockFrame:SetScript("OnDragStart", function() mainFrame:StartMoving() end)
	lockFrame:SetScript("OnDragStop", function() mainFrame:StopMovingOrSizing() end)

	lockFrame:SetBackdrop({
		bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
		edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
		tile = true, tileSize = 16, edgeSize = 16,
		insets = { left = 4, right = 4, top = 4, bottom = 4 },
	})
	lockFrame:SetBackdropColor(0.02, 0.02, 0.02, 0.97)
	lockFrame:SetBackdropBorderColor(0.8, 0.1, 0.1, 1)

	local stopFS = lockFrame:CreateFontString(nil, "OVERLAY")
	stopFS:SetFont("Fonts\\FRIZQT__.TTF", 34, "OUTLINE")
	stopFS:SetPoint("TOP", lockFrame, "TOP", 0, -60)
	stopFS:SetJustifyH("CENTER")
	stopFS:SetText("|cffff0000STOP!|r")

	local lockedFS = lockFrame:CreateFontString(nil, "OVERLAY")
	lockedFS:SetFont("Fonts\\FRIZQT__.TTF", 22, "OUTLINE")
	lockedFS:SetPoint("TOP", stopFS, "BOTTOM", 0, -6)
	lockedFS:SetJustifyH("CENTER")
	lockedFS:SetText("|cffff4444Addon is LOCKED|r")

	local icon = lockFrame:CreateTexture(nil, "ARTWORK")
	icon:SetTexture("Interface\\Icons\\inv_misc_key_03")
	icon:SetSize(60, 60)
	icon:SetPoint("TOP", lockedFS, "BOTTOM", 0, -12)

	-- Made deliberately hard to miss: larger, gold border panel behind it,
	-- bright colored label text, and anchored close to the icon rather
	-- than stacked further down under three other elements.
	local btnPanel = CreateFrame("Frame", nil, lockFrame)
	btnPanel:SetSize(220, 46)
	btnPanel:SetPoint("TOP", icon, "BOTTOM", 0, -18)
	btnPanel:SetBackdrop({
		bgFile = "Interface\\Buttons\\WHITE8X8",
		edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
		tile = false, edgeSize = 12,
		insets = { left = 3, right = 3, top = 3, bottom = 3 },
	})
	btnPanel:SetBackdropColor(0.15, 0.1, 0, 0.9)
	btnPanel:SetBackdropBorderColor(1, 0.82, 0, 1)
	btnPanel:EnableMouse(false)

	-- startBtn is parented directly to lockFrame (same as stopFS/lockedFS/
	-- icon, which always rendered fine) rather than to btnPanel - btnPanel
	-- is purely decorative art behind it now. Some client builds don't
	-- reliably propagate frame level/strata/enabled-state through an extra
	-- plain-Frame parent for template-inherited widgets, which was making
	-- this button render dim and eat clicks with no Lua error to show for it.
	startBtn = CreateFrame("Button", nil, lockFrame, "UIPanelButtonTemplate")
	startBtn:SetSize(200, 32)
	startBtn:SetPoint("CENTER", btnPanel, "CENTER", 0, 0)
	startBtn:SetFrameLevel(lockFrame:GetFrameLevel() + 5)
	startBtn:SetText("|cffffd200Start Tutorial|r")
	startBtn:SetScript("OnClick", function()
		lockFrame:Hide()
		MW.Tutorial.Start()
	end)
	startBtn:Enable()
	MW_SkinButton(startBtn)
	startBtn:Show()

	lockFrame:Hide()
end

function MW.UI.ShowLockOverlay()
	local mainFrame = _G["MarketWatchFrame"]
	if not mainFrame then return end

	BuildLockOverlay()
	if startBtn then
		local gdb = MarketWatch.db and MarketWatch.db.global
		if gdb and gdb.tutorialInProgress then
			startBtn:SetText("Resume Tutorial")
		else
			startBtn:SetText("Start Tutorial")
		end
	end

	-- lockFrame and tutFrame cover the exact same rectangle. Re-opening the
	-- addon (e.g. the minimap button) while the tutorial is already
	-- mid-session must not leave both shown at once - two stacked
	-- semi-transparent panels wash each other out, making the STOP text
	-- and the Resume/Start button underneath look faint and unclickable.
	if tutFrame then tutFrame:Hide() end

	mainFrame:Show()
	lockFrame:Show()
end

--------------------------------------------------------------------
-- Tutorial window
--------------------------------------------------------------------
local IMG_W, IMG_H = 616, 308 -- 10% larger than the original 560x280

local tutFrame
local imgTex, captionFS, pageIndicatorFS, prevBtn, nextBtn

local quizQuestionFS, quizWrongFS, quizLockoutFS, submitBtn
local answerButtons = {}

local currentPage = 0 -- 0..6 = image pages, 7 = quiz
local selectedAnswer = nil
local lockoutTicker

local function GetGlobalDB()
	return MarketWatch.db.global
end

local function RenderImagePage(index)
	local page = TUTORIAL_PAGES[index + 1]

	imgTex:SetTexture(IMG_PATH .. page.image)
	captionFS:SetText(page.text)
	pageIndicatorFS:SetText("Page " .. (index + 1) .. " of 7")

	imgTex:Show()
	captionFS:Show()
	pageIndicatorFS:Show()
	if index > 0 then
		prevBtn:Show()
	else
		prevBtn:Hide()
	end
	nextBtn:Show()
	nextBtn:SetText(index == 6 and "Continue" or "Next")

	quizQuestionFS:Hide()
	quizWrongFS:Hide()
	quizLockoutFS:Hide()
	submitBtn:Hide()
	for _, btn in ipairs(answerButtons) do
		btn:Hide()
		btn.label:Hide()
	end
end

local function StopLockoutTicker()
	if lockoutTicker then
		lockoutTicker:SetScript("OnUpdate", nil)
		lockoutTicker = nil
	end
end

local function SetQuizInteractive(interactive)
	if interactive then
		submitBtn:Enable()
	else
		submitBtn:Disable()
	end
	for _, btn in ipairs(answerButtons) do
		if interactive then
			btn:Enable()
		else
			btn:Disable()
		end
	end
end

local function StartLockoutCountdown()
	StopLockoutTicker()
	SetQuizInteractive(false)
	quizLockoutFS:Show()

	local elapsedAccum = 0
	lockoutTicker = CreateFrame("Frame")
	lockoutTicker:SetScript("OnUpdate", function(self, elapsed)
		if not tutFrame or not tutFrame:IsShown() then return end

		elapsedAccum = elapsedAccum + elapsed
		if elapsedAccum < 1 then return end -- once a second is plenty for a countdown
		elapsedAccum = 0

		local remaining = (GetGlobalDB().quizLockoutUntil or 0) - time()
		if remaining <= 0 then
			StopLockoutTicker()
			quizLockoutFS:Hide()
			SetQuizInteractive(true)
			GetGlobalDB().quizAttempts = 0
		else
			local mm = math.floor(remaining / 60)
			local ss = remaining % 60
			quizLockoutFS:SetText(string.format("|cffff0000Locked out - try again in %d:%02d|r", mm, ss))
		end
	end)
end

local function RenderQuizPage()
	imgTex:Hide()
	captionFS:Hide()
	pageIndicatorFS:Hide()
	nextBtn:Hide()
	prevBtn:Show() -- lets them re-read the last image page before answering

	quizQuestionFS:Show()
	quizQuestionFS:SetText(QUIZ_QUESTION)
	quizWrongFS:Hide()
	submitBtn:Show()

	selectedAnswer = nil
	for _, btn in ipairs(answerButtons) do
		btn:Show()
		btn.label:Show()
		btn:SetChecked(false)
	end

	local remaining = (GetGlobalDB().quizLockoutUntil or 0) - time()
	if remaining > 0 then
		StartLockoutCountdown()
	else
		quizLockoutFS:Hide()
		SetQuizInteractive(true)
		-- Mirror the ticker's own reset (line ~273) - if the lockout expired
		-- while this window wasn't open to run that ticker, the attempt
		-- count would otherwise stay maxed out and re-trigger a lockout on
		-- the very next wrong answer instead of granting a fresh set of tries.
		GetGlobalDB().quizAttempts = 0
	end
end

local function GoToPage(newPage)
	currentPage = newPage
	local gdb = GetGlobalDB()
	gdb.tutorialPage = newPage
	gdb.tutorialInProgress = true
	if newPage <= 6 then
		RenderImagePage(newPage)
	else
		RenderQuizPage()
	end
end

--------------------------------------------------------------------
-- Ending sequence
--------------------------------------------------------------------
local endFrame

local function BuildEndFrame()
	if endFrame then return end

	endFrame = CreateFrame("Frame", "MW_TutorialEndFrame", UIParent)
	endFrame:SetSize(512, 512)
	endFrame:SetPoint("CENTER")
	endFrame:SetFrameStrata("FULLSCREEN_DIALOG")
	endFrame:SetFrameLevel(200)

	local tex = endFrame:CreateTexture(nil, "OVERLAY")
	tex:SetAllPoints(endFrame)
	tex:SetTexture(IMG_PATH .. "EndTut")

	endFrame:Hide()
end

local function PlayEndingSequence()
	BuildEndFrame()
	tutFrame:Hide()
	StopLockoutTicker()

	-- MarketWatchFrame stays open behind the tutorial nowadays, so hide it
	-- here: it avoids a flash of the (still-locked-feeling) tabs behind the
	-- ending art, and it means the ToggleMain() below actually re-opens the
	-- window instead of closing it (it's a toggle, and the frame would
	-- otherwise still count as "shown").
	local mainFrame = _G["MarketWatchFrame"]
	if mainFrame then mainFrame:Hide() end

	FadeFrame(endFrame, 0, 1, 2.0, function()
		MarketWatch:ScheduleTimer(function()
			FadeFrame(endFrame, 1, 0, 1.5, function()
				endFrame:Hide()

				local gdb = GetGlobalDB()
				gdb.tutorialCompleted = true
				gdb.tutorialInProgress = false
				gdb.tutorialPage = 0
				gdb.quizAttempts = 0
				gdb.quizLockoutUntil = 0

				MW.UI.ToggleMain() -- now unlocked - opens the real tracker
			end)
		end, 1.5) -- hold time at full opacity before fading out
	end)
end

--------------------------------------------------------------------
-- Quiz answer submission
--------------------------------------------------------------------
local function SubmitAnswer()
	if not selectedAnswer then
		quizWrongFS:Show()
		quizWrongFS:SetText("|cffffaa00Pick an answer first.|r")
		return
	end

	local remaining = (GetGlobalDB().quizLockoutUntil or 0) - time()
	if remaining > 0 then return end -- still locked out, ignore

	if selectedAnswer == QUIZ_CORRECT_INDEX then
		PlayEndingSequence()
		return
	end

	local gdb = GetGlobalDB()
	gdb.quizAttempts = (gdb.quizAttempts or 0) + 1
	local attempts = gdb.quizAttempts
	local triesLeft = MAX_ATTEMPTS - attempts

	if attempts >= MAX_ATTEMPTS then
		gdb.quizLockoutUntil = time() + LOCKOUT_SECONDS
		quizWrongFS:Show()
		quizWrongFS:SetText("|cffff0000Wrong Answer!|r |cffff6666Too many failed attempts - locked out for 5 minutes.|r")
		StartLockoutCountdown()
	elseif attempts == WARNING_AT_ATTEMPT then
		quizWrongFS:Show()
		quizWrongFS:SetText("|cffff0000Wrong Answer!|r |cffffaa00Warning: reaching 10 failed attempts locks you out for 5 minutes. (" .. triesLeft .. " tries left)|r")
	else
		quizWrongFS:Show()
		quizWrongFS:SetText("|cffff0000Wrong Answer!|r  (" .. triesLeft .. " tries left)")
	end
end

--------------------------------------------------------------------
-- Frame construction
--------------------------------------------------------------------
local function BuildTutorialFrame()
	if tutFrame then return end

	local mainFrame = _G["MarketWatchFrame"]
	if not mainFrame then return end

	-- lives inside MarketWatchFrame as a covering child (below the title,
	-- above the tabs/list) instead of its own floating popup
	-- Same reasoning as lockFrame above: parented to UIParent so the forced
	-- tutorial is never affected by whatever scale the main tracker has.
	tutFrame = CreateFrame("Frame", "MW_TutorialFrame", UIParent)
	-- Same reasoning as lockFrame's strata comment above.
	tutFrame:SetFrameStrata("FULLSCREEN_DIALOG")
	tutFrame:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 16, -40)
	tutFrame:SetPoint("BOTTOMRIGHT", mainFrame, "BOTTOMRIGHT", -16, 16)
	tutFrame:SetFrameLevel(mainFrame:GetFrameLevel() + 50)
	tutFrame:EnableMouse(true)

	-- dragging the covered area still moves the whole window
	tutFrame:RegisterForDrag("LeftButton")
	tutFrame:SetScript("OnDragStart", function() mainFrame:StartMoving() end)
	tutFrame:SetScript("OnDragStop", function() mainFrame:StopMovingOrSizing() end)

	tutFrame:SetBackdrop({
		bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
		edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
		tile = true, tileSize = 16, edgeSize = 16,
		insets = { left = 4, right = 4, top = 4, bottom = 4 },
	})
	tutFrame:SetBackdropColor(0.03, 0.03, 0.04, 0.97)
	tutFrame:SetBackdropBorderColor(0.8, 0.65, 0.2, 0.9)

	pageIndicatorFS = tutFrame:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
	pageIndicatorFS:SetPoint("TOP", 0, -14)

	-- image, scaled to sit in the upper two-thirds
	imgTex = tutFrame:CreateTexture(nil, "ARTWORK")
	imgTex:SetSize(IMG_W, IMG_H)
	imgTex:SetPoint("TOP", 0, -34)

	-- caption: centered paragraph, word-wrapped, below the image
	captionFS = tutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
	captionFS:SetPoint("TOP", imgTex, "BOTTOM", 0, -16)
	captionFS:SetWidth(650)
	captionFS:SetJustifyH("CENTER")
	captionFS:SetJustifyV("TOP")
	captionFS:SetWordWrap(true)
	captionFS:SetSpacing(4)

	-- Previous / Next, centered as a pair under the caption
	-- y=60 (not 26) so these clear the main window's own footer button row
	-- (Config/Saved Listings/Blacklist/Keywords, ~20-44px above the window's
	-- bottom edge) instead of landing almost exactly on top of it.
	prevBtn = CreateFrame("Button", nil, tutFrame, "UIPanelButtonTemplate")
	prevBtn:SetSize(90, 26)
	prevBtn:SetPoint("BOTTOM", tutFrame, "BOTTOM", -50, 60)
	-- Same fix as the lock overlay's Start/Resume button: explicit frame
	-- level above tutFrame plus an explicit Enable().
	prevBtn:SetFrameLevel(tutFrame:GetFrameLevel() + 5)
	prevBtn:SetText("Previous")
	prevBtn:SetScript("OnClick", function()
		if currentPage > 0 then
			GoToPage(currentPage - 1)
		end
	end)
	prevBtn:Enable()
	MW_SkinButton(prevBtn)

	nextBtn = CreateFrame("Button", nil, tutFrame, "UIPanelButtonTemplate")
	nextBtn:SetSize(90, 26)
	nextBtn:SetPoint("BOTTOM", tutFrame, "BOTTOM", 50, 60)
	nextBtn:SetFrameLevel(tutFrame:GetFrameLevel() + 5)
	nextBtn:SetText("Next")
	nextBtn:SetScript("OnClick", function()
		if currentPage < 6 then
			GoToPage(currentPage + 1)
		else
			GoToPage(7)
		end
	end)
	nextBtn:Enable()
	MW_SkinButton(nextBtn)

	----------------------------------------------------------------
	-- Quiz elements (built once, toggled visible on page 7)
	----------------------------------------------------------------
	quizQuestionFS = tutFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
	quizQuestionFS:SetPoint("TOP", 0, -70)
	quizQuestionFS:SetWidth(600)
	quizQuestionFS:SetJustifyH("CENTER")
	quizQuestionFS:Hide()

	for i = 1, 4 do
		local btn = CreateFrame("CheckButton", "MW_QuizAnswer" .. i, tutFrame, "UIRadioButtonTemplate")
		btn:SetPoint("TOP", quizQuestionFS, "BOTTOM", -60, -30 - (i - 1) * 34)
		btn:SetFrameLevel(tutFrame:GetFrameLevel() + 5)

		local label = tutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
		label:SetPoint("LEFT", btn, "RIGHT", 6, 1)
		label:SetText(QUIZ_ANSWERS[i])
		btn.label = label

		btn:SetScript("OnClick", function()
			selectedAnswer = i
			for j, b in ipairs(answerButtons) do
				b:SetChecked(j == i)
			end
			quizWrongFS:Hide()
		end)

		btn:Enable()
		btn:Hide()
		label:Hide()
		answerButtons[i] = btn
	end

	submitBtn = CreateFrame("Button", nil, tutFrame, "UIPanelButtonTemplate")
	submitBtn:SetSize(140, 26)
	submitBtn:SetPoint("TOP", answerButtons[4], "BOTTOM", 60, -20)
	submitBtn:SetFrameLevel(tutFrame:GetFrameLevel() + 5)
	submitBtn:SetText("Submit Answer")
	submitBtn:SetScript("OnClick", SubmitAnswer)
	submitBtn:Enable()
	MW_SkinButton(submitBtn)
	submitBtn:Hide()

	quizWrongFS = tutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
	quizWrongFS:SetPoint("TOP", submitBtn, "BOTTOM", 0, -14)
	quizWrongFS:SetWidth(620)
	quizWrongFS:SetJustifyH("CENTER")
	quizWrongFS:SetWordWrap(true)
	quizWrongFS:Hide()

	quizLockoutFS = tutFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
	quizLockoutFS:SetPoint("TOP", submitBtn, "BOTTOM", 0, -14)
	quizLockoutFS:Hide()

	tutFrame:Hide()
end

function MW.Tutorial.Start()
	BuildTutorialFrame()
	if not tutFrame then return end -- MarketWatchFrame wasn't ready yet

	if lockFrame then lockFrame:Hide() end

	local mainFrame = _G["MarketWatchFrame"]
	if mainFrame then mainFrame:Show() end

	local gdb = GetGlobalDB()
	currentPage = tonumber(gdb.tutorialPage) or 0
	if currentPage < 0 or currentPage > 7 then
		currentPage = 0
	end
	gdb.tutorialInProgress = true
	selectedAnswer = nil
	tutFrame:SetAlpha(1)
	tutFrame:Show()
	if currentPage <= 6 then
		RenderImagePage(currentPage)
	else
		RenderQuizPage()
	end
end

--------------------------------------------------------------------
-- lockFrame/tutFrame are parented to UIParent, not MarketWatchFrame (see
-- the scale-independence comments above), so they're independent toplevel
-- frames now rather than real children - closing the main window (X
-- button, /mw toggle, etc.) no longer automatically hides them the way a
-- true child frame would. Hook mainFrame's OnHide so closing it always
-- takes both overlays down with it, regardless of which one is open.
--------------------------------------------------------------------
do
	local mainFrame = _G["MarketWatchFrame"]
	if mainFrame then
		mainFrame:HookScript("OnHide", function()
			if lockFrame then lockFrame:Hide() end
			if tutFrame then tutFrame:Hide() end
		end)
	end
end
