-- ======================================================
-- BlackBox Addon: Sync.lua (Rewritten for sanity)
-- Purpose: Auto-sync shared flight path pins with debug toggle
-- ======================================================

local function IsInInstanceGroup()
    return IsInGroup(LE_PARTY_CATEGORY_INSTANCE)
end


local addonPrefix = "BB_SYNC"
C_ChatInfo.RegisterAddonMessagePrefix(addonPrefix)

local function NormalizeZone(zone)
    return zone and zone:gsub("^%s*(.-)%s*$", "%1") or "Unknown"
end

local function ZonesEqual(a, b)
    return NormalizeZone(a):lower() == NormalizeZone(b):lower()
end

local function pinExists(zone, x, y)
    zone = NormalizeZone(zone)
    for _, entry in ipairs(BlackBoxFlightLogDB or {}) do
        if ZonesEqual(entry.zone, zone) and math.abs(entry.x - x) < 0.05 and math.abs(entry.y - y) < 0.05 then
            return true
        end
    end
    return false
end

local function DebugPrint(...)
    if BlackBoxDB and BlackBoxDB.settings and BlackBoxDB.settings.debugMode then
        print("[BlackBox-DEBUG]:", ...)
    end
end

function BlackBox.Sync_BroadcastAllZones()
    if not IsInGroup() then return end
    if IsInInstanceGroup() then
        DebugPrint("Broadcast aborted: Player is in an instance group.")
        return
    end
    if not BlackBoxFlightLogDB then return end

    local allPins = {}
    for _, entry in ipairs(BlackBoxFlightLogDB) do
        local zone = NormalizeZone(entry.zone)
        local pinType
        if entry.eventType == "crate" then
            pinType = "CRATE"
        elseif entry.eventType == "war_supply_crate" then
            pinType = "WAR_SUPPLY_CRATE"
        else
            pinType = "PIN"
        end
        table.insert(allPins, string.format("%.2f,%.2f,%s,%s", entry.x, entry.y, zone, pinType))
    end

    if #allPins == 0 then
        DebugPrint("No pins to broadcast.")
        return
    end

    local MAX_LENGTH = 240
    local chunks = {}
    local current = "ALL_ZONES;"
    for _, pin in ipairs(allPins) do
        local test = current .. (current:sub(-1) == ";" and "" or ";") .. pin
        if #test > MAX_LENGTH then
            table.insert(chunks, current)
            current = "ALL_ZONES;" .. pin
        else
            current = test
        end
    end
    table.insert(chunks, current)

    DebugPrint(string.format("Broadcasting %d pins in %d chunks", #allPins, #chunks))

    for i, chunk in ipairs(chunks) do
        local delay = (i - 1) * 0.1
        C_Timer.After(delay, function()
            if IsInGroup() and not IsInInstanceGroup() and BlackBoxDB.settings.syncGroup then
                local function GetGroupChannel()
                    if IsInRaid() then
                        return "RAID"
                    elseif IsInGroup() then  -- removed instance group branch
                        return "PARTY"
                    end
                    return nil
                end
                
                local channel = GetGroupChannel()
                                DebugPrint(string.format("Sending chunk %d/%d to %s", i, #chunks, channel))
                C_ChatInfo.SendAddonMessage(addonPrefix, chunk, channel)
            end
            if IsInGuild() and BlackBoxDB.settings.syncGuild then
                DebugPrint(string.format("Sending chunk %d/%d to GUILD", i, #chunks))
                C_ChatInfo.SendAddonMessage(addonPrefix, chunk, "GUILD")
            end
        end)
    end
end

function BlackBox.Sync_SendPinsForZone(zone)
    if not IsInGroup() then return end
    if IsInInstanceGroup() then
        DebugPrint("SendPinsForZone aborted: Player is in an instance group.")
        return
    end
    zone = NormalizeZone(zone)
    if not zone or not BlackBoxFlightLogDB then return end

    local pins = {}
    for _, entry in ipairs(BlackBoxFlightLogDB) do
        if ZonesEqual(entry.zone, zone) then
            table.insert(pins, string.format("%.1f,%.1f", entry.x, entry.y))
        end
    end

    if #pins == 0 then
        DebugPrint(string.format("No matching pins for zone '%s' in DB", zone))
        return
    end

    local msg = zone .. ";" .. table.concat(pins, ";")

    if IsInGroup() and not IsInInstanceGroup() and BlackBoxDB.settings.syncGroup then
        local function GetGroupChannel()
            if IsInRaid() then
                return "RAID"
            elseif IsInGroup() then  -- removed instance group branch
                return "PARTY"
            end
            return nil
        end
    
        local channel = GetGroupChannel()
    
        DebugPrint(string.format("Sending %d pins for '%s' to %s", #pins, zone, channel))
        C_ChatInfo.SendAddonMessage(addonPrefix, msg, channel)
    end

    if IsInGuild() and BlackBoxDB.settings.syncGuild then
        DebugPrint(string.format("Sending %d pins for '%s' to GUILD", #pins, zone))
        C_ChatInfo.SendAddonMessage(addonPrefix, msg, "GUILD")
    end
end

function BlackBox.Sync_HandleIncomingPins(message, sender, channel)
    if sender == UnitName("player") then return end
    if channel == "GUILD" and not BlackBoxDB.settings.syncGuild then return end
    if (channel == "PARTY" or channel == "RAID") and not BlackBoxDB.settings.syncGroup then return end

    local added = 0
    local defaultColor = { r = 0, g = 1, b = 0, a = 1 } -- Default green color

    if message:sub(1, 10) == "ALL_ZONES;" then
        local data = message:sub(11)
        for entry in data:gmatch("([^;]+)") do
            local x, y, zone, pinType = entry:match("([%d%.]+),([%d%.]+),([^,]+),(.+)")
            x, y = tonumber(x), tonumber(y)
            zone = NormalizeZone(zone)

            if x and y and zone and not pinExists(zone, x, y) then
                local color = pinType:lower() == "war_supply_crate" and { r = 1, g = 0, b = 0, a = 1 } or defaultColor
                table.insert(BlackBoxFlightLogDB, {
                    zone = zone,
                    x = x,
                    y = y,
                    eventType = pinType:lower() == "war_supply_crate" and "war_supply_crate" or pinType:lower(),
                    message = string.format("Flying Machine %s %.2f %.2f", zone, x, y),
                    time = time(),
                    color = color
                })
                added = added + 1
            end
        end
    else
        local zone, coords = message:match("^([^;]+);(.+)$")
        zone = NormalizeZone(zone)

        if zone and coords then
            for pair in coords:gmatch("([^;]+)") do
                local x, y = pair:match("([%d%.]+),([%d%.]+)")
                x, y = tonumber(x), tonumber(y)

                if x and y and not pinExists(zone, x, y) then
                    local color = defaultColor
                    table.insert(BlackBoxFlightLogDB, {
                        zone = zone,
                        x = x,
                        y = y,
                        message = string.format("Flying Machine %s %.2f %.2f", zone, x, y),
                        time = time(),
                        color = color
                    })
                    added = added + 1
                end
            end
        end
    end

    if added > 0 then
        DebugPrint(string.format("|cff00ff00[BlackBox]:|r Synced %d pins from %s", added, sender))
        BlackBox.UpdateFlightLogUI()
        BlackBox.PlotMarkersForZone(BlackBox.currentZone)
    end
end

local syncListener = CreateFrame("Frame")
syncListener:RegisterEvent("CHAT_MSG_ADDON")
syncListener:RegisterEvent("ADDON_LOADED")
syncListener:RegisterEvent("PLAYER_ENTERING_WORLD")

syncListener:SetScript("OnEvent", function(_, event, prefix, message, channel, sender)
    if event == "CHAT_MSG_ADDON" and prefix == addonPrefix then
        if IsInInstanceGroup() then
            DebugPrint("Incoming message ignored: Player is in an instance group.")
            return
        end
        DebugPrint(string.format("Got message: '%s' from %s on %s", message, sender, channel))
        if message == "SYNC_REQUEST" then
            BlackBox.Sync_BroadcastAllZones()
        elseif message:sub(1, 8) == "REQUEST:" then
            local requestedZone = message:sub(9)
            BlackBox.Sync_SendPinsForZone(requestedZone)
        else
            BlackBox.Sync_HandleIncomingPins(message, sender, channel)
        end
    elseif event == "ADDON_LOADED" then
        BlackBoxDB = BlackBoxDB or {}
        BlackBoxDB.settings = BlackBoxDB.settings or {}
        if BlackBoxDB.settings.syncGroup == nil then BlackBoxDB.settings.syncGroup = true end
        if BlackBoxDB.settings.syncGuild == nil then BlackBoxDB.settings.syncGuild = true end
        if BlackBoxDB.settings.debugMode == nil then BlackBoxDB.settings.debugMode = false end
    elseif event == "PLAYER_ENTERING_WORLD" then
        if IsInInstanceGroup() then
            DebugPrint("Sync request aborted: Player is in an instance group.")
            return
        end
        C_Timer.After(2, function()
            local channel
            if IsInGroup() and not IsInInstanceGroup() and BlackBoxDB.settings.syncGroup then
                if IsInRaid() then
                    channel = "RAID"
                elseif IsInGroup() then
                    channel = "PARTY"
                end
    
                if channel then
                    C_ChatInfo.SendAddonMessage(addonPrefix, "SYNC_REQUEST", channel)
                end
            end
    
            if IsInGuild() and BlackBoxDB.settings.syncGuild then
                C_ChatInfo.SendAddonMessage(addonPrefix, "SYNC_REQUEST", "GUILD")
            end
        end)
    end
end)

-- =========================================================
-- SYNC CHANNEL TOGGLES UI (MapOverview Header)
-- =========================================================

function BlackBox.CreateSyncToggles()
    if not BlackBox.MapOverviewFrame then return end

    -- Try both methods of accessing the header frame
    local header = BlackBox.MapOverviewFrame.headerFrame or BlackBox.MapOverviewFrame:GetChildren()
    if not header or header._syncTogglesCreated then return end

    local function CreateSyncCheckbox(label, offsetX, settingKey)
        local cb = CreateFrame("CheckButton", "BB_SyncToggle_" .. settingKey, header, "UICheckButtonTemplate")
        cb:SetPoint("TOPLEFT", header, "TOPLEFT", offsetX - 190, 5)

        cb.text = cb:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        cb.text:SetPoint("LEFT", cb, "RIGHT", -2, 0)
        cb.text:SetText(label)

        if BlackBoxDB.settings[settingKey] == nil then
            BlackBoxDB.settings[settingKey] = true
        end

        cb:SetChecked(BlackBoxDB.settings[settingKey])
        cb:SetScript("OnClick", function(self)
            local newState = self:GetChecked()
            BlackBoxDB.settings[settingKey] = newState
            print(string.format("|cff00ff00[BlackBox]:|r Sync %s set to %s", label, tostring(newState)))
        end)
    end

    CreateSyncCheckbox("Group", 8, "syncGroup")
    CreateSyncCheckbox("Guild", 80, "syncGuild")
    header._syncTogglesCreated = true
end

-- Try to create immediately after login
local function TryCreateTogglesImmediately()
    if BlackBox.MapOverviewFrame then
        BlackBox.CreateSyncToggles()
    else
        -- Keep checking every 0.1s until the frame exists
        local ticker
        ticker = C_Timer.NewTicker(0., function()
            if BlackBox.MapOverviewFrame then
                BlackBox.CreateSyncToggles()
                ticker:Cancel()
            end
        end)
    end
end

-- Hook addon load and call the frame check
local initTogglesFrame = CreateFrame("Frame")
initTogglesFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
initTogglesFrame:SetScript("OnEvent", function()
    TryCreateTogglesImmediately()
end)

-- Just in case UpdateMapOverview is called later
hooksecurefunc(BlackBox, "UpdateMapOverview", function()
    BlackBox.CreateSyncToggles()
end)
