local _, GF = ...

GF.UsageGuideDialog = {}
local UGD = GF.UsageGuideDialog

local DIALOG_W = 640
local DIALOG_H = 450
local BODY_LEFT = 44
local BODY_RIGHT = 44
local BODY_TOP = -54
local BODY_BOTTOM = 28
local BODY_BG_ALPHA = 0.9
local BODY_BG_INSET_LEFT = GF.FRAME_BG_INSET_LEFT or 7
local BODY_BG_INSET_TOP = GF.FRAME_BG_INSET_TOP or -18
local BODY_BG_INSET_RIGHT = GF.FRAME_BG_INSET_RIGHT or -2
local BODY_BG_INSET_BOTTOM = GF.FRAME_BG_INSET_BOTTOM or 3
local CONTENT_W = DIALOG_W - BODY_LEFT - BODY_RIGHT
local CONTENT_H = DIALOG_H + BODY_TOP - BODY_BOTTOM
local GAME_VERSION_TEXT = "12.0.7"
local LOGO_TEXTURE = "Interface\\AddOns\\GroupFinder\\Art\\Logo\\GroupFinder.png"
local GOLD_LINE_TEXTURE = "Interface\\AddOns\\GroupFinder\\Art\\UI\\GoldLine.png"
local WHITE = "Interface\\Buttons\\WHITE8X8"

local HERO_H = 64
local HERO_LOGO_SIZE = 64
local HERO_TEXT_GAP = 22
local HERO_TEXT_MIN_W = 180
local HERO_TEXT_MAX_W = 330
local HERO_BAND_TOP = BODY_BG_INSET_TOP - 8
local HERO_BAND_BOTTOM = -166
local SECTION_LEFT = 12
local SECTION_RIGHT = 12
local SECTION_W = CONTENT_W - SECTION_LEFT - SECTION_RIGHT
local BODY_TOP_GAP = 16
local TITLE_TEXT_GAP = 6
local INTRO_TEXT_MIN_H = 36
local INTRO_TEXT_MAX_H = 60
local INTRO_TEXT_SPACING = 3
local INTRO_COMMAND_GAP = 12
local COMMAND_INFO_GAP = 16
local INFO_ROW_GAP = 8
local INFO_ROW_H = 22
local GOLD_LINE_SOURCE_H = 15
local GOLD_LINE_H = 2
local GOLD_LINE_TEX_TOP = 7 / GOLD_LINE_SOURCE_H
local GOLD_LINE_TEX_BOTTOM = 8 / GOLD_LINE_SOURCE_H

local MAIN_GOLD = { 1, 0.82, 0, 1 }
local BODY_TEXT = { 238 / 255, 228 / 255, 205 / 255, 1 }
local MUTED_TEXT = { 184 / 255, 170 / 255, 135 / 255, 1 }
local LINK_BLUE = { 130 / 255, 204 / 255, 1, 1 }
local COMMAND_BLUE = { 151 / 255, 224 / 255, 1, 1 }
local FOOTER_GRAY = { 0.5, 0.5, 0.5, 1 }

local FONT_BRAND_TITLE = 30
local FONT_COMMAND_TEXT = 18
local FONT_SECTION_TITLE = 18
local FONT_INFO_TEXT = 14
local FONT_FOOTER_TEXT = 12
local FONT_DESCRIPTION_TEXT = 13
local INFO_LABEL_W = 76
local INFO_COL_W = math.floor((SECTION_W - 22) / 2)

local function getAddonVersion()
	local version
	if C_AddOns and C_AddOns.GetAddOnMetadata then
		local ok, value = pcall(C_AddOns.GetAddOnMetadata, "GroupFinder", "Version")
		if ok then
			version = value
		end
	elseif GetAddOnMetadata then
		local ok, value = pcall(GetAddOnMetadata, "GroupFinder", "Version")
		if ok then
			version = value
		end
	end
	if type(version) == "string" and version ~= "" then
		return version
	end
	return "1.0.1"
end

local function setFont(fs, template, size, flags)
	if not fs then
		return
	end
	fs._gfFontSizeOverride = size
	fs._gfFontFlagsOverride = flags
	if GF.Font and GF.Font.ApplyToFontString then
		GF.Font.ApplyToFontString(fs, template or "GameFontHighlight")
	end
end

local function colorText(fs, color)
	if fs and color then
		fs:SetTextColor(color[1], color[2], color[3], color[4] or 1)
	end
end

