local _, GF = ...

GF.TabBar = {}
local TB = GF.TabBar

local function workspaceRouter()
	local router = GF.WorkspaceRouter
	if not router then
		error("GroupFinder WorkspaceRouter must load before TabBar", 2)
	end
	return router
end

local function getTabNames()
	local L = GF.L or {}
	return {
		[GF.TAB_BROWSE] = L.TAB_BROWSE,
		[GF.TAB_CREATE] = L.TAB_CREATE,
		[GF.TAB_BLOCKLIST] = L.TAB_BLOCKLIST,
		[GF.TAB_SETTINGS] = L.TAB_SETTINGS,
		[GF.TAB_DEBUG] = L.TAB_DEBUG,
		[GF.TAB_MPLUS_CHARACTER] = L.TAB_MPLUS_CHARACTER,
		[GF.TAB_MPLUS_GROUP] = L.TAB_MPLUS_GROUP,
		[GF.TAB_MPLUS_CARPOOL] = L.TAB_MPLUS_CARPOOL,
		[GF.TAB_MPLUS_DUNGEON] = L.TAB_MPLUS_DUNGEON,
	}
end

function TB:Init(mainFrame, opts)
	opts = opts or {}
	self.mainFrame = mainFrame
	self.tabs = {}
	self.tabsBar = CreateFrame("Frame", "GroupFinderAddonTabsBar", mainFrame)
	self.tabsBar.useSystemTabs = true
	self.tabsBar:SetFrameLevel((mainFrame.panelBackplate and mainFrame.panelBackplate:GetFrameLevel() or mainFrame:GetFrameLevel()) - 2)
	self.tabsBar.selectedHighlightFrameLevel = (mainFrame.panelBackplate and mainFrame.panelBackplate:GetFrameLevel() or mainFrame:GetFrameLevel()) + 20
	self.tabsBar:SetPoint(
		"TOPLEFT",
		mainFrame,
		"TOPLEFT",
		(GF.MAIN_PANEL_INSET_LEFT or 26) + 32,
		-((GF.MAIN_PANEL_INSET_TOP or 64) - 35 + 12)
	)
	self.tabsBar:SetSize(760, GF.MAIN_PANEL_TAB_HEIGHT or 32)
	local names = getTabNames()
	local router = workspaceRouter()
	for _, tabID in ipairs(router:GetAllTabIDs()) do
		local tab = GF.UI.CreateNativeTabButton(self.tabsBar, names[tabID] or tostring(tabID), tabID)
		tab:SetID(tabID)
		tab:SetScript("OnClick", function(btn)
			TB:Select(btn:GetID())
		end)
		tab:Hide()
		self.tabs[tabID] = tab
	end
	router:Init({ workspaceID = opts.workspaceID })
	self:SetWorkspace(router:GetWorkspaceID(), {
		silent = true,
		keepCurrent = true,
	})
end

function TB:GetWorkspace()
	return workspaceRouter():GetWorkspaceID()
end

function TB:GetVisibleTabOrder()
	return workspaceRouter():GetVisibleTabOrder(self:GetWorkspace())
end

function TB:IsTabAvailable(tabID)
	return workspaceRouter():IsTabAvailable(tabID, self:GetWorkspace())
end

function TB:SetWorkspace(workspaceID, opts)
	opts = opts or {}
	local router = workspaceRouter()
	local transition = opts._routerTransition
	local target
	if type(transition) == "table"
		and transition.workspaceID == router:NormalizeWorkspaceID(workspaceID)
	then
		target = transition.tabID
	else
		target, transition = router:SetWorkspace(workspaceID, {
			targetTabID = opts.targetTabID,
			keepCurrent = opts.keepCurrent == true,
		})
	end
	for _, tab in pairs(self.tabs or {}) do
		tab:Hide()
	end
	for _, tabID in ipairs(self:GetVisibleTabOrder()) do
		local tab = self.tabs[tabID]
		if tab and self:IsTabAvailable(tabID) then
			tab:Show()
		end
	end
	self:RelayoutTabs()
	self:RefreshTabStates()
	if not opts.silent and self.mainFrame and self.mainFrame.OnTabChanged then
		self.mainFrame:OnTabChanged(target)
	end
	return target
