local addonTable = select(2, ...)
---@type MKA
local MKA = addonTable.MKA
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_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 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 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._mkaSecretStringCacheRecentPatched then
        return true
    end

    local originalCacheRecent = recent.CacheRecent
    recent._mkaOriginalCacheRecent = 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._mkaSecretStringCacheRecentPatched = 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 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
    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()
    return frame
end

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

    titleBox._mkaMeetingStoneOwner = owner
    titleBox._mkaMeetingStoneTitleRouteEntryCreation = entryCreation
    titleBox:SetScript("OnTextChanged", function(self)
        if _G.InputBoxInstructions_OnTextChanged then
            pcall(_G.InputBoxInstructions_OnTextChanged, self)
        end
        if _G.LFGListEntryCreation_UpdateValidState then
            pcall(_G.LFGListEntryCreation_UpdateValidState, entryCreation)
        end

        local currentOwner = self._mkaMeetingStoneOwner
        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
        currentOwner:SyncMeetingStoneDraftFromWidgets()
        currentOwner:RefreshMeetingStoneActionButtons()
    end)
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 MKA:DetachMeetingStoneNativeInputControls()
    if 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
        return
    end

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

local function HookMeetingStoneNativeSummary(owner, summaryBox)
    if not (summaryBox and summaryBox.HookScript) then
        return
    end

    summaryBox._mkaMeetingStoneOwner = owner
    if summaryBox._mkaMeetingStoneSummaryHooked then
        return
    end

    summaryBox:HookScript("OnTextChanged", function(self)
        local currentOwner = self._mkaMeetingStoneOwner
        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
        currentOwner:SyncMeetingStoneDraftFromWidgets()
    end)
    summaryBox._mkaMeetingStoneSummaryHooked = true
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
    if control and _G.InputBoxInstructions_OnTextChanged then
        pcall(_G.InputBoxInstructions_OnTextChanged, control)
    end
end

local function IsMeetingStoneControlParentedTo(control, parent)
    if not (control and parent and control.GetParent) then
        return false
    end

    local ok, currentParent = pcall(control.GetParent, control)
    return ok and currentParent == 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 IsMeetingStoneNativeControlHeldByVisibleExternalFrame(control, holder)
    if not (control and holder and control.GetParent) then
        return false
    end
    if IsMeetingStoneControlParentedTo(control, holder) then
        return false
    end

    local ok, parent = pcall(control.GetParent, control)
    if not ok or not parent or parent == holder then
        return false
    end
    return IsMeetingStoneFrameVisible(parent)
end

local function IsMeetingStoneNativeInputHeldByVisibleExternalFrame(titleBox, titleHolder, summaryFrame, summaryHolder)
    return IsMeetingStoneNativeControlHeldByVisibleExternalFrame(titleBox, titleHolder)
        or IsMeetingStoneNativeControlHeldByVisibleExternalFrame(summaryFrame, summaryHolder)
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 IsMeetingStoneNativeOrSystemPanelVisible() then
        CloseMeetingStoneAssistantForNativePanel(owner)
        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._mkaMeetingStoneTextRoutingHooked 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._mkaMeetingStoneTextRoutingHooked = 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 MKA: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 MKA: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
        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
        self:DetachMeetingStoneNativeInputControls()
        UseMeetingStoneFallbackInputControls(widgets)
        return false
    end

    if IsMeetingStoneNativeInputHeldByVisibleExternalFrame(titleBox, widgets.meetingStoneTitleHolder, summaryFrame, widgets.meetingStoneSummaryHolder) then
        return false
    end

    HookMeetingStoneNativeEntryCreationVisibility(self, entryCreation)
    ApplyMeetingStoneNativeEntryCreationContext(entryCreation)

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

    if not IsMeetingStoneControlParentedTo(titleBox, widgets.meetingStoneTitleHolder) then
        AttachMeetingStoneNativeFrame(self, "titleBox", titleBox, widgets.meetingStoneTitleHolder)
    end
    if not IsMeetingStoneControlParentedTo(summaryFrame, widgets.meetingStoneSummaryHolder) then
        CaptureMeetingStoneNativeControl(self, "summaryBox", summaryBox)
        AttachMeetingStoneNativeFrame(self, "summaryFrame", summaryFrame, widgets.meetingStoneSummaryHolder)
        ApplyMeetingStoneSummaryTextInsets(summaryBox, summaryFrame)
    end

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

    widgets.meetingStoneTitleBox = titleBox
    widgets.meetingStoneSummaryFrame = summaryFrame
    widgets.meetingStoneSummaryBox = summaryBox
    widgets.meetingStoneUsesNativeTextControls = true
    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 _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
end

local function RouteMeetingStoneQueueStatusButtonClick(owner, mouseButton)
    if mouseButton and mouseButton ~= "LeftButton" then
        return false
    end
    if not (owner and owner.IsMeetingStoneActiveListingManagedByAssistant and owner:IsMeetingStoneActiveListingManagedByAssistant()) 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.mkaMeetingStoneQueueStatusOnClickWrapper then
        return false
    end
    if _G.InCombatLockdown and _G.InCombatLockdown() then
        return false
    end

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

    button.mkaMeetingStoneQueueStatusOnClickWrapper = nil
    button.mkaMeetingStoneQueueStatusOriginalOnClick = nil
    button.mkaMeetingStoneQueueStatusOwner = 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 managedByAssistant = owner.IsMeetingStoneActiveListingManagedByAssistant
        and owner:IsMeetingStoneActiveListingManagedByAssistant()
    if currentOnClick == button.mkaMeetingStoneQueueStatusOnClickWrapper then
        if managedByAssistant then
            button.mkaMeetingStoneQueueStatusOwner = owner
            queueStatusHookedButton = button
            return true
        end
        RestoreMeetingStoneQueueStatusButton(button)
        return false
    end

    if not managedByAssistant then
        return false
    end
    if _G.InCombatLockdown and _G.InCombatLockdown() then
        return false
    end

    local originalOnClick = currentOnClick
    local wrapper
    wrapper = function(clickedButton, mouseButton, ...)
        local currentOwner = clickedButton and clickedButton.mkaMeetingStoneQueueStatusOwner 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.mkaMeetingStoneQueueStatusOnClickWrapper = wrapper
    button.mkaMeetingStoneQueueStatusOriginalOnClick = originalOnClick
    button.mkaMeetingStoneQueueStatusOwner = 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 MKA: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


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