local function paint(texture, r, g, b, a)
	if not texture then
		return
	end
	if texture.SetColorTexture then
		texture:SetColorTexture(r or 0, g or 0, b or 0, a or 1)
	else
		texture:SetTexture(WHITE)
		texture:SetVertexColor(r or 0, g or 0, b or 0, a or 1)
	end
end

local function applyDialogBackground(f)
	if not f then
		return
	end
	if f.Bg then
		f.Bg:Hide()
	end
	local fill = f.gfBodyBg and f.gfBodyBg.fill
	if fill then
		fill:ClearAllPoints()
		fill:SetPoint("TOPLEFT", f, "TOPLEFT", BODY_BG_INSET_LEFT, BODY_BG_INSET_TOP)
		fill:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", BODY_BG_INSET_RIGHT, BODY_BG_INSET_BOTTOM)
		fill:SetAtlas(nil)
		fill:SetTexture(nil)
		paint(fill, 5 / 255, 4 / 255, 2 / 255, BODY_BG_ALPHA)
		fill:Show()
	end
end

local function createText(parent, template, size, color, flags)
	local fs = GF.UI.CreateFontString(parent, "ARTWORK", template or "GameFontHighlight")
	setFont(fs, template or "GameFontHighlight", size or 12, flags or "")
	colorText(fs, color or BODY_TEXT)
	return fs
end

local function createGoldLine(parent, alpha)
	local line = parent:CreateTexture(nil, "ARTWORK")
	line:SetTexture(GOLD_LINE_TEXTURE)
	line:SetHeight(GOLD_LINE_H)
	line:SetTexCoord(0, 1, GOLD_LINE_TEX_TOP, GOLD_LINE_TEX_BOTTOM)
	line:SetAlpha(alpha or 0.42)
	return line
end

local function getTextWidth(fs, fallback)
	local width = fs and fs.GetStringWidth and fs:GetStringWidth() or 0
	if type(width) ~= "number" or width <= 0 then
		return fallback or 0
	end
	return width
end

local function getTextHeight(fs, fallback)
	local height = fs and fs.GetStringHeight and fs:GetStringHeight() or 0
	if type(height) ~= "number" or height <= 0 then
		return fallback or 0
	end
	return height
end

local function refreshIdentityLayout(f)
	if not f then
		return
	end
	local textWidth = math.ceil(math.max(
		HERO_TEXT_MIN_W,
		getTextWidth(f.title, HERO_TEXT_MIN_W),
		getTextWidth(f.meta, HERO_TEXT_MIN_W)
	))
	textWidth = math.min(HERO_TEXT_MAX_W, textWidth)
	f.identity:SetSize(HERO_LOGO_SIZE + HERO_TEXT_GAP + textWidth, HERO_H)
	f.identityText:SetSize(textWidth, HERO_H)
	f.title:SetWidth(textWidth)
	f.meta:SetWidth(textWidth)
end

local function refreshBodyLayout(f)
	if not f then
		return
	end
	local introHeight = math.ceil(getTextHeight(f.introText, INTRO_TEXT_MIN_H))
	introHeight = math.max(INTRO_TEXT_MIN_H, math.min(INTRO_TEXT_MAX_H, introHeight))
	f.introText:SetHeight(introHeight)

	f.commandTitle:ClearAllPoints()
	f.commandTitle:SetPoint("TOPLEFT", f.introText, "BOTTOMLEFT", 0, -INTRO_COMMAND_GAP)
	f.command:ClearAllPoints()
	f.command:SetPoint("TOPLEFT", f.commandTitle, "BOTTOMLEFT", 0, -TITLE_TEXT_GAP)
	f.infoRow1:ClearAllPoints()
	f.infoRow1:SetPoint("TOPLEFT", f.command, "BOTTOMLEFT", 0, -COMMAND_INFO_GAP)
	f.infoRow2:ClearAllPoints()
	f.infoRow2:SetPoint("TOPLEFT", f.infoRow1, "BOTTOMLEFT", 0, -INFO_ROW_GAP)
end

