local addonTable = select(2, ...)
---@type MK
local MK = addonTable.MK
local core = addonTable
local TRANSLATE = core.TRANSLATE or function(msg) return msg end

core.MeetingStoneBridge = core.MeetingStoneBridge or {}
local MeetingStoneBridge = core.MeetingStoneBridge
local MeetingStoneConstants = core.MeetingStoneConstants or {}
local MEETINGSTONE_FORM_TITLE_NATIVE_OFFSET_LEFT = MeetingStoneConstants.MEETINGSTONE_FORM_TITLE_NATIVE_OFFSET_LEFT
local MEETINGSTONE_FORM_TITLE_NATIVE_OFFSET_RIGHT = MeetingStoneConstants.MEETINGSTONE_FORM_TITLE_NATIVE_OFFSET_RIGHT
local MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_LEFT = MeetingStoneConstants.MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_LEFT
local MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_TOP = MeetingStoneConstants.MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_TOP
local MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_RIGHT = MeetingStoneConstants.MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_RIGHT
local MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_BOTTOM = MeetingStoneConstants.MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_BOTTOM
local MEETINGSTONE_FORM_PLACEHOLDER_TEXT_SIZE = MeetingStoneConstants.MEETINGSTONE_FORM_PLACEHOLDER_TEXT_SIZE or 14
local MEETINGSTONE_FORM_SUMMARY_NATIVE_OFFSET_LEFT = MeetingStoneConstants.MEETINGSTONE_FORM_SUMMARY_NATIVE_OFFSET_LEFT
local MEETINGSTONE_FORM_SUMMARY_NATIVE_OFFSET_RIGHT = MeetingStoneConstants.MEETINGSTONE_FORM_SUMMARY_NATIVE_OFFSET_RIGHT
local MEETINGSTONE_ATTACHED_SUMMARY_OFFSET_ADJUST_X = -2
local MEETINGSTONE_ATTACHED_SUMMARY_OFFSET_LEFT =
    (MEETINGSTONE_FORM_TITLE_NATIVE_OFFSET_LEFT or MEETINGSTONE_FORM_SUMMARY_NATIVE_OFFSET_LEFT or 0) + MEETINGSTONE_ATTACHED_SUMMARY_OFFSET_ADJUST_X
local MEETINGSTONE_ATTACHED_SUMMARY_OFFSET_RIGHT =
    (MEETINGSTONE_FORM_TITLE_NATIVE_OFFSET_RIGHT or MEETINGSTONE_FORM_SUMMARY_NATIVE_OFFSET_RIGHT or 0) + MEETINGSTONE_ATTACHED_SUMMARY_OFFSET_ADJUST_X
local MEETINGSTONE_MISSING_ADDON_MESSAGE_KEY = MeetingStoneConstants.MEETINGSTONE_MISSING_ADDON_MESSAGE_KEY
local MEETINGSTONE_PROVIDER_ADDONS = { "MeetingStone", "MeetingStoneEX" }
local MEETINGSTONE_PROVIDER_DEPENDENCIES = { "!!!Libs", "BigFoot" }
local MEETINGSTONE_ENV_NAMES = { "MeetingStone", "MeetingStoneEX" }
local MEETINGSTONE_NATIVE_CONTROL_RECOVERY_INTERVAL = 0.25
local MEETINGSTONE_LEADER_CHANGE_POPUP_KEY = "PREMADE_GROUP_LEADER_CHANGE_DELIST_WARNING"
local MEETINGSTONE_NATIVE_BORROW_OWNER = "mykeystone"
local MEETINGSTONE_NATIVE_BORROW_OWNER_LEGACY = "MyKeyStone"
local MEETINGSTONE_NATIVE_BORROW_CHANNEL = "entryCreation"
local meetingStoneNativeBorrowSerial = 0

local function IsMeetingStoneCombatLocked()
    return _G.InCombatLockdown and _G.InCombatLockdown()
end

local function CanManageMeetingStoneListing()
    local listing = core.MeetingStoneListing
    if listing and listing.CanManageListing then
        return listing.CanManageListing()
    end
    return true
end

local function UseMeetingStoneFallbackInputControls(widgets)
    if not widgets then
        return
    end

    if widgets.meetingStoneFallbackTitleBox then
        widgets.meetingStoneFallbackTitleBox:Show()
        widgets.meetingStoneTitleBox = widgets.meetingStoneFallbackTitleBox
    end
    if widgets.meetingStoneFallbackSummaryFrame then
        widgets.meetingStoneFallbackSummaryFrame:Show()
        widgets.meetingStoneSummaryFrame = widgets.meetingStoneFallbackSummaryFrame
        widgets.meetingStoneSummaryBox = widgets.meetingStoneFallbackSummaryBox
    end
    widgets.meetingStoneUsesNativeTextControls = false
end

local function SetMeetingStoneNativeInputOccupied(widgets, occupied, restoreForm)
    if core.MeetingStoneTab and core.MeetingStoneTab.SetNativeInputOccupied then
        core.MeetingStoneTab.SetNativeInputOccupied(widgets, occupied, restoreForm)
        return
    end
    if widgets then
        widgets.meetingStoneNativeInputOccupied = occupied == true or nil
    end
end

