local addonName, ZLAUTO= ...

local ZL = ZLAUTO.mainFrame
local MyAddon = ZL.MyAddon
ZL.Channel = MyAddon:NewModule('Channel', 'AceEvent-3.0')
local Channel = ZL.Channel

function Channel:OnEnable()
    self.OUR_CHANNELS = {
        ["AutoAuction"] = true,
        -- ["寻求组队"] = true,
    }
    self.joiningIndexs = {}
    self.joining = {}
    self.joined = {}
    self.renames = {}

    self:RegisterEvent('CHAT_MSG_CHANNEL_NOTICE_USER')
    self:RegisterEvent('CHAT_MSG_CHANNEL_NOTICE')
    self:RegisterEvent('CHAT_MSG_CHANNEL')
    self:RegisterEvent('CHANNEL_UI_UPDATE', 'RestoreAll')
    self:RestoreAll()
    self:Join(addonName)

    self.errorBlocker = CreateFrame('Frame')
    self.errorBlocker:RegisterEvent('ADDON_ACTION_BLOCKED')
    self.errorBlocker:SetScript('OnEvent', function(self, ...)
        self.ok = nil
    end)
    self.errorBlocker.Start = function(self)
        self.ok = true
        self.frames = {GetFramesRegisteredForEvent('ADDON_ACTION_BLOCKED')}
        for _, frame in ipairs(self.frames) do
            if frame ~= self then
                frame:UnregisterEvent('ADDON_ACTION_BLOCKED')
            end
        end
    end
    self.errorBlocker.End = function(self)
        for _, frame in ipairs(self.frames) do
            frame:RegisterEvent('ADDON_ACTION_BLOCKED')
        end
    end
    self.errorBlocker.IsOk = function(self)
        return self.ok
    end

    local serverChannels = {}
    local function IsServerChannel(channel)
        return serverChannels[channel]
    end

    hooksecurefunc('ChatConfig_UpdateCheckboxes', function(frame)
        if not frame.checkBoxTable or not frame.checkBoxTable[1] or not frame.checkBoxTable[1].channelID then
            return
        end
        local checkBoxName = frame:GetName() .. 'Checkbox'
        for i, value in ipairs(frame.checkBoxTable) do
            if value.channelName then
                local checkBox = _G[checkBoxName .. i .. 'Check']
                local checkBoxText = _G[checkBoxName .. i .. "CheckText"]
                if checkBox and self:IsOurChannel(value.channelName) and not IsServerChannel(value.channelName) then
                    if checkBox:GetChecked() then
                        checkBox:Click()
                    end
                    checkBox:Disable()
                    if _G[checkBoxName .. i].CloseChannel then
                        _G[checkBoxName .. i].CloseChannel:Disable()
                    end
                    if checkBoxText then
                        local text = type(value.text) == "function" and value.text() or value.text
                        checkBoxText:SetText(DISABLED_FONT_COLOR:WrapTextInColorCode(text))
                    end
                end
            end
        end
    end)

    hooksecurefunc(ChannelFrame.ChannelList, 'AddChannelButtonInternal', function(f, button, _, name, _, channelId)
        if self:IsOurChannel(name) and not IsServerChannel(name) then
            button:Disable()
            local text = ('%s %s %s'):format(button:GetChannelNumberText(), button:GetChannelName(),
                                             button:GetMemberCountText())
            button.Text:SetText(DISABLED_FONT_COLOR:WrapTextInColorCode(text))
        end
    end)

    local function RefreshServerChannels()
        for i, v in ipairs {EnumerateServerChannels()} do
            serverChannels[v] = true
        end
    end

    ChatConfigFrame:HookScript('OnShow', RefreshServerChannels)
    ChannelFrame:HookScript('OnShow', RefreshServerChannels)
    C_Timer.NewTicker(0.1, function()
        Channel.errorBlocker:Start()
        pcall(Channel.SendVersion)
        Channel.errorBlocker:Start()
    end)
end

function Channel:RestoreAll(event)
    for channelName in pairs(self.OUR_CHANNELS) do
        self:RestoreChannel(channelName)
    end
    if event then
        self:UnregisterEvent(event)
    end
end

function Channel:RestoreChannel(channelName)
    local id = GetChannelName(channelName)
    if id and id > 0 then
        self:BindChannel(channelName, channelName)
        return true
    end

    local channels = {GetChannelList()}
    for i = 1, #channels, 3 do
        local name = channels[i + 1]
        local prefix, index = name:match('^(.+)(%d+)$')
        if prefix == channelName then
            self:BindChannel(channelName, name)
            return true
        end
    end
end

function Channel:BindChannel(channelName, realChannelName)
    self.joined[channelName] = realChannelName
    self.renames[realChannelName] = channelName
end

function Channel:UnbindChannel(channelName)
    local realChannelName = self.joined[channelName]
    if realChannelName then
        self.joined[channelName] = nil
        self.renames[realChannelName] = nil
    end