local function refreshContent(f)
	local L = GF.L or {}
	local addonVersion = getAddonVersion()
	local addonName = L.ADDON_NAME or "GroupFinder"
	local versionText = string.format(L.USAGE_DETAIL_VERSION_FMT or "Current version: %s", addonVersion)

	f.title:SetText(addonName)
	f.meta:SetText(versionText)
	f.introTitle:SetText(L.USAGE_DETAIL_INTRO_TITLE or "Addon Overview")
	f.introText:SetText(L.USAGE_DETAIL_INTRO_TEXT or "")
	f.commandTitle:SetText(L.USAGE_DETAIL_SHORTCUT_TITLE or "Slash Commands")
	f.command:SetText(L.USAGE_DETAIL_SHORTCUT_TEXT or "/gf")
	f.versionLabel:SetText((L.USAGE_DETAIL_VERSION_TITLE or "Version") .. "：")
	f.versionText:SetText(addonVersion)
	f.authorLabel:SetText((L.USAGE_DETAIL_AUTHOR_TITLE or "Author") .. "：")
	f.authorText:SetText(L.USAGE_DETAIL_AUTHOR_TEXT or "")
	f.homepageLabel:SetText((L.USAGE_DETAIL_HOMEPAGE_TITLE or "Homepage") .. "：")
	f.homepageText:SetText(L.USAGE_DETAIL_HOMEPAGE_TEXT or "")
	f.feedbackLabel:SetText((L.USAGE_DETAIL_FEEDBACK_TITLE or "Feedback") .. "：")
	f.feedbackText:SetText(L.USAGE_DETAIL_FEEDBACK_TEXT or "")
	f.footer:SetText(string.format("%s - %s - %s", addonName, GAME_VERSION_TEXT, addonVersion))
	refreshIdentityLayout(f)
	refreshBodyLayout(f)
end

local function playDialogSound(kind)
	if not PlaySound or not SOUNDKIT then
		return
	end
	local sound
	if kind == "open" then
		sound = SOUNDKIT.IG_QUEST_LOG_OPEN or SOUNDKIT.IG_CHARACTER_INFO_OPEN
	else
		sound = SOUNDKIT.IG_QUEST_LOG_CLOSE or SOUNDKIT.IG_CHARACTER_INFO_CLOSE
	end
	if sound then
		pcall(PlaySound, sound)
	end
end

local function hideMainFrameForDialog()
	local main = GF.MainFrame
	local frame = main and main.frame
	UGD._restoreMainFrame = frame and frame:IsShown() and true or false
	if not UGD._restoreMainFrame then
		return
	end
	main._suppressNextHideSound = true
	if main.HideFrame then
		main:HideFrame()
	else
		frame:Hide()
	end
end

local function restoreMainFrameAfterDialog()
	if not UGD._restoreMainFrame then
		return
	end
	UGD._restoreMainFrame = nil
	local main = GF.MainFrame
	if not main then
		return
	end
	main._suppressNextShowSound = true
	if main.ShowFrame then
		main:ShowFrame()
	elseif main.frame then
		main.frame:Show()
	end
end