local function AddUniqueString(list, seen, value)
    value = type(value) == "string" and value or nil
    if not value or value == "" or seen[value] then
        return
    end

    seen[value] = true
    list[#list + 1] = value
end

local function IsMeetingStoneProviderTitle(title, notes)
    title = tostring(title or "")
    notes = tostring(notes or "")
    return title:find("MeetingStone", 1, true)
        or title:find("Meeting Stone", 1, true)
        or title:find("集合石", 1, true)
        or notes:find("MeetingStone", 1, true)
end

local function GetMeetingStoneProviderAddonNames()
    local names = {}
    local seen = {}

    for _, addonName in ipairs(MEETINGSTONE_PROVIDER_ADDONS) do
        AddUniqueString(names, seen, addonName)
    end

    local getNumAddOns = C_AddOns and C_AddOns.GetNumAddOns or GetNumAddOns
    local getAddOnInfo = C_AddOns and C_AddOns.GetAddOnInfo or GetAddOnInfo
    if getNumAddOns and getAddOnInfo then
        local okCount, count = pcall(getNumAddOns)
        count = okCount and tonumber(count) or 0
        for index = 1, count do
            local okInfo, name, title, notes = pcall(getAddOnInfo, index)
            if okInfo and IsMeetingStoneProviderTitle(title, notes) then
                AddUniqueString(names, seen, name)
            end
        end
    end

    return names
end

local function IsMeetingStoneProviderAddon(addonName)
    if type(addonName) ~= "string" then
        return false
    end

    for _, candidate in ipairs(GetMeetingStoneProviderAddonNames()) do
        if addonName == candidate then
            return true
        end
    end
    return false
end

local function IsLoadOnDemandReason(reason)
    return reason == "DEMAND_LOADED" or reason == "LOAD_ON_DEMAND"
end

local function IsAddonLoaded(addonName)
    if C_AddOns and C_AddOns.IsAddOnLoaded then
        return C_AddOns.IsAddOnLoaded(addonName)
    end
    if IsAddOnLoaded then
        return IsAddOnLoaded(addonName)
    end
    return false
end

local function IsAddonInstalled(addonName)
    if C_AddOns and C_AddOns.GetAddOnInfo then
        local ok, name = pcall(C_AddOns.GetAddOnInfo, addonName)
        return ok and name ~= nil
    end
    if GetAddOnInfo then
        local ok, name = pcall(GetAddOnInfo, addonName)
        return ok and name ~= nil
    end
    return IsAddonLoaded(addonName)
end

local function IsAddonEnabled(addonName)
    if not IsAddonInstalled(addonName) then
        return false
    end

    local playerName = UnitName and UnitName("player") or nil
    if C_AddOns and C_AddOns.GetAddOnEnableState then
        local ok, enableState = pcall(C_AddOns.GetAddOnEnableState, addonName, playerName)
        if ok and tonumber(enableState) and tonumber(enableState) <= 0 then
            return false
        end
    elseif GetAddOnEnableState then
        local ok, enableState = pcall(GetAddOnEnableState, playerName, addonName)
        if ok and tonumber(enableState) and tonumber(enableState) <= 0 then
            return false
        end
    end

    local loadableChecker = C_AddOns and C_AddOns.IsAddOnLoadable or IsAddOnLoadable
    if loadableChecker then
        local ok, loadable, reason = pcall(loadableChecker, addonName)
        if ok and loadable == false and not IsLoadOnDemandReason(reason) and not IsAddonLoaded(addonName) then
            return false
        end
    end

    if C_AddOns and C_AddOns.GetAddOnInfo then
        local ok, _, _, _, loadable, reason = pcall(C_AddOns.GetAddOnInfo, addonName)
        if ok then
            if reason == "DISABLED" or reason == "DEP_DISABLED" then
                return false
            end
            if loadable == false and not IsLoadOnDemandReason(reason) and not IsAddonLoaded(addonName) then
                return false
            end
        end
    elseif GetAddOnInfo then
        local ok, _, _, _, loadable, reason = pcall(GetAddOnInfo, addonName)
        if ok then
            if reason == "DISABLED" or reason == "DEP_DISABLED" then
                return false
            end
            if loadable == false and not IsLoadOnDemandReason(reason) and not IsAddonLoaded(addonName) then
                return false
            end
        end
    end

    return true
end

local function IsTruthyConfigValue(value)
    return value == true or value == 1 or value == "1"
end

local function GetBigFootMeetingStoneConfigEnabled()
    if type(_G.BigFoot_GetModVariable) == "function" then
        local ok, value = pcall(_G.BigFoot_GetModVariable, "RaidToolkit", "EnableMeetingStone")
        if ok and value ~= nil then
            return IsTruthyConfigValue(value)
        end
    end

    local bigFootConfig = type(_G.BigFoot_Config) == "table" and _G.BigFoot_Config.RaidToolkit
    if type(bigFootConfig) == "table" and bigFootConfig.EnableMeetingStone ~= nil then
        return IsTruthyConfigValue(bigFootConfig.EnableMeetingStone)
    end

    if type(_G.IsConfigurableAddOn) == "function" then
        local ok, configurable = pcall(_G.IsConfigurableAddOn, "MeetingStone")
        if ok and configurable == true then
            return true
        end
    end

    if type(_G.BigFoot_HasAddon) == "function" then
        local ok, hasAddon = pcall(_G.BigFoot_HasAddon, "MeetingStone")
        if ok and hasAddon == true then
            return true
        end
    end

    return nil
end

local function IsMeetingStoneProviderUserEnabled(addonName)
    if addonName == "MeetingStone" then
        local bigFootEnabled = GetBigFootMeetingStoneConfigEnabled()
        if bigFootEnabled ~= nil then
            return bigFootEnabled == true
        end
    end

    return IsAddonEnabled(addonName)
end

local function TryLoadAddonThroughBigFoot(addonName)
    if addonName ~= "MeetingStone" or type(_G.BigFoot_LoadAddOn) ~= "function" then
        return false
    end

    local ok, loaded = pcall(_G.BigFoot_LoadAddOn, addonName)
    return ok and (loaded == true or IsAddonLoaded(addonName))
end

local function TryRawLoadAddon(addonName)
    if IsAddonLoaded(addonName) then
        return true
    end
    if not IsAddonInstalled(addonName) then
        return false
    end

    local loader = C_AddOns and C_AddOns.LoadAddOn or LoadAddOn
    if not loader then
        return false
    end

    local ok, loadedOrReason = pcall(loader, addonName)
    return ok and (loadedOrReason == true or IsAddonLoaded(addonName))
end

local function TryLoadMeetingStoneProviderDependencies()
    for _, addonName in ipairs(MEETINGSTONE_PROVIDER_DEPENDENCIES) do
        TryRawLoadAddon(addonName)
    end
end

local function TryLoadAddon(addonName)
    if IsAddonLoaded(addonName) then
        return true
    end

    if not IsAddonEnabled(addonName) then
        return false, MEETINGSTONE_MISSING_ADDON_MESSAGE_KEY
    end

    local loader = C_AddOns and C_AddOns.LoadAddOn or LoadAddOn
    if not loader then
        return false, "LoadAddOn is unavailable."
    end

    local ok, loadedOrReason = pcall(loader, addonName)
    if ok and (loadedOrReason == true or IsAddonLoaded(addonName)) then
        return true
    end

    return false, tostring(loadedOrReason or "unknown")
end

local function IsMeetingStoneAddonInstalled()
    for _, addonName in ipairs(GetMeetingStoneProviderAddonNames()) do
        if IsAddonInstalled(addonName) then
            return true
        end
    end
    return false
end

local function IsMeetingStoneAddonEnabled()
    TryLoadMeetingStoneProviderDependencies()
    for _, addonName in ipairs(GetMeetingStoneProviderAddonNames()) do
        if IsAddonLoaded(addonName) or IsMeetingStoneProviderUserEnabled(addonName) then
            return true
        end
    end
    return false
end

local function TryLoadMeetingStoneAddon()
    TryLoadMeetingStoneProviderDependencies()

    local lastReason
    for _, addonName in ipairs(GetMeetingStoneProviderAddonNames()) do
        if IsAddonInstalled(addonName) then
            local loaded = false
            local reason
            if IsMeetingStoneProviderUserEnabled(addonName) then
                loaded = TryLoadAddonThroughBigFoot(addonName)
                if not loaded then
                    loaded, reason = TryLoadAddon(addonName)
                end
            else
                reason = MEETINGSTONE_MISSING_ADDON_MESSAGE_KEY
            end
            if loaded then
                return true, addonName
            end
            lastReason = reason
        end
    end

    return false, lastReason or MEETINGSTONE_MISSING_ADDON_MESSAGE_KEY
end

local function IsMeetingStoneAddonLoaded()
    for _, addonName in ipairs(GetMeetingStoneProviderAddonNames()) do
        local ok, loaded = pcall(IsAddonLoaded, addonName)
        if ok then
            if loaded == true then
                return true
            end
        end
    end
    return false
end

local function GetMeetingStoneEnv()
    local libStub = _G.LibStub
    if not libStub then
        return nil
    end

    local ok, envLib = pcall(libStub, "NetEaseEnv-1.0")
    if not ok or not envLib or type(envLib._NSList) ~= "table" then
        return nil
    end

    local names = {}
    local seen = {}
    for _, envName in ipairs(MEETINGSTONE_ENV_NAMES) do
        AddUniqueString(names, seen, envName)
    end
    for _, addonName in ipairs(GetMeetingStoneProviderAddonNames()) do
        AddUniqueString(names, seen, addonName)
    end

    for _, envName in ipairs(names) do
        local env = envLib._NSList[envName]
        if type(env) == "table" then
            return env
        end
    end
    return nil
end

local function GetMeetingStoneRuntime()
    local env = GetMeetingStoneEnv()
    if not env then
        return nil, nil
    end

    return env.CurrentActivity, env.Logic
end

local function PatchMeetingStoneRecentCacheRecent()
    local env = GetMeetingStoneEnv()
    local recent = env and env.Recent
    if type(recent) ~= "table" or type(recent.CacheRecent) ~= "function" then
        return false
    end
    if recent._mkSecretStringCacheRecentPatched then
        return true
    end

    local originalCacheRecent = recent.CacheRecent
    recent._mkOriginalCacheRecent = originalCacheRecent
    recent.CacheRecent = function(self, ...)
        local ok, result = pcall(originalCacheRecent, self, ...)
        if ok then
            return result
        end

        local message = tostring(result or "")
        if message:find("secret string", 1, true) then
            return
        end

        error(message, 0)
    end
    recent._mkSecretStringCacheRecentPatched = true
    return true
end

local function GetMeetingStoneNativeEntryCreationFrame(skipLoad)
    if not skipLoad and not (_G.LFGListFrame and _G.LFGListFrame.EntryCreation) then
        TryLoadAddon("Blizzard_GroupFinder")
        if UIParentLoadAddOn then
            pcall(UIParentLoadAddOn, "Blizzard_GroupFinder")
        end
    end

    return _G.LFGListFrame and _G.LFGListFrame.EntryCreation
end

local function CaptureMeetingStoneFramePlacement(frame)
    if not frame then
        return nil
    end

    local points = {}
    if frame.GetNumPoints and frame.GetPoint then
        for index = 1, frame:GetNumPoints() do
            local point, relativeTo, relativePoint, xOffset, yOffset = frame:GetPoint(index)
            points[#points + 1] = {
                point = point,
                relativeTo = relativeTo,
                relativePoint = relativePoint,
                xOffset = xOffset,
                yOffset = yOffset,
            }
        end
    end

    return {
        parent = frame.GetParent and frame:GetParent() or nil,
        points = points,
        width = frame.GetWidth and frame:GetWidth() or nil,
        height = frame.GetHeight and frame:GetHeight() or nil,
        frameLevel = frame.GetFrameLevel and frame:GetFrameLevel() or nil,
        enabled = frame.IsEnabled and frame:IsEnabled() or nil,
        shown = frame.IsShown and frame:IsShown() or false,
    }
end

local function RestoreMeetingStoneFramePlacement(frame, placement)
    if not frame or not placement then
        return
    end

    if frame.SetParent then
        frame:SetParent(placement.parent or UIParent)
    end
    if frame.ClearAllPoints then
        frame:ClearAllPoints()
    end
    if frame.SetSize and placement.width and placement.height then
        frame:SetSize(placement.width, placement.height)
    end
    if frame.SetFrameLevel and placement.frameLevel then
        pcall(frame.SetFrameLevel, frame, placement.frameLevel)
    end
    if placement.enabled ~= nil then
        if frame.SetEnabled then
            pcall(frame.SetEnabled, frame, placement.enabled == true)
        elseif placement.enabled and frame.Enable then
            pcall(frame.Enable, frame)
        elseif not placement.enabled and frame.Disable then
            pcall(frame.Disable, frame)
        end
    end
    if frame.SetPoint then
        for _, point in ipairs(placement.points or {}) do
            frame:SetPoint(point.point, point.relativeTo, point.relativePoint, point.xOffset, point.yOffset)
        end
    end
    if frame.SetShown then
        frame:SetShown(placement.shown == true)
    elseif placement.shown and frame.Show then
        frame:Show()
    elseif frame.Hide then
        frame:Hide()
    end
end

local function SetMeetingStoneNativeControlEnabled(frame, enabled)
    if not frame then
        return
    end

    if frame.SetEnabled then
        pcall(frame.SetEnabled, frame, enabled == true)
    elseif enabled and frame.Enable then
        pcall(frame.Enable, frame)
    elseif not enabled and frame.Disable then
        pcall(frame.Disable, frame)
    end
end

local function SetMeetingStoneRegionShown(region, shown)
    if not region then
        return
    end
    if region.SetShown then
        region:SetShown(shown == true)
    elseif shown and region.Show then
        region:Show()
    elseif region.Hide then
        region:Hide()
    end
end

local MEETINGSTONE_NATIVE_TITLE_DECORATION_KEYS = {
    "Left",
    "Middle",
    "Right",
    "NineSlice",
    "Border",
    "BorderBox",
    "Background",
    "Bg",
}

local MEETINGSTONE_NATIVE_TITLE_DECORATION_SUFFIXES = {
    "Left",
    "Middle",
    "Right",
    "NineSlice",
    "Border",
    "Background",
    "Bg",
}

local function AddMeetingStoneNativeTitleDecorationRegion(regions, seen, region)
    if not region or seen[region] then
        return
    end
    if not (region.Hide or region.SetShown) then
        return
    end

    seen[region] = true
    regions[#regions + 1] = region
end

local function GetMeetingStoneNativeTitleDecorationRegions(frame)
    local regions = {}
    local seen = {}
    if not frame then
        return regions
    end

    for _, key in ipairs(MEETINGSTONE_NATIVE_TITLE_DECORATION_KEYS) do
        AddMeetingStoneNativeTitleDecorationRegion(regions, seen, frame[key])
    end

    local name = frame.GetName and frame:GetName()
    if name and name ~= "" then
        for _, suffix in ipairs(MEETINGSTONE_NATIVE_TITLE_DECORATION_SUFFIXES) do
            AddMeetingStoneNativeTitleDecorationRegion(regions, seen, _G[name .. suffix])
        end
    end

    return regions
end

local function HideMeetingStoneNativeTitleDecoration(frame)
    if not frame then
        return
    end

    if not frame._mkMeetingStoneTitleDecorationState then
        local state = {}
        for _, region in ipairs(GetMeetingStoneNativeTitleDecorationRegions(frame)) do
            state[#state + 1] = {
                region = region,
                shown = region.IsShown and region:IsShown() or false,
            }
        end
        frame._mkMeetingStoneTitleDecorationState = state
    end

    for _, entry in ipairs(frame._mkMeetingStoneTitleDecorationState or {}) do
        SetMeetingStoneRegionShown(entry.region, false)
    end
end

local function RestoreMeetingStoneNativeTitleDecoration(frame)
    local state = frame and frame._mkMeetingStoneTitleDecorationState
    if type(state) ~= "table" then
        return
    end

    for _, entry in ipairs(state) do
        SetMeetingStoneRegionShown(entry.region, entry.shown == true)
    end
    frame._mkMeetingStoneTitleDecorationState = nil
end

local function CaptureMeetingStoneFontStringState(fontString)
    if not fontString then
        return nil
    end

    local state = {
        shown = fontString.IsShown and fontString:IsShown() or false,
        text = fontString.GetText and fontString:GetText() or nil,
        points = {},
    }
    if fontString.GetNumPoints and fontString.GetPoint then
        for index = 1, fontString:GetNumPoints() do
            local point, relativeTo, relativePoint, xOffset, yOffset = fontString:GetPoint(index)
            state.points[#state.points + 1] = {
                point = point,
                relativeTo = relativeTo,
                relativePoint = relativePoint,
                xOffset = xOffset,
                yOffset = yOffset,
            }
        end
    end
    if fontString.GetFont then
        local ok, fontFile, fontHeight, fontFlags = pcall(fontString.GetFont, fontString)
        if ok then
            state.fontFile = fontFile
            state.fontHeight = fontHeight
            state.fontFlags = fontFlags
        end
    end
    if fontString.GetTextColor then
        local ok, r, g, b, a = pcall(fontString.GetTextColor, fontString)
        if ok then
            state.textColor = { r, g, b, a }
        end
    end
    if fontString.GetJustifyH then
        local ok, justifyH = pcall(fontString.GetJustifyH, fontString)
        if ok then
            state.justifyH = justifyH
        end
    end
    if fontString.GetJustifyV then
        local ok, justifyV = pcall(fontString.GetJustifyV, fontString)
        if ok then
            state.justifyV = justifyV
        end
    end
    if fontString.GetWordWrap then
        local ok, wordWrap = pcall(fontString.GetWordWrap, fontString)
        if ok then
            state.wordWrap = wordWrap
        end
    end
    return state
end

local function RestoreMeetingStoneFontStringState(fontString, state)
    if not fontString or not state then
        return
    end

    if fontString.SetText and state.text ~= nil then
        fontString:SetText(state.text)
    end
    if fontString.SetFont and state.fontFile and state.fontHeight then
        pcall(fontString.SetFont, fontString, state.fontFile, state.fontHeight, state.fontFlags)
    end
    if fontString.SetTextColor and state.textColor then
        fontString:SetTextColor(state.textColor[1], state.textColor[2], state.textColor[3], state.textColor[4])
    end
    if fontString.SetJustifyH and state.justifyH then
        pcall(fontString.SetJustifyH, fontString, state.justifyH)
    end
    if fontString.SetJustifyV and state.justifyV then
        pcall(fontString.SetJustifyV, fontString, state.justifyV)
    end
    if fontString.SetWordWrap and state.wordWrap ~= nil then
        pcall(fontString.SetWordWrap, fontString, state.wordWrap == true)
    end
    if fontString.ClearAllPoints then
        fontString:ClearAllPoints()
    end
    if fontString.SetPoint then
        for _, point in ipairs(state.points or {}) do
            fontString:SetPoint(point.point, point.relativeTo, point.relativePoint, point.xOffset, point.yOffset)
        end
    end
    SetMeetingStoneRegionShown(fontString, state.shown == true)
end

local function EnsureMeetingStoneNativePlaceholder(holder, key, text, multiline)
    if not holder or not key then
        return nil
    end

    holder._mkMeetingStoneNativePlaceholders = holder._mkMeetingStoneNativePlaceholders or {}
    local overlay = holder._mkMeetingStoneNativePlaceholders[key]
    if not overlay then
        overlay = CreateFrame("Frame", nil, holder)
        overlay:SetAllPoints(holder)
        overlay:EnableMouse(false)

        local label = overlay:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
        label:SetJustifyH("LEFT")
        label:SetJustifyV(multiline and "TOP" or "MIDDLE")
        label:SetTextColor(0.58, 0.56, 0.52, 0.95)
        if core.ApplyFont then
            core.ApplyFont(label, MEETINGSTONE_FORM_PLACEHOLDER_TEXT_SIZE, "")
        end
        if multiline then
            label:SetPoint(
                "TOPLEFT",
                overlay,
                "TOPLEFT",
                (MEETINGSTONE_ATTACHED_SUMMARY_OFFSET_LEFT or 0) + (MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_LEFT or 0),
                -(MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_TOP or 0)
            )
            label:SetPoint("RIGHT", overlay, "RIGHT", -8, 0)
            if label.SetWordWrap then
                label:SetWordWrap(true)
            end
        else
            label:SetPoint("LEFT", overlay, "LEFT", 10, 0)
            label:SetPoint("RIGHT", overlay, "RIGHT", -10, 0)
        end
        overlay.label = label
        holder._mkMeetingStoneNativePlaceholders[key] = overlay
    end

    if overlay.label then
        overlay.label:SetText(text or "")
    end
    overlay:Hide()
    return overlay
end

local function RefreshMeetingStoneNativePlaceholder(control)
    if not control then
        return
    end

    local overlay = control._mkMeetingStoneNativePlaceholder
    local attachedFrame = control._mkMeetingStoneNativeAttachedFrame
    local holder = control._mkMeetingStoneNativePlaceholderHolder
    local active = control._mkMeetingStoneNativePlaceholderActive == true
    if not (active and overlay and attachedFrame and holder) then
        SetMeetingStoneRegionShown(overlay, false)
        return
    end

    local attached = attachedFrame.GetParent and attachedFrame:GetParent() == holder
    if not attached then
        SetMeetingStoneRegionShown(overlay, false)
        return
    end

    if overlay.SetFrameLevel and attachedFrame.GetFrameLevel then
        pcall(overlay.SetFrameLevel, overlay, attachedFrame:GetFrameLevel() + 10)
    end

    local instructions = control.Instructions
    if instructions then
        SetMeetingStoneRegionShown(instructions, false)
    end

    local text = control.GetText and control:GetText() or ""
    SetMeetingStoneRegionShown(overlay, text == "")
end

local function AttachMeetingStoneNativePlaceholder(control, attachedFrame, holder, key, text, multiline)
    if not control or not holder or not key then
        return
    end

    local instructions = control.Instructions
    if instructions and not control._mkMeetingStoneNativeInstructionState then
        control._mkMeetingStoneNativeInstructionState = CaptureMeetingStoneFontStringState(instructions)
    end

    control._mkMeetingStoneNativePlaceholder = EnsureMeetingStoneNativePlaceholder(holder, key, text, multiline)
    control._mkMeetingStoneNativePlaceholderHolder = holder
    control._mkMeetingStoneNativeAttachedFrame = attachedFrame or control
    control._mkMeetingStoneNativePlaceholderActive = true

    if not control._mkMeetingStoneNativePlaceholderHooked and control.HookScript then
        control:HookScript("OnTextChanged", RefreshMeetingStoneNativePlaceholder)
        control:HookScript("OnEditFocusGained", RefreshMeetingStoneNativePlaceholder)
        control:HookScript("OnEditFocusLost", RefreshMeetingStoneNativePlaceholder)
        control._mkMeetingStoneNativePlaceholderHooked = true
    end
    RefreshMeetingStoneNativePlaceholder(control)
end

local function RestoreMeetingStoneNativePlaceholder(control)
    if not control then
        return
    end

    control._mkMeetingStoneNativePlaceholderActive = false
    SetMeetingStoneRegionShown(control._mkMeetingStoneNativePlaceholder, false)
    if control.Instructions and control._mkMeetingStoneNativeInstructionState then
        RestoreMeetingStoneFontStringState(control.Instructions, control._mkMeetingStoneNativeInstructionState)
    end
    control._mkMeetingStoneNativeInstructionState = nil
    control._mkMeetingStoneNativePlaceholder = nil
    control._mkMeetingStoneNativePlaceholderHolder = nil
    control._mkMeetingStoneNativeAttachedFrame = nil
end

local function NextMeetingStoneNativeBorrowToken()
    meetingStoneNativeBorrowSerial = meetingStoneNativeBorrowSerial + 1
    return MEETINGSTONE_NATIVE_BORROW_OWNER .. ":" .. meetingStoneNativeBorrowSerial
end

local function IsMeetingStoneNativeControlBorrowedByAssistant(frame, token)
    if not frame then
        return false
    end
    if token and frame._mkMeetingStoneNativeBorrowToken ~= token then
        return false
    end
    if frame._gfBorrowOwner and frame._gfBorrowOwner ~= MEETINGSTONE_NATIVE_BORROW_OWNER then
        return false
    end
    if frame._GFBorrowOwner and frame._GFBorrowOwner ~= MEETINGSTONE_NATIVE_BORROW_OWNER_LEGACY then
        return false
    end
    if frame._mkMeetingStoneNativeBorrowOwner == MEETINGSTONE_NATIVE_BORROW_OWNER then
        return true
    end
    if frame._gfBorrowOwner == MEETINGSTONE_NATIVE_BORROW_OWNER
        and (not frame._gfBorrowChannel or frame._gfBorrowChannel == MEETINGSTONE_NATIVE_BORROW_CHANNEL)
    then
        return true
    end
    return frame._GFBorrowOwner == MEETINGSTONE_NATIVE_BORROW_OWNER_LEGACY
end

local function MarkMeetingStoneNativeControlBorrowed(frame, state, reason)
    if not (frame and state) then
        return
    end

    if not state.borrowToken or frame._mkMeetingStoneNativeBorrowToken ~= state.borrowToken then
        state.borrowToken = NextMeetingStoneNativeBorrowToken()
    end
    state.borrowOwner = MEETINGSTONE_NATIVE_BORROW_OWNER
    state.borrowChannel = MEETINGSTONE_NATIVE_BORROW_CHANNEL
    state.borrowReason = reason

    local since = _G.GetTime and _G.GetTime() or nil
    frame._mkMeetingStoneNativeBorrowOwner = MEETINGSTONE_NATIVE_BORROW_OWNER
    frame._mkMeetingStoneNativeBorrowChannel = MEETINGSTONE_NATIVE_BORROW_CHANNEL
    frame._mkMeetingStoneNativeBorrowToken = state.borrowToken
    frame._mkMeetingStoneNativeBorrowReason = reason
    frame._mkMeetingStoneNativeBorrowSince = since
    frame._gfBorrowOwner = MEETINGSTONE_NATIVE_BORROW_OWNER
    frame._gfBorrowChannel = MEETINGSTONE_NATIVE_BORROW_CHANNEL
    frame._GFBorrowOwner = MEETINGSTONE_NATIVE_BORROW_OWNER_LEGACY
    frame._GFBorrowChannel = MEETINGSTONE_NATIVE_BORROW_CHANNEL
    frame._GFBorrowToken = state.borrowToken
    frame._GFBorrowReason = reason
    frame._GFBorrowSince = since
end

local function ClearMeetingStoneNativeControlBorrowed(frame, state)
    if not (frame and state and state.borrowToken) then
        return false
    end
    if frame._mkMeetingStoneNativeBorrowToken ~= state.borrowToken then
        return false
    end

    if frame._mkMeetingStoneNativeBorrowOwner == MEETINGSTONE_NATIVE_BORROW_OWNER then
        frame._mkMeetingStoneNativeBorrowOwner = nil
        frame._mkMeetingStoneNativeBorrowChannel = nil
        frame._mkMeetingStoneNativeBorrowToken = nil
        frame._mkMeetingStoneNativeBorrowReason = nil
        frame._mkMeetingStoneNativeBorrowSince = nil
    end
    if frame._gfBorrowOwner == MEETINGSTONE_NATIVE_BORROW_OWNER
        and frame._gfBorrowChannel == MEETINGSTONE_NATIVE_BORROW_CHANNEL
    then
        frame._gfBorrowOwner = nil
        frame._gfBorrowChannel = nil
    end
    if frame._GFBorrowOwner == MEETINGSTONE_NATIVE_BORROW_OWNER_LEGACY
        and frame._GFBorrowToken == state.borrowToken
    then
        frame._GFBorrowOwner = nil
        frame._GFBorrowChannel = nil
        frame._GFBorrowToken = nil
        frame._GFBorrowReason = nil
        frame._GFBorrowSince = nil
    end

    state.borrowToken = nil
    state.borrowOwner = nil
    state.borrowChannel = nil
    state.borrowReason = nil
    return true
end

local function ClearMeetingStoneNativeInputBorrowMarkers(owner)
    local states = owner and owner.meetingStoneNativeControlStates
    if type(states) ~= "table" then
        return
    end

    for _, key in ipairs({ "titleBox", "summaryFrame" }) do
        local state = states[key]
        if state and state.frame then
            ClearMeetingStoneNativeControlBorrowed(state.frame, state)
            state.attached = false
        end
    end
end

local function IsMeetingStoneBorrowStateStillInHolder(state)
    if not (state and state.frame and state.holder and state.frame.GetParent) then
        return true
    end
    local ok, parent = pcall(state.frame.GetParent, state.frame)
    return ok and parent == state.holder
end

local function CanRestoreMeetingStoneNativeControl(state, parentState)
    if not (state and state.frame) then
        return false
    end
    if state.borrowToken then
        return IsMeetingStoneBorrowStateStillInHolder(state)
            and IsMeetingStoneNativeControlBorrowedByAssistant(state.frame, state.borrowToken)
    end
    if parentState and parentState.borrowToken then
        return IsMeetingStoneBorrowStateStillInHolder(parentState)
            and IsMeetingStoneNativeControlBorrowedByAssistant(parentState.frame, parentState.borrowToken)
    end
    return state.attached == true
end

local function CaptureMeetingStoneNativeControl(owner, key, frame)
    if not owner or not key or not frame then
        return nil
    end

    owner.meetingStoneNativeControlStates = owner.meetingStoneNativeControlStates or {}
    local state = owner.meetingStoneNativeControlStates[key]
    if not state or state.frame ~= frame or not state.attached then
        state = {
            frame = frame,
            placement = CaptureMeetingStoneFramePlacement(frame),
            attached = false,
        }
        owner.meetingStoneNativeControlStates[key] = state
    end
    return state
end

local function AttachMeetingStoneNativeFrame(owner, key, frame, holder)
    if not owner or not key or not frame or not holder then
        return nil
    end

    local state = CaptureMeetingStoneNativeControl(owner, key, frame)
    if state then
        state.attached = true
        state.holder = holder
    end

    frame:SetParent(holder)
    frame:ClearAllPoints()
    if key == "titleBox" then
        frame:SetPoint("TOPLEFT", holder, "TOPLEFT", MEETINGSTONE_FORM_TITLE_NATIVE_OFFSET_LEFT, 0)
        frame:SetPoint("BOTTOMRIGHT", holder, "BOTTOMRIGHT", MEETINGSTONE_FORM_TITLE_NATIVE_OFFSET_RIGHT, 0)
    elseif key == "summaryFrame" then
        frame:SetPoint("TOPLEFT", holder, "TOPLEFT", MEETINGSTONE_ATTACHED_SUMMARY_OFFSET_LEFT, 0)
        frame:SetPoint("BOTTOMRIGHT", holder, "BOTTOMRIGHT", MEETINGSTONE_ATTACHED_SUMMARY_OFFSET_RIGHT, 0)
    else
        frame:SetAllPoints(holder)
    end
    if frame.SetFrameLevel and holder.GetFrameLevel then
        pcall(frame.SetFrameLevel, frame, (holder:GetFrameLevel() or 0) + 5)
    end
    frame:Show()
    if state then
        MarkMeetingStoneNativeControlBorrowed(frame, state, key)
    end
    return frame
end

local function RouteMeetingStoneNativeTitleTextChanged(owner, entryCreation, titleBox)
    if not (owner and entryCreation and titleBox and titleBox.SetScript) then
        return
    end

    local currentScript = titleBox.GetScript and titleBox:GetScript("OnTextChanged") or nil
    local currentWrapper = titleBox._mkMeetingStoneTitleOnTextChangedWrapper
    if currentScript == currentWrapper and titleBox._mkMeetingStoneTitleRouteEntryCreation == entryCreation then
        titleBox._mkMeetingStoneOwner = owner
        return
    end

    titleBox._mkMeetingStoneOwner = owner
    titleBox._mkMeetingStoneTitleRouteEntryCreation = entryCreation
    titleBox._mkMeetingStoneTitleOriginalOnTextChanged = nil

    local wrapper
    wrapper = function(self, ...)
        local userInput = ...
        -- Other LFG addons also replace this singleton's script; do not replay their stale handlers.
        if _G.InputBoxInstructions_OnTextChanged then
            pcall(_G.InputBoxInstructions_OnTextChanged, self)
        end
        RefreshMeetingStoneNativePlaceholder(self)
        if _G.LFGListEntryCreation_UpdateValidState then
            pcall(_G.LFGListEntryCreation_UpdateValidState, entryCreation)
        end

        local currentOwner = self._mkMeetingStoneOwner
        if not (currentOwner and currentOwner.IsMainWindowShown and currentOwner:IsMainWindowShown()) then
            return
        end
        if currentOwner.activeTab ~= "meetingstone" or not currentOwner.widgets or currentOwner.widgets.meetingStoneTitleBox ~= self then
            return
        end
        if userInput == false and currentOwner.meetingStonePreparingNativeEditState == true then
            currentOwner:RefreshMeetingStoneActionButtons()
            return
        end
        if userInput == false and currentOwner.meetingStoneSubmittingNativeText == true then
            currentOwner:SyncMeetingStoneDraftFromWidgets()
            currentOwner:RefreshMeetingStoneActionButtons()
            return
        end
        if userInput == false
            and currentOwner.ShouldPreserveMeetingStoneManagedFormText
            and currentOwner:ShouldPreserveMeetingStoneManagedFormText()
            and currentOwner.RestoreMeetingStoneProtectedNativeText
            and currentOwner:RestoreMeetingStoneProtectedNativeText("title")
        then
            currentOwner:RefreshMeetingStoneActionButtons()
            return
        end
        currentOwner:SyncMeetingStoneDraftFromWidgets()
        currentOwner:RefreshMeetingStoneActionButtons()
    end
    titleBox._mkMeetingStoneTitleOnTextChangedWrapper = wrapper
    titleBox:SetScript("OnTextChanged", wrapper)
end

local function RouteMeetingStoneNativeSummaryTextChanged(owner, entryCreation, summaryBox)
    if not (owner and entryCreation and summaryBox and summaryBox.SetScript) then
        return
    end

    local currentScript = summaryBox.GetScript and summaryBox:GetScript("OnTextChanged") or nil
    local currentWrapper = summaryBox._mkMeetingStoneSummaryOnTextChangedWrapper
    if currentScript == currentWrapper and summaryBox._mkMeetingStoneSummaryRouteEntryCreation == entryCreation then
        summaryBox._mkMeetingStoneOwner = owner
        return
    end

    summaryBox._mkMeetingStoneOwner = owner
    summaryBox._mkMeetingStoneSummaryRouteEntryCreation = entryCreation

    local wrapper
    wrapper = function(self, ...)
        local userInput = ...
        -- Keep Blizzard's scrolling edit-box maintenance, but ignore stale addon-owned routing.
        if _G.InputScrollFrame_OnTextChanged then
            pcall(_G.InputScrollFrame_OnTextChanged, self, userInput)
        elseif _G.InputBoxInstructions_OnTextChanged then
            pcall(_G.InputBoxInstructions_OnTextChanged, self)
        end
        RefreshMeetingStoneNativePlaceholder(self)
        if _G.LFGListEntryCreation_UpdateValidState then
            pcall(_G.LFGListEntryCreation_UpdateValidState, entryCreation)
        end

        local currentOwner = self._mkMeetingStoneOwner
        if not (currentOwner and currentOwner.IsMainWindowShown and currentOwner:IsMainWindowShown()) then
            return
        end
        if currentOwner.activeTab ~= "meetingstone" or not currentOwner.widgets or currentOwner.widgets.meetingStoneSummaryBox ~= self then
            return
        end
        if userInput == false and currentOwner.meetingStonePreparingNativeEditState == true then
            currentOwner:RefreshMeetingStoneActionButtons()
            return
        end
        if userInput == false and currentOwner.meetingStoneSubmittingNativeText == true then
            currentOwner:SyncMeetingStoneDraftFromWidgets()
            currentOwner:RefreshMeetingStoneActionButtons()
            return
        end
        if userInput == false
            and currentOwner.ShouldPreserveMeetingStoneManagedFormText
            and currentOwner:ShouldPreserveMeetingStoneManagedFormText()
            and currentOwner.RestoreMeetingStoneProtectedNativeText
            and currentOwner:RestoreMeetingStoneProtectedNativeText("summary")
        then
            return
        end
        currentOwner:SyncMeetingStoneDraftFromWidgets()
    end
    summaryBox._mkMeetingStoneSummaryOnTextChangedWrapper = wrapper
    summaryBox:SetScript("OnTextChanged", wrapper)
end

local function ApplyMeetingStoneSummaryTextInsets(editBox, relativeFrame)
    if not editBox or not relativeFrame then
        return
    end

    editBox:ClearAllPoints()
    editBox:SetPoint("TOPLEFT", relativeFrame, "TOPLEFT", MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_LEFT, -MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_TOP)
    editBox:SetPoint("BOTTOMRIGHT", relativeFrame, "BOTTOMRIGHT", -MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_RIGHT, MEETINGSTONE_FORM_SUMMARY_TEXT_INSET_BOTTOM)
end

local function ApplyMeetingStoneNativeEntryCreationContext(entryCreation)
    if not entryCreation then
        return
    end

    for _, frame in ipairs({
        entryCreation.Name,
        entryCreation.Description,
        entryCreation.Description and entryCreation.Description.EditBox,
        entryCreation.VoiceChat,
        entryCreation.VoiceChat and entryCreation.VoiceChat.EditBox,
    }) do
        if frame then
            frame.selectedActivity = entryCreation.selectedActivity
            frame.selectedCategory = entryCreation.selectedCategory
        end
    end
end

function MK:DetachMeetingStoneNativeInputControls()
    local widgets = self.tabViews and self.tabViews.meetingstone or (self.activeTab == "meetingstone" and self.widgets) or nil
    local canSyncFromActiveWidgets = widgets and self.widgets == widgets
    local keepRecoveryActive = self.IsMainWindowShown
        and self:IsMainWindowShown()
        and self.activeTab == "meetingstone"
    if not keepRecoveryActive and self.meetingStoneNativeControlRecoveryTicker then
        if self.meetingStoneNativeControlRecoveryTicker.Cancel then
            pcall(self.meetingStoneNativeControlRecoveryTicker.Cancel, self.meetingStoneNativeControlRecoveryTicker)
        end
        self.meetingStoneNativeControlRecoveryTicker = nil
    end

    if canSyncFromActiveWidgets and self.SyncMeetingStoneDraftFromWidgets then
        self:SyncMeetingStoneDraftFromWidgets(true)
        if self.SaveMeetingStoneActiveListingDraft
            and self.IsMeetingStoneActiveListingManagedByAssistant
            and self:IsMeetingStoneActiveListingManagedByAssistant()
        then
            self:SaveMeetingStoneActiveListingDraft(self.meetingStoneDraft)
        end
    end

    local states = self.meetingStoneNativeControlStates
    if type(states) ~= "table" then
        if widgets then
            widgets.meetingStoneUsesNativeTextControls = false
            SetMeetingStoneNativeInputOccupied(widgets, false)
        end
        return
    end

    for _, key in ipairs({ "titleBox", "summaryBox", "summaryFrame" }) do
        local state = states[key]
        if state and (state.attached or key == "summaryBox") and state.frame then
            local parentState = key == "summaryBox" and states.summaryFrame or nil
            if CanRestoreMeetingStoneNativeControl(state, parentState) then
                RestoreMeetingStoneNativePlaceholder(state.frame)
                RestoreMeetingStoneFramePlacement(state.frame, state.placement)
                if key == "titleBox" then
                    RestoreMeetingStoneNativeTitleDecoration(state.frame)
                end
                ClearMeetingStoneNativeControlBorrowed(state.frame, state)
            end
            state.attached = false
        end
    end

    if widgets then
        widgets.meetingStoneUsesNativeTextControls = false
        SetMeetingStoneNativeInputOccupied(widgets, false)
    end
end

local function ReadMeetingStoneTextControl(control)
    if not (control and control.GetText) then
        return ""
    end

    local ok, text = pcall(control.GetText, control)
    if ok then
        return text or ""
    end
    return ""
end

local function SetMeetingStoneTextControl(control, text)
    if control and control.SetEnabled then
        pcall(control.SetEnabled, control, true)
    elseif control and control.Enable then
        pcall(control.Enable, control)
    end
    if control and control.SetText then
        pcall(control.SetText, control, text or "")
    end
    if control and control.SetCursorPosition and control.GetText then
        local ok, currentText = pcall(control.GetText, control)
        pcall(control.SetCursorPosition, control, ok and strlen(currentText or "") or 0)
    end
    local parent
    if control and control.GetParent then
        local ok, currentParent = pcall(control.GetParent, control)
        parent = ok and currentParent or nil
    end
    if control and parent and parent.ScrollBar and _G.InputScrollFrame_OnTextChanged then
        pcall(_G.InputScrollFrame_OnTextChanged, control, false)
    elseif control and _G.InputBoxInstructions_OnTextChanged then
        pcall(_G.InputBoxInstructions_OnTextChanged, control)
    end
    RefreshMeetingStoneNativePlaceholder(control)
end

local function TrimMeetingStoneBridgeText(text)
    text = tostring(text or "")
    local listing = core.MeetingStoneListing
    if listing and listing.TrimText then
        return listing.TrimText(text)
    end
    if strtrim then
        return strtrim(text)
    end
    return string.match(text, "^%s*(.-)%s*$") or text
end

local function IsMeetingStoneBridgeTextFilled(text)
    local listing = core.MeetingStoneListing
    if listing and listing.IsTextFilled then
        return listing.IsTextFilled(text) == true
    end
    return TrimMeetingStoneBridgeText(text) ~= ""
end

local function IsMeetingStoneFallbackControlVisible(frame)
    if not (frame and frame.IsShown) then
        return false
    end
    local ok, shown = pcall(frame.IsShown, frame)
    return ok and shown == true
end

local function CaptureMeetingStoneFallbackDraftForNativeAttach(owner, widgets)
    if not (owner and widgets) or widgets.meetingStoneUsesNativeTextControls == true then
        return false
    end

    if owner.SyncMeetingStoneDraftFromWidgets then
        owner:SyncMeetingStoneDraftFromWidgets(true)
    end

    local draft = type(owner.meetingStoneDraft) == "table" and owner.meetingStoneDraft or {}
    owner.meetingStoneDraft = draft
    local changed = false
    local fallbackActive = widgets.meetingStoneTitleBox == widgets.meetingStoneFallbackTitleBox
        or widgets.meetingStoneSummaryBox == widgets.meetingStoneFallbackSummaryBox
        or IsMeetingStoneFallbackControlVisible(widgets.meetingStoneFallbackTitleBox)
        or IsMeetingStoneFallbackControlVisible(widgets.meetingStoneFallbackSummaryFrame)

    if not fallbackActive then
        return false
    end

    local shouldAllowEmptyText = draft.source == "local-removal" or draft.suppressNativeTitleAutofill == true
    local title = TrimMeetingStoneBridgeText(ReadMeetingStoneTextControl(widgets.meetingStoneFallbackTitleBox))
    local summary = TrimMeetingStoneBridgeText(ReadMeetingStoneTextControl(widgets.meetingStoneFallbackSummaryBox))
    if (IsMeetingStoneBridgeTextFilled(title) or shouldAllowEmptyText) and draft.title ~= title then
        draft.title = title
        changed = true
    end
    if (IsMeetingStoneBridgeTextFilled(summary) or shouldAllowEmptyText) and draft.summary ~= summary then
        draft.summary = summary
        changed = true
    end

    if changed then
        owner.meetingStoneDraftID = (owner.meetingStoneDraftID or 0) + 1
        widgets.meetingStoneDraftID = nil
    end
    return changed
end

local function HasMeetingStoneActiveListingForNativeAttach()
    local listing = core.MeetingStoneListing
    if listing and listing.HasActiveListing then
        local ok, hasActive = pcall(listing.HasActiveListing)
        return ok and hasActive == true
    end
    if C_LFGList and C_LFGList.HasActiveEntryInfo then
        local ok, hasActive = pcall(C_LFGList.HasActiveEntryInfo)
        return ok and hasActive == true
    end
    return false
end

local function ApplyMeetingStoneDraftTextToAttachedNativeControls(owner, widgets, entryCreation, titleBox, summaryBox)
    if not (owner and widgets and entryCreation and titleBox and summaryBox) then
        return
    end

    local draft = type(owner.meetingStoneDraft) == "table" and owner.meetingStoneDraft or nil
    if not draft then
        return
    end

    local shouldWriteEmptyText = draft.source == "local-removal" or draft.suppressNativeTitleAutofill == true
    if HasMeetingStoneActiveListingForNativeAttach() and not shouldWriteEmptyText then
        return
    end

    local title = TrimMeetingStoneBridgeText(draft.title)
    local summary = TrimMeetingStoneBridgeText(draft.summary)
    if IsMeetingStoneBridgeTextFilled(title) or shouldWriteEmptyText then
        SetMeetingStoneTextControl(titleBox, title)
    end
    if IsMeetingStoneBridgeTextFilled(summary) or shouldWriteEmptyText then
        SetMeetingStoneTextControl(summaryBox, summary)
    end

    RefreshMeetingStoneNativePlaceholder(titleBox)
    RefreshMeetingStoneNativePlaceholder(summaryBox)
    if _G.LFGListEntryCreation_UpdateValidState then
        pcall(_G.LFGListEntryCreation_UpdateValidState, entryCreation)
    end
end

local function GetMeetingStoneControlParent(control)
    if not (control and control.GetParent) then
        return nil
    end

    local ok, currentParent = pcall(control.GetParent, control)
    if ok then
        return currentParent
    end
    return nil
end

local function IsMeetingStoneControlParentedTo(control, parent)
    if not (control and parent) then
        return false
    end
    return GetMeetingStoneControlParent(control) == parent
end

local function IsMeetingStoneFrameVisible(frame)
    if not frame then
        return false
    end

    if frame.IsVisible then
        local ok, visible = pcall(frame.IsVisible, frame)
        if ok then
            return visible == true
        end
    end
    if frame.IsShown then
        local ok, shown = pcall(frame.IsShown, frame)
        if ok then
            return shown == true
        end
    end
    return false
end

local function IsMeetingStoneNativeControlBorrowedByExternalAddon(control)
    if not control then
        return false
    end
    if control._gfBorrowOwner and control._gfBorrowOwner ~= MEETINGSTONE_NATIVE_BORROW_OWNER then
        return true
    end
    if control._GFBorrowOwner and control._GFBorrowOwner ~= MEETINGSTONE_NATIVE_BORROW_OWNER_LEGACY then
        return true
    end
    return control._mkMeetingStoneNativeBorrowOwner
        and control._mkMeetingStoneNativeBorrowOwner ~= MEETINGSTONE_NATIVE_BORROW_OWNER
end

local function IsMeetingStoneNativeControlHeldByExternalFrame(control, holder, nativeParent, systemPanelVisible)
    if not (control and holder and control.GetParent) then
        return false
    end
    if IsMeetingStoneNativeControlBorrowedByExternalAddon(control) then
        return true
    end

    local parent = GetMeetingStoneControlParent(control)
    if not parent then
        return false
    end
    if parent == holder then
        return systemPanelVisible == true
    end
    if nativeParent and parent == nativeParent then
        return systemPanelVisible == true
    end

    return true
end

local function IsMeetingStoneNativeInputHeldByExternalFrame(
    titleBox,
    titleHolder,
    summaryFrame,
    summaryHolder,
    summaryBox,
    entryCreation,
    systemPanelVisible
)
    return IsMeetingStoneNativeControlHeldByExternalFrame(titleBox, titleHolder, entryCreation, systemPanelVisible)
        or IsMeetingStoneNativeControlHeldByExternalFrame(summaryFrame, summaryHolder, entryCreation, systemPanelVisible)
        or IsMeetingStoneNativeControlHeldByExternalFrame(summaryBox, summaryFrame, summaryFrame, systemPanelVisible)
end

local function EnsureMeetingStoneNativeControlRecovery(owner)
    if not (owner and C_Timer and C_Timer.NewTicker) or owner.meetingStoneNativeControlRecoveryTicker then
        return
    end

    owner.meetingStoneNativeControlRecoveryTicker = C_Timer.NewTicker(MEETINGSTONE_NATIVE_CONTROL_RECOVERY_INTERVAL, function(ticker)
        if not (owner.IsMainWindowShown and owner:IsMainWindowShown() and owner.activeTab == "meetingstone" and owner.widgets) then
            if ticker and ticker.Cancel then
                ticker:Cancel()
            end
            owner.meetingStoneNativeControlRecoveryTicker = nil
            return
        end
        if owner.AttachMeetingStoneNativeInputControls then
            owner:AttachMeetingStoneNativeInputControls(owner.widgets)
        end
    end)
end

local function IsMeetingStoneNativeEntryCreationVisible(entryCreation)
    return IsMeetingStoneFrameVisible(entryCreation)
end

local function IsMeetingStoneNativeOrSystemPanelVisible()
    local entryCreation = GetMeetingStoneNativeEntryCreationFrame(true)
    if entryCreation and IsMeetingStoneNativeEntryCreationVisible(entryCreation) then
        return true
    end

    if IsMeetingStoneFrameVisible(_G.LFGListFrame) or IsMeetingStoneFrameVisible(_G.PVEFrame) then
        return true
    end

    if IsMeetingStoneAddonLoaded() then
        return IsMeetingStoneFrameVisible(_G.CreatePanel)
            or IsMeetingStoneFrameVisible(_G.ManagerPanel)
            or IsMeetingStoneFrameVisible(_G.MainPanel)
    end

    return false
end

local function CloseMeetingStoneAssistantForNativePanel(owner)
    if not (owner and owner.IsMainWindowShown and owner:IsMainWindowShown()) then
        return false
    end

    if owner.activeTab == "meetingstone" and owner.SyncMeetingStoneDraftFromWidgets then
        owner:SyncMeetingStoneDraftFromWidgets(true)
    end
    if owner.HideMainWindow then
        owner:HideMainWindow()
        return true
    end

    local frame = owner.mainWindow and (owner.mainWindow.frame or owner.mainWindow)
    if frame and frame.Hide then
        frame:Hide()
        return true
    end
    return false
end

local function RefreshMeetingStoneNativeTextControlRouting(owner)
    if not (owner and owner.IsMainWindowShown and owner:IsMainWindowShown()) then
        return
    end

    if owner.activeTab ~= "meetingstone" then
        return
    end

    local widgets = owner.widgets
    if not widgets then
        return
    end

    if owner.AttachMeetingStoneNativeInputControls then
        owner:AttachMeetingStoneNativeInputControls(widgets)
    end

    if owner.RefreshMeetingStoneActionButtons then
        owner:RefreshMeetingStoneActionButtons(widgets)
    end
end

local function QueueMeetingStoneNativeTextControlRouting(owner)
    local function refreshRouting()
        RefreshMeetingStoneNativeTextControlRouting(owner)
    end

    if C_Timer and C_Timer.After then
        C_Timer.After(0, refreshRouting)
        C_Timer.After(0.05, refreshRouting)
    else
        refreshRouting()
    end
end

local function HookMeetingStoneNativeVisibilityFrame(owner, frame)
    if not (owner and frame and frame.HookScript) or frame._mkMeetingStoneTextRoutingHooked then
        return
    end

    frame:HookScript("OnShow", function()
        QueueMeetingStoneNativeTextControlRouting(owner)
    end)
    frame:HookScript("OnHide", function()
        if owner.IsMainWindowShown and owner:IsMainWindowShown() and owner.activeTab == "meetingstone" and owner.SyncMeetingStoneDraftFromWidgets then
            owner:SyncMeetingStoneDraftFromWidgets(true)
        end
        QueueMeetingStoneNativeTextControlRouting(owner)
    end)
    frame._mkMeetingStoneTextRoutingHooked = true
end

local function HookMeetingStoneNativeEntryCreationVisibility(owner, entryCreation)
    if not (owner and entryCreation) then
        return
    end

    HookMeetingStoneNativeVisibilityFrame(owner, entryCreation)
    HookMeetingStoneNativeVisibilityFrame(owner, entryCreation.GetParent and entryCreation:GetParent())
    HookMeetingStoneNativeVisibilityFrame(owner, _G.LFGListFrame)
    HookMeetingStoneNativeVisibilityFrame(owner, _G.PVEFrame)
end

local function HookMeetingStoneSystemPanelVisibility(owner)
    local entryCreation = GetMeetingStoneNativeEntryCreationFrame(true)
    if entryCreation then
        HookMeetingStoneNativeVisibilityFrame(owner, entryCreation)
        HookMeetingStoneNativeVisibilityFrame(owner, entryCreation.GetParent and entryCreation:GetParent())
    end

    HookMeetingStoneNativeVisibilityFrame(owner, _G.LFGListFrame)
    HookMeetingStoneNativeVisibilityFrame(owner, _G.PVEFrame)

    if IsMeetingStoneAddonLoaded() then
        HookMeetingStoneNativeVisibilityFrame(owner, _G.CreatePanel)
        HookMeetingStoneNativeVisibilityFrame(owner, _G.ManagerPanel)
        HookMeetingStoneNativeVisibilityFrame(owner, _G.MainPanel)
    end
end

local function RefreshMeetingStoneSystemPanelVisibilityRouting(owner)
    PatchMeetingStoneRecentCacheRecent()
    HookMeetingStoneSystemPanelVisibility(owner)
    RefreshMeetingStoneNativeTextControlRouting(owner)
end

local function QueueMeetingStoneSystemPanelVisibilityRouting(owner)
    local function refreshRouting()
        RefreshMeetingStoneSystemPanelVisibilityRouting(owner)
    end

    if C_Timer and C_Timer.After then
        C_Timer.After(0, refreshRouting)
        C_Timer.After(0.05, refreshRouting)
    else
        refreshRouting()
    end
end

function MK:SetupMeetingStoneNativePanelVisibilityRouting()
    if self.meetingStoneNativePanelVisibilityFrame then
        RefreshMeetingStoneSystemPanelVisibilityRouting(self)
        return
    end

    local frame = CreateFrame("Frame")
    frame:RegisterEvent("ADDON_LOADED")
    frame:RegisterEvent("PLAYER_ENTERING_WORLD")
    frame:RegisterEvent("PLAYER_REGEN_ENABLED")
    frame:RegisterEvent("LFG_LIST_ACTIVE_ENTRY_UPDATE")
    frame:SetScript("OnEvent", function(_, event, loadedAddonName)
        if event == "ADDON_LOADED"
            and loadedAddonName ~= "Blizzard_GroupFinder"
            and not IsMeetingStoneProviderAddon(loadedAddonName)
        then
            return
        end
        QueueMeetingStoneSystemPanelVisibilityRouting(self)
    end)
    self.meetingStoneNativePanelVisibilityFrame = frame
    QueueMeetingStoneSystemPanelVisibilityRouting(self)
end

function MK:AttachMeetingStoneNativeInputControls(widgets)
    widgets = widgets or self.widgets
    if not widgets then
        return false
    end

    HookMeetingStoneSystemPanelVisibility(self)

    if not CanManageMeetingStoneListing()
        or (self.IsMeetingStoneManagementAvailable and not self:IsMeetingStoneManagementAvailable())
    then
        SetMeetingStoneNativeInputOccupied(widgets, false)
        self:DetachMeetingStoneNativeInputControls()
        UseMeetingStoneFallbackInputControls(widgets)
        return false
    end

    EnsureMeetingStoneNativeControlRecovery(self)

    local entryCreation = GetMeetingStoneNativeEntryCreationFrame()
    local titleBox = entryCreation and entryCreation.Name
    local summaryFrame = entryCreation and entryCreation.Description
    local summaryBox = summaryFrame and summaryFrame.EditBox
    if not (entryCreation and titleBox and summaryFrame and summaryBox and widgets.meetingStoneTitleHolder and widgets.meetingStoneSummaryHolder) then
        SetMeetingStoneNativeInputOccupied(widgets, false)
        self:DetachMeetingStoneNativeInputControls()
        UseMeetingStoneFallbackInputControls(widgets)
        return false
    end

    if IsMeetingStoneNativeInputHeldByExternalFrame(
        titleBox,
        widgets.meetingStoneTitleHolder,
        summaryFrame,
        widgets.meetingStoneSummaryHolder,
        summaryBox,
        entryCreation,
        IsMeetingStoneNativeOrSystemPanelVisible()
    ) then
        self:DetachMeetingStoneNativeInputControls()
        ClearMeetingStoneNativeInputBorrowMarkers(self)
        RestoreMeetingStoneNativeTitleDecoration(titleBox)
        SetMeetingStoneNativeInputOccupied(widgets, true)
        if widgets.meetingStoneFallbackTitleBox then
            widgets.meetingStoneFallbackTitleBox:Hide()
        end
        if widgets.meetingStoneFallbackSummaryFrame then
            widgets.meetingStoneFallbackSummaryFrame:Hide()
        end
        return false
    end

    HookMeetingStoneNativeEntryCreationVisibility(self, entryCreation)
    ApplyMeetingStoneNativeEntryCreationContext(entryCreation)

    CaptureMeetingStoneFallbackDraftForNativeAttach(self, widgets)

    if widgets.meetingStoneFallbackTitleBox then
        widgets.meetingStoneFallbackTitleBox:Hide()
    end
    if widgets.meetingStoneFallbackSummaryFrame then
        widgets.meetingStoneFallbackSummaryFrame:Hide()
    end

    AttachMeetingStoneNativeFrame(self, "titleBox", titleBox, widgets.meetingStoneTitleHolder)
    HideMeetingStoneNativeTitleDecoration(titleBox)
    AttachMeetingStoneNativePlaceholder(
        titleBox,
        titleBox,
        widgets.meetingStoneTitleHolder,
        "title",
        TRANSLATE("请输入队伍名称"),
        false
    )
    CaptureMeetingStoneNativeControl(self, "summaryBox", summaryBox)
    AttachMeetingStoneNativeFrame(self, "summaryFrame", summaryFrame, widgets.meetingStoneSummaryHolder)
    ApplyMeetingStoneSummaryTextInsets(summaryBox, summaryFrame)
    AttachMeetingStoneNativePlaceholder(
        summaryBox,
        summaryFrame,
        widgets.meetingStoneSummaryHolder,
        "summary",
        TRANSLATE("请输入关于你的队伍的更多细节（可选）"),
        true
    )

    RouteMeetingStoneNativeTitleTextChanged(self, entryCreation, titleBox)
    RouteMeetingStoneNativeSummaryTextChanged(self, entryCreation, summaryBox)

    widgets.meetingStoneTitleBox = titleBox
    widgets.meetingStoneSummaryFrame = summaryFrame
    widgets.meetingStoneSummaryBox = summaryBox
    widgets.meetingStoneUsesNativeTextControls = true
    ApplyMeetingStoneDraftTextToAttachedNativeControls(self, widgets, entryCreation, titleBox, summaryBox)
    SetMeetingStoneNativeInputOccupied(widgets, false, true)
    if self.ShouldPreserveMeetingStoneManagedFormText
        and self:ShouldPreserveMeetingStoneManagedFormText()
        and self.RestoreMeetingStoneProtectedNativeText
    then
        self:RestoreMeetingStoneProtectedNativeText("title")
        self:RestoreMeetingStoneProtectedNativeText("summary")
    end
    return true
end

local function TryLoadQueueStatusFrameUI()
    if _G.EyeTemplateMixin then
        return true
    end

    if C_AddOns and C_AddOns.LoadAddOn then
        local ok = pcall(C_AddOns.LoadAddOn, "Blizzard_QueueStatusFrame")
        if ok and _G.EyeTemplateMixin then
            return true
        end
    end

    if UIParentLoadAddOn then
        local ok = pcall(UIParentLoadAddOn, "Blizzard_QueueStatusFrame")
        if ok and _G.EyeTemplateMixin then
            return true
        end
    end

    if LoadAddOn then
        local ok = pcall(LoadAddOn, "Blizzard_QueueStatusFrame")
        if ok and _G.EyeTemplateMixin then
            return true
        end
    end

    return _G.EyeTemplateMixin ~= nil
end

local function GetMeetingStoneQueueStatusButton()
    if not (_G.QueueStatusButton or _G.QueueStatusMinimapButton) then
        TryLoadQueueStatusFrameUI()
    end
    return _G.QueueStatusButton or _G.QueueStatusMinimapButton
end

local function HideMeetingStoneNativeGroupFinderFrames()
    if IsMeetingStoneCombatLocked() then
        return false
    end

    if _G.QueueStatusFrame and _G.QueueStatusFrame.Hide then
        pcall(_G.QueueStatusFrame.Hide, _G.QueueStatusFrame)
    end
    if IsMeetingStoneAddonLoaded() then
        for _, frame in ipairs({ _G.CreatePanel, _G.ManagerPanel, _G.MainPanel }) do
            if frame and frame.Hide then
                pcall(frame.Hide, frame)
            end
        end
    end
    if _G.PVEFrame and _G.PVEFrame.IsShown and _G.PVEFrame:IsShown() then
        if _G.HideUIPanel then
            pcall(_G.HideUIPanel, _G.PVEFrame)
        else
            pcall(_G.PVEFrame.Hide, _G.PVEFrame)
        end
    elseif _G.LFGListFrame and _G.LFGListFrame.Hide then
        pcall(_G.LFGListFrame.Hide, _G.LFGListFrame)
    end
    return true
end

local function RouteMeetingStoneQueueStatusButtonClick(owner, mouseButton)
    if mouseButton and mouseButton ~= "LeftButton" then
        return false
    end
    if not (owner and owner.IsMeetingStoneActiveSeasonDungeonListing and owner:IsMeetingStoneActiveSeasonDungeonListing()) then
        return false
    end

    if owner.OpenMeetingStonePanelFromQueueStatusEye then
        owner:OpenMeetingStonePanelFromQueueStatusEye()
        return true
    end
    return false
end

local queueStatusHookedButton

local function RestoreMeetingStoneQueueStatusButton(button)
    if not (button and button.GetScript and button.SetScript) then
        return false
    end
    if button:GetScript("OnClick") ~= button.mkMeetingStoneQueueStatusOnClickWrapper then
        return false
    end
    if IsMeetingStoneCombatLocked() then
        return false
    end

    local ok = pcall(button.SetScript, button, "OnClick", button.mkMeetingStoneQueueStatusOriginalOnClick)
    if not ok then
        return false
    end

    button.mkMeetingStoneQueueStatusOnClickWrapper = nil
    button.mkMeetingStoneQueueStatusOriginalOnClick = nil
    button.mkMeetingStoneQueueStatusOwner = nil
    if queueStatusHookedButton == button then
        queueStatusHookedButton = nil
    end
    return true
end

local function HookMeetingStoneQueueStatusButton(owner)
    local button = GetMeetingStoneQueueStatusButton()
    if not (owner and button and button.GetScript and button.SetScript) then
        return false
    end
    local currentOnClick = button:GetScript("OnClick")
    local shouldRouteQueueStatusEye = owner.IsMeetingStoneActiveSeasonDungeonListing
        and owner:IsMeetingStoneActiveSeasonDungeonListing()
    if currentOnClick == button.mkMeetingStoneQueueStatusOnClickWrapper then
        if shouldRouteQueueStatusEye then
            button.mkMeetingStoneQueueStatusOwner = owner
            queueStatusHookedButton = button
            return true
        end
        RestoreMeetingStoneQueueStatusButton(button)
        return false
    end

    if not shouldRouteQueueStatusEye then
        return false
    end
    if IsMeetingStoneCombatLocked() then
        return false
    end

    local originalOnClick = currentOnClick
    local wrapper
    wrapper = function(clickedButton, mouseButton, ...)
        local currentOwner = clickedButton and clickedButton.mkMeetingStoneQueueStatusOwner or owner
        local handled = RouteMeetingStoneQueueStatusButtonClick(currentOwner, mouseButton)
        if handled then
            if C_Timer and C_Timer.After then
                C_Timer.After(0, HideMeetingStoneNativeGroupFinderFrames)
            else
                HideMeetingStoneNativeGroupFinderFrames()
            end
            return
        end

        if originalOnClick then
            return originalOnClick(clickedButton, mouseButton, ...)
        end
    end

    local ok = pcall(button.SetScript, button, "OnClick", wrapper)
    if not ok then
        return false
    end

    button.mkMeetingStoneQueueStatusOnClickWrapper = wrapper
    button.mkMeetingStoneQueueStatusOriginalOnClick = originalOnClick
    button.mkMeetingStoneQueueStatusOwner = owner
    queueStatusHookedButton = button
    return true
end

local function QueueMeetingStoneQueueStatusRoutingRefresh(owner)
    if C_Timer and C_Timer.After then
        C_Timer.After(0, function()
            HookMeetingStoneQueueStatusButton(owner)
            if owner and owner.RefreshQueueStatusButtonOffset then
                owner:RefreshQueueStatusButtonOffset()
            end
        end)
    else
        HookMeetingStoneQueueStatusButton(owner)
        if owner and owner.RefreshQueueStatusButtonOffset then
            owner:RefreshQueueStatusButtonOffset()
        end
    end
end

function MK:SetupMeetingStoneQueueStatusRouting()
    if self.meetingStoneQueueStatusRoutingFrame then
        HookMeetingStoneQueueStatusButton(self)
        if self.RefreshQueueStatusButtonOffset then
            self:RefreshQueueStatusButtonOffset()
        end
        return
    end

    local frame = CreateFrame("Frame")
    frame:RegisterEvent("ADDON_LOADED")
    frame:RegisterEvent("PLAYER_ENTERING_WORLD")
    frame:RegisterEvent("PLAYER_REGEN_ENABLED")
    frame:RegisterEvent("LFG_LIST_ACTIVE_ENTRY_UPDATE")
    frame:SetScript("OnEvent", function(_, event, loadedAddonName)
        if event == "ADDON_LOADED" and loadedAddonName ~= "Blizzard_QueueStatusFrame" then
            return
        end
        QueueMeetingStoneQueueStatusRoutingRefresh(self)
    end)
    self.meetingStoneQueueStatusRoutingFrame = frame
    QueueMeetingStoneQueueStatusRoutingRefresh(self)
end

local function QueueMeetingStoneLeaderChangePopupOpen(owner, action)
    if not (owner and owner.OpenMeetingStonePanelFromLeadershipChange) then
        return
    end

    local function openMeetingStonePanel()
        if owner.OpenMeetingStonePanelFromLeadershipChange then
            owner:OpenMeetingStonePanelFromLeadershipChange(action)
        end
    end

    if C_Timer and C_Timer.After then
        C_Timer.After(0, openMeetingStonePanel)
    else
        openMeetingStonePanel()
    end
end

local function HookMeetingStoneLeaderChangePopup(owner)
    if not (owner and _G.StaticPopupDialogs) then
        return false
    end

    local dialogInfo = _G.StaticPopupDialogs[MEETINGSTONE_LEADER_CHANGE_POPUP_KEY]
    if type(dialogInfo) ~= "table" then
        return false
    end

    if dialogInfo.mkMeetingStoneLeaderChangePopupHooked then
        dialogInfo.mkMeetingStoneLeaderChangePopupOwner = owner
        return true
    end

    local originalOnAccept = dialogInfo.OnAccept
    local originalOnCancel = dialogInfo.OnCancel

    dialogInfo.OnAccept = function(dialog, data, ...)
        local currentOwner = dialogInfo.mkMeetingStoneLeaderChangePopupOwner or owner
        local keepOpen
        if originalOnAccept then
            keepOpen = originalOnAccept(dialog, data, ...)
        end
        if dialog then
            dialog.delistOnHide = false
        end
        QueueMeetingStoneLeaderChangePopupOpen(currentOwner, "list")
        return keepOpen
    end

    dialogInfo.OnCancel = function(dialog, data, reason, ...)
        local currentOwner = dialogInfo.mkMeetingStoneLeaderChangePopupOwner or owner
        local keepOpen
        if originalOnCancel then
            keepOpen = originalOnCancel(dialog, data, reason, ...)
        end
        if reason == "clicked" then
            if dialog then
                dialog.delistOnHide = false
            end
            QueueMeetingStoneLeaderChangePopupOpen(currentOwner, "edit")
        end
        return keepOpen
    end

    dialogInfo.mkMeetingStoneLeaderChangePopupHooked = true
    dialogInfo.mkMeetingStoneLeaderChangePopupOwner = owner
    return true
end

local function QueueMeetingStoneLeaderChangePopupRoutingRefresh(owner)
    if C_Timer and C_Timer.After then
        C_Timer.After(0, function()
            HookMeetingStoneLeaderChangePopup(owner)
        end)
    else
        HookMeetingStoneLeaderChangePopup(owner)
    end
end

function MK:SetupMeetingStoneLeaderChangePopupRouting()
    if self.meetingStoneLeaderChangePopupRoutingFrame then
        HookMeetingStoneLeaderChangePopup(self)
        return
    end

    local frame = CreateFrame("Frame")
    frame:RegisterEvent("ADDON_LOADED")
    frame:RegisterEvent("PLAYER_ENTERING_WORLD")
    frame:SetScript("OnEvent", function(_, event, loadedAddonName)
        if event == "ADDON_LOADED"
            and loadedAddonName ~= "Blizzard_StaticPopup_Game"
            and loadedAddonName ~= "Blizzard_GroupFinder"
        then
            return
        end
        QueueMeetingStoneLeaderChangePopupRoutingRefresh(self)
    end)
    self.meetingStoneLeaderChangePopupRoutingFrame = frame
    QueueMeetingStoneLeaderChangePopupRoutingRefresh(self)
end


MeetingStoneBridge.IsAddonLoaded = IsAddonLoaded
MeetingStoneBridge.IsAddonInstalled = IsAddonInstalled
MeetingStoneBridge.IsAddonEnabled = IsAddonEnabled
MeetingStoneBridge.TryLoadAddon = TryLoadAddon
MeetingStoneBridge.GetMeetingStoneProviderAddonNames = GetMeetingStoneProviderAddonNames
MeetingStoneBridge.IsMeetingStoneProviderAddon = IsMeetingStoneProviderAddon
MeetingStoneBridge.IsMeetingStoneAddonInstalled = IsMeetingStoneAddonInstalled
MeetingStoneBridge.IsMeetingStoneAddonEnabled = IsMeetingStoneAddonEnabled
MeetingStoneBridge.TryLoadMeetingStoneAddon = TryLoadMeetingStoneAddon
MeetingStoneBridge.IsMeetingStoneAddonLoaded = IsMeetingStoneAddonLoaded
MeetingStoneBridge.GetEnv = GetMeetingStoneEnv
MeetingStoneBridge.GetRuntime = GetMeetingStoneRuntime
MeetingStoneBridge.GetNativeEntryCreationFrame = GetMeetingStoneNativeEntryCreationFrame
MeetingStoneBridge.CaptureFramePlacement = CaptureMeetingStoneFramePlacement
MeetingStoneBridge.RestoreFramePlacement = RestoreMeetingStoneFramePlacement
MeetingStoneBridge.SetNativeControlEnabled = SetMeetingStoneNativeControlEnabled
MeetingStoneBridge.CaptureNativeControl = CaptureMeetingStoneNativeControl
MeetingStoneBridge.AttachNativeFrame = AttachMeetingStoneNativeFrame
MeetingStoneBridge.ApplySummaryTextInsets = ApplyMeetingStoneSummaryTextInsets
MeetingStoneBridge.ReadTextControl = ReadMeetingStoneTextControl
MeetingStoneBridge.SetTextControl = SetMeetingStoneTextControl
MeetingStoneBridge.IsControlParentedTo = IsMeetingStoneControlParentedTo
MeetingStoneBridge.IsFrameVisible = IsMeetingStoneFrameVisible
MeetingStoneBridge.IsNativeEntryCreationVisible = IsMeetingStoneNativeEntryCreationVisible
MeetingStoneBridge.IsNativeOrSystemPanelVisible = IsMeetingStoneNativeOrSystemPanelVisible
MeetingStoneBridge.CloseAssistantForNativePanel = CloseMeetingStoneAssistantForNativePanel
MeetingStoneBridge.RefreshNativeTextControlRouting = RefreshMeetingStoneNativeTextControlRouting
MeetingStoneBridge.QueueNativeTextControlRouting = QueueMeetingStoneNativeTextControlRouting
MeetingStoneBridge.TryLoadQueueStatusFrameUI = TryLoadQueueStatusFrameUI
MeetingStoneBridge.GetQueueStatusButton = GetMeetingStoneQueueStatusButton
MeetingStoneBridge.HideNativeGroupFinderFrames = HideMeetingStoneNativeGroupFinderFrames
MeetingStoneBridge.RouteQueueStatusButtonClick = RouteMeetingStoneQueueStatusButtonClick
MeetingStoneBridge.HookQueueStatusButton = HookMeetingStoneQueueStatusButton
MeetingStoneBridge.QueueQueueStatusRoutingRefresh = QueueMeetingStoneQueueStatusRoutingRefresh
MeetingStoneBridge.HookLeaderChangePopup = HookMeetingStoneLeaderChangePopup
MeetingStoneBridge.QueueLeaderChangePopupRoutingRefresh = QueueMeetingStoneLeaderChangePopupRoutingRefresh