end

function Channel:CHAT_MSG_CHANNEL_NOTICE_USER(_, msg, _, _, _, _, _, _, _, realChannelName)
    if msg == 'INVALID_NAME' then
        local channelName, index = self:MatchJoiningChannel(realChannelName)
        if channelName then
            if self.joiningIndexs[channelName] == index then
                self:Join(channelName)
            end
        end
    end
end

function Channel:CHAT_MSG_CHANNEL_NOTICE(_, msg, _, _, _, _, _, _, _, realChannelName)
    if msg == 'YOU_CHANGED' then
        local channelName = self:MatchJoiningChannel(realChannelName)
        if channelName then
            self.joiningIndexs[channelName] = nil
            self.joining[channelName] = nil
            self:BindChannel(channelName, realChannelName)
        end
    elseif msg == 'YOU_LEFT' then
        local channelName = self:GetUsChannelName(realChannelName)
        if channelName then
            self:UnbindChannel(channelName)
        end
    end
end

local function UpdateCheckNotice()
    if ZL.updateCheckNoticed == nil then
        ZL.Print("有新的版本，请及时到各大插件平台更新。", true)
        ZL.updateCheckNoticed = true
    end
end

function Channel:CHAT_MSG_CHANNEL(_, text, unitName, _, _, _, _, _, _, channelName, _, _, guid)
    local baseChannelName = channelName:match('^([^ -]+)')
    if baseChannelName then
        channelName = baseChannelName
    end
    channelName = self:GetUsChannelName(channelName) or channelName
    if self:IsOurChannel(channelName) then
        local textList = strsplittable("§", text)
        -- 移除空字符串
        tDeleteItem(textList, "")
        if #textList > 1 and textList[1] == addonName then
            unitName = unitName:match("^([^-]+)")
            if textList[2] then --版本检测
                if guid ~= UnitGUID("player") then
                    local senderVerA, senderVerB, senderVerC = textList[2]:match("^V(%d+)%.(%d+)%.(%d+)")
                    senderVerA = tonumber(senderVerA) or 0
                    senderVerB = tonumber(senderVerB) or 0
                    senderVerC = tonumber(senderVerC) or 0
                    if senderVerA > ZL.addonVersionA then
                        UpdateCheckNotice()
                    elseif senderVerA == ZL.addonVersionA then
                        if senderVerB > ZL.addonVersionB then
                            UpdateCheckNotice()
                        elseif senderVerB == ZL.addonVersionB then
                            if senderVerC > ZL.addonVersionC then
                                UpdateCheckNotice()
                            end
                        end
                    end
                end
            end
        end
    end
end

function Channel:MatchJoiningChannel(realChannelName)
    for k, v in pairs(self.joiningIndexs) do
        if k == realChannelName then
            return k, v
        elseif (k .. v) == realChannelName then
            return k, v
        end
    end
end

function Channel:Join(channelName)
    if self.joined[channelName] then
        return
    end
    if self:RestoreChannel(channelName) then
        return
    end

    if self.joining[channelName] then
        return
    end

    local index = self.joiningIndexs[channelName] or -1
    index = index + 1
    self.joiningIndexs[channelName] = index
    local joinName = channelName
    if index > 0 then
        joinName = joinName .. index
    end

    self.joining[joinName] = true
    JoinTemporaryChannel(joinName)
end

function Channel:Leave(channelName)
    local realChannelName = self.joined[channelName]
    if realChannelName then
        LeaveChannelByName(realChannelName)
        self:UnbindChannel(channelName)
    end
end

function Channel:GetUsChannelName(realChannelName)
    return self.renames[realChannelName]
end

function Channel:GetRealChannelName(channelName)
    return self.joined[channelName]
end

function Channel:GetSendChannelId(channelName)
    channelName = self.joined[channelName]
    if not channelName then
        return
    end
    local id = GetChannelName(channelName)
    if not id or id == 0 then
        return
    end
    return id
end

function Channel:IsOurChannel(name)
    if self.OUR_CHANNELS[name] then
        return true
    end
    return self.OUR_CHANNELS[self:GetUsChannelName(name)]
end

function Channel:GetChannelID(channelName)
    local channelID = GetChannelName(channelName)
    if not channelID or channelID == 0 then
        self:Join(channelName)
        channelID = GetChannelName(channelName)
    end
    if channelID and channelID ~= 0 then
        return channelID
    end
end

function Channel:SendVersion(channelName)
    channelName = channelName or addonName
    local channelID = Channel:GetChannelID(channelName)
    if channelID and (not UnitIsAFK('player')) then
        -- Channel.errorBlocker:Start()
        pcall(SendChatMessage, "AutoAuction§" .. ZL.addonVersion, 'CHANNEL', nil, channelID)
        -- Channel.errorBlocker:End()
        channelID = nil
    end
end