local function ensureFrame()
	if UGD.frame then
		return UGD.frame
	end
	local L = GF.L or {}
	local f = GF.UI.CreateSatelliteSettingsFrame({
		name = "GroupFinderAddonUsageGuideDialog",
		width = DIALOG_W,
		height = DIALOG_H,
		title = L.USAGE_GUIDE_TITLE or "Addon details",
		levelOffset = 5,
		onClose = function()
			UGD:Hide()
		end,
	})
	applyDialogBackground(f)
	f:HookScript("OnHide", function()
		if UGD._shown then
			UGD._shown = nil
			playDialogSound("close")
			if UGD._skipMainFrameRestore then
				UGD._skipMainFrameRestore = nil
				UGD._restoreMainFrame = nil
			else
				restoreMainFrameAfterDialog()
			end
		end
	end)

	f.content = CreateFrame("Frame", nil, f)
	f.content:SetPoint("TOPLEFT", f, "TOPLEFT", BODY_LEFT, BODY_TOP)
	f.content:SetSize(CONTENT_W, CONTENT_H)
	f.content:SetFrameLevel(f:GetFrameLevel() + 5)

	f.identityBand = CreateFrame("Frame", nil, f)
	f.identityBand:SetPoint("TOPLEFT", f, "TOPLEFT", BODY_LEFT, HERO_BAND_TOP)
	f.identityBand:SetPoint("BOTTOMRIGHT", f, "TOPRIGHT", -BODY_RIGHT, HERO_BAND_BOTTOM)

	f.identity = CreateFrame("Frame", nil, f.identityBand)
	f.identity:SetPoint("CENTER", f.identityBand, "CENTER", 0, 0)
	f.identity:SetSize(HERO_LOGO_SIZE + HERO_TEXT_GAP + HERO_TEXT_MAX_W, HERO_H)

	f.icon = f.identity:CreateTexture(nil, "ARTWORK")
	f.icon:SetPoint("LEFT", f.identity, "LEFT", 0, 0)
	f.icon:SetSize(HERO_LOGO_SIZE, HERO_LOGO_SIZE)
	f.icon:SetTexture(GF.ADDON_MENU_LOGO_TEXTURE or LOGO_TEXTURE)

	f.identityText = CreateFrame("Frame", nil, f.identity)
	f.identityText:SetPoint("LEFT", f.icon, "RIGHT", HERO_TEXT_GAP, 0)
	f.identityText:SetSize(HERO_TEXT_MAX_W, HERO_H)

	f.title = createText(f.identityText, "GameFontNormalLarge", FONT_BRAND_TITLE, MAIN_GOLD, "OUTLINE")
	f.title:SetPoint("TOPLEFT", f.identityText, "TOPLEFT", 0, -2)
	f.title:SetWidth(HERO_TEXT_MAX_W)
	f.title:SetJustifyH("LEFT")
	f.meta = createText(f.identityText, "GameFontHighlight", FONT_INFO_TEXT, BODY_TEXT, "")
	f.meta:SetPoint("TOPLEFT", f.title, "BOTTOMLEFT", 0, -8)
	f.meta:SetWidth(HERO_TEXT_MAX_W)
	f.meta:SetJustifyH("LEFT")

	f.mainDivider = createGoldLine(f.content, 0.56)
	f.mainDivider:SetPoint("TOPLEFT", f.identityBand, "BOTTOMLEFT", 0, 0)
	f.mainDivider:SetPoint("TOPRIGHT", f.identityBand, "BOTTOMRIGHT", 0, 0)

	f.bodyContent = CreateFrame("Frame", nil, f.content)
	f.bodyContent:SetPoint("TOP", f.mainDivider, "BOTTOM", 0, -BODY_TOP_GAP)
	f.bodyContent:SetSize(SECTION_W, 166)

	f.introTitle = createText(f.content, "GameFontNormalLarge", FONT_SECTION_TITLE, MAIN_GOLD, "OUTLINE")
	f.introTitle:SetPoint("TOPLEFT", f.bodyContent, "TOPLEFT", 0, 0)
	f.introTitle:SetSize(SECTION_W, 22)
	f.introTitle:SetJustifyH("LEFT")
	f.introText = createText(f.content, "GameFontHighlight", FONT_INFO_TEXT, BODY_TEXT, "")
	f.introText:SetPoint("TOPLEFT", f.introTitle, "BOTTOMLEFT", 0, -TITLE_TEXT_GAP)
	f.introText:SetSize(SECTION_W, INTRO_TEXT_MIN_H)
	f.introText:SetJustifyH("LEFT")
	f.introText:SetWordWrap(true)
	if f.introText.SetSpacing then
		f.introText:SetSpacing(INTRO_TEXT_SPACING)
	end

	f.commandTitle = createText(f.content, "GameFontNormalLarge", FONT_SECTION_TITLE, MAIN_GOLD, "OUTLINE")
	f.commandTitle:SetPoint("TOPLEFT", f.introText, "BOTTOMLEFT", 0, -INTRO_COMMAND_GAP)
	f.commandTitle:SetSize(SECTION_W, 22)
	f.commandTitle:SetJustifyH("LEFT")
	f.command = createText(f.content, "GameFontHighlightLarge", FONT_COMMAND_TEXT, COMMAND_BLUE, "")
	f.command:SetPoint("TOPLEFT", f.commandTitle, "BOTTOMLEFT", 0, -TITLE_TEXT_GAP)
	f.command:SetSize(SECTION_W, 22)
	f.command:SetJustifyH("LEFT")

	f.infoRow1 = CreateFrame("Frame", nil, f.content)
	f.infoRow1:SetPoint("TOPLEFT", f.command, "BOTTOMLEFT", 0, -COMMAND_INFO_GAP)
	f.infoRow1:SetSize(SECTION_W, INFO_ROW_H)
	f.infoRow2 = CreateFrame("Frame", nil, f.content)
	f.infoRow2:SetPoint("TOPLEFT", f.infoRow1, "BOTTOMLEFT", 0, -INFO_ROW_GAP)
	f.infoRow2:SetSize(SECTION_W, INFO_ROW_H)

	f.versionLabel = createText(f.infoRow1, "GameFontNormal", FONT_INFO_TEXT, MAIN_GOLD, "")
	f.versionLabel:SetPoint("LEFT", f.infoRow1, "LEFT", 0, 0)
	f.versionLabel:SetSize(INFO_LABEL_W, 18)
	f.versionLabel:SetJustifyH("LEFT")
	f.versionText = createText(f.content, "GameFontHighlight", FONT_INFO_TEXT, BODY_TEXT, "")
	f.versionText:SetPoint("LEFT", f.versionLabel, "RIGHT", 0, 0)
	f.versionText:SetSize(INFO_COL_W - INFO_LABEL_W, 18)
	f.versionText:SetJustifyH("LEFT")

	f.authorLabel = createText(f.infoRow1, "GameFontNormal", FONT_INFO_TEXT, MAIN_GOLD, "")
	f.authorLabel:SetPoint("LEFT", f.infoRow1, "LEFT", INFO_COL_W + 22, 0)
	f.authorLabel:SetSize(INFO_LABEL_W, 18)
	f.authorLabel:SetJustifyH("LEFT")
	f.authorText = createText(f.content, "GameFontHighlight", FONT_INFO_TEXT, BODY_TEXT, "")
	f.authorText:SetPoint("LEFT", f.authorLabel, "RIGHT", 0, 0)
	f.authorText:SetSize(INFO_COL_W - INFO_LABEL_W, 18)
	f.authorText:SetJustifyH("LEFT")

	f.homepageLabel = createText(f.infoRow2, "GameFontNormal", FONT_INFO_TEXT, MAIN_GOLD, "")
	f.homepageLabel:SetPoint("LEFT", f.infoRow2, "LEFT", 0, 0)
	f.homepageLabel:SetSize(INFO_LABEL_W, 18)
	f.homepageLabel:SetJustifyH("LEFT")
	f.homepageText = createText(f.content, "GameFontHighlight", FONT_INFO_TEXT, LINK_BLUE, "")
	f.homepageText:SetPoint("LEFT", f.homepageLabel, "RIGHT", 0, 0)
	f.homepageText:SetSize(INFO_COL_W - INFO_LABEL_W, 18)
	f.homepageText:SetJustifyH("LEFT")

	f.feedbackLabel = createText(f.infoRow2, "GameFontNormal", FONT_INFO_TEXT, MAIN_GOLD, "")
	f.feedbackLabel:SetPoint("LEFT", f.infoRow2, "LEFT", INFO_COL_W + 22, 0)
	f.feedbackLabel:SetSize(INFO_LABEL_W, 18)
	f.feedbackLabel:SetJustifyH("LEFT")
	f.feedbackText = createText(f.content, "GameFontHighlight", FONT_INFO_TEXT, LINK_BLUE, "")
	f.feedbackText:SetPoint("LEFT", f.feedbackLabel, "RIGHT", 0, 0)
	f.feedbackText:SetSize(INFO_COL_W - INFO_LABEL_W, 18)
	f.feedbackText:SetJustifyH("LEFT")

	f.footer = createText(f, "GameFontDisableSmall", FONT_FOOTER_TEXT, FOOTER_GRAY, "")
	f.footer:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -18, 14)
	f.footer:SetSize(CONTENT_W, 16)
	f.footer:SetJustifyH("RIGHT")

	refreshContent(f)

	UGD.frame = f
	return f
end

function UGD:Hide()
	if self.frame then
		self.frame:Hide()
	end
end

function UGD:RefreshLocale()
	if not self.frame then
		return
	end
	local L = GF.L or {}
	GF.UI.ApplySettingsFrameChrome(self.frame, L.USAGE_GUIDE_TITLE or "Addon details")
	refreshContent(self.frame)
end

function UGD:CloseForMainFrameOpen()
	if self.frame and self.frame:IsShown() then
		self._skipMainFrameRestore = true
		self.frame:Hide()
	end
end

function UGD:Show()
	local L = GF.L or {}
	local f = ensureFrame()
	if f:IsShown() then
		refreshContent(f)
		return
	end
	GF.UI.ApplySettingsFrameChrome(f, L.USAGE_GUIDE_TITLE or "Addon details")
	applyDialogBackground(f)
	refreshContent(f)
	GF.UI.CenterOnMainFrame(f, 0)
	hideMainFrameForDialog()
	f:Show()
	self._shown = true
	playDialogSound("open")
end