end

function TB:RefreshLocale()
	if not self.tabs then
		return
	end
	local names = getTabNames()
	for tabID, tab in pairs(self.tabs) do
		if tab and GF.UI and GF.UI.SetNativeTabText then
			GF.UI.SetNativeTabText(tab, names[tabID] or tostring(tabID))
		end
	end
	self:RelayoutTabs()
end

function TB:RefreshTabStates()
	local current = self:GetCurrent()
	for tabID, tab in pairs(self.tabs or {}) do
		if tab and GF.UI.SetNativeTabSelected then
			GF.UI.SetNativeTabSelected(tab, tabID == current)
		end
	end
end

function TB:Select(tabID, opts)
	opts = opts or {}
	local router = workspaceRouter()
	local transition = opts._routerTransition
	if type(transition) ~= "table" or transition.tabID ~= tabID then
		transition = router:SelectTab(tabID)
	end
	if transition == nil or transition.tabChanged ~= true then
		return
	end
	self:RefreshTabStates()
	if transition.previousTabID and transition.previousTabID ~= tabID
		and self.mainFrame and self.mainFrame.frame
		and ((self.mainFrame.IsUserVisible
			and self.mainFrame:IsUserVisible())
			or (not self.mainFrame.IsUserVisible
				and self.mainFrame.frame.IsShown
				and self.mainFrame.frame:IsShown()))
		and GF.UI and GF.UI.PlayUISound then
		GF.UI.PlayUISound("tab")
	end
	if self.mainFrame and self.mainFrame.OnTabChanged then
		self.mainFrame:OnTabChanged(tabID, opts)
	end
end

function TB:SelectTab(tabID, opts)
	local tab = self.tabs and self.tabs[tabID]
	if not tab or not tab:IsShown() or not self:IsTabAvailable(tabID) then
		return
	end
	self:Select(tabID, opts)
end

function TB:GetCurrent()
	return workspaceRouter():GetCurrentTabID()
end

function TB:RelayoutTabs()
	if not self.tabs then
		return
	end
	local previous
	for _, tabID in ipairs(self:GetVisibleTabOrder()) do
		local tab = self.tabs[tabID]
		if tab and tab:IsShown() then
			tab:ClearAllPoints()
			if previous then
				tab:SetPoint("TOPLEFT", previous, "TOPRIGHT", GF.MAIN_PANEL_TAB_GAP or 1, 0)
			else
				tab:SetPoint("TOPLEFT", self.tabsBar, "TOPLEFT", 0, 0)
			end
			previous = tab
		end
	end
	self:RefreshTabStates()
end

function TB:RefreshFonts()
	self:RefreshTabStates()
end

function TB:SetBlocklistTabVisible(visible)
	local transition = workspaceRouter():SetBlocklistTabAvailable(visible)
	if transition and transition.tabChanged then
		self:Select(transition.tabID, { _routerTransition = transition })
	end
	local tab = self.tabs and self.tabs[GF.TAB_BLOCKLIST]
	if tab then
		tab:SetShown(self:IsTabAvailable(GF.TAB_BLOCKLIST))
	end
	self:RelayoutTabs()
end

function TB:SetDebugTabVisible(visible)
	local enabled = visible == true
	local transition = workspaceRouter():SetDebugTabAvailable(enabled)
	if transition and transition.tabChanged then
		self:Select(transition.tabID, { _routerTransition = transition })
	end
	local tab = self.tabs and self.tabs[GF.TAB_DEBUG]
	if tab then
		tab:SetShown(enabled and self:IsTabAvailable(GF.TAB_DEBUG))
	end
	self:RelayoutTabs()
end
