-- ======================================================
-- BlackBox Addon: Predict Crate Drop Location
-- Version: 1.1 (Merged with prediction code, options panel,
--          War Supply Crate detection, and minimap icon)
-- ======================================================

--------------------------------------------
-- 0) GLOBAL INITIALIZATION
--------------------------------------------
if not _G["BlackBox"] then
    _G["BlackBox"] = {}
end
local BlackBox = _G["BlackBox"]

-- Flight log saved variable initialization
BlackBoxFlightLogDB = BlackBoxFlightLogDB or {}

--------------------------------------------
-- 1) CONFIGURABLE SETTINGS
--------------------------------------------
local PROJECTION_DISTANCE = 40      -- How far (in units) to project from the current waypoint
local DEFAULT_ANGLE_DEGREE = 45       -- Default projection angle in degrees
local DEBUG_MODE = false            -- Set to true to print debug messages

local DEFAULT_ANGLE = math.rad(DEFAULT_ANGLE_DEGREE)

-- Ensure our database exists and load any saved settings.
BlackBoxDB = BlackBoxDB or {}
if BlackBoxDB.settings then
    PROJECTION_DISTANCE = BlackBoxDB.settings.projectionDistance or PROJECTION_DISTANCE
    DEFAULT_ANGLE_DEGREE = BlackBoxDB.settings.defaultAngle or DEFAULT_ANGLE_DEGREE
    DEBUG_MODE = BlackBoxDB.settings.debugMode or DEBUG_MODE
    DEFAULT_ANGLE = math.rad(DEFAULT_ANGLE_DEGREE)
else
    BlackBoxDB.settings = {}
end

-- Simple debug print helper.
local function DebugPrint(...)
    if BlackBoxDB.settings.debugMode then
        --Print("DEBUG:", ...)
    end
end

--------------------------------------------
-- 2) BLACKBOX DROP SPOT DATABASE
--------------------------------------------
-- Overwrite (or define) dropSpots as a table with predefined coordinates.
BlackBoxDB.dropSpots = {
    ["The Ringing Deeps"] = {
        {x=40.4, y=31.7},
        {x=46.5, y=41.7}, {x=51.2, y=41.4}, {x=48.7, y=54.3}, {x=50.6, y=67.0},
        {x=55.69, y=68.0}, {x=58.6, y=36.4}, {x=62.87, y=42.04},
    },
    ["Siren Isle"] = {
        {x=39.9, y=51.3}, {x=42.4, y=69.2}, {x=52.3, y=70.7},
    },
    ["Azj%-Kahet"] = {
        {x=54.7, y=53.9}, {x=62.7, y=66.5}, {x=62.8, y=66.3}, {x=68.7, y=55.2},
        {x=72.7, y=42.9}, {x=76.6, y=76.6}, {x=39.4, y=58.6}, {x=39.5, y=58.6},
        {x=45.2, y=72.3}, {x=45.5, y=72.6},
    },
    ["Isle of Dorn"] = {
        {x=29.1, y=61.8}, {x=38.6, y=78.2}, {x=40.1, y=61.5}, {x=40.2, y=61.4},
        {x=56.1, y=30.4}, {x=57.7, y=41.9}, {x=59.9, y=71.0}, {x=64.6, y=23.1},
        {x=74.7, y=57.8}, {x=79.1, y=46.8},
    },
    ["Hallowfall"] = {
        {x=26.1, y=53.1}, {x=35.9, y=45.8}, {x=38.4, y=54.7}, {x=38.6, y=54.7},
        {x=40.7, y=34.7}, {x=46.4, y=62.4}, {x=46.4, y=62.5}, {x=46.5, y=62.4},
        {x=46.5, y=62.6}, {x=54.3, y=31.4}, {x=54.4, y=31.5}, {x=54.5, y=31.4},
        {x=58.1, y=58.9}, {x=59.3, y=46.3}, {x=59.4, y=46.5}, {x=59.5, y=46.3},
        {x=63.1, y=63.7},
    },
    ["Undermine"] = {
        {x=33.4, y=67.4}, {x=33.4, y=67.5}, {x=33.5, y=67.4}, {x=33.6, y=67.5},
        {x=35.8, y=19.9}, {x=46.6, y=63.7}, {x=50.4, y=14.9}, {x=50.4, y=15.5},
        {x=50.4, y=85.4}, {x=50.4, y=85.5}, {x=50.6, y=14.9}, {x=50.6, y=15.5},
        {x=50.7, y=85.3}, {x=50.8, y=85.5}, {x=51.9, y=48.9}, {x=52.1, y=48.4},
        {x=63.2, y=32.7}, {x=63.2, y=79.6}, {x=63.3, y=79.1}, {x=63.5, y=32.7},
        {x=63.5, y=79.5}, {x=68.9, y=61.4},
    },
    ["Voidstorm"] = {
    },
    ["Eversong Woods"] = {
    },
    ["Harandar"] = {
    },
    ["Isle of Quel'Danas"] = {
    },
    ["Zul'Aman"] = {
    },
}

--------------------------------------------
-- 2A) ZONE ABBREVIATIONS LOOKUP TABLE
--------------------------------------------
BlackBoxDB.zoneAbbreviations = {
    rd = "The Ringing Deeps",   -- RD: The Ringing Deeps
    ak = "Azj%-Kahet",           -- AK: Azj%-Kahet
    si = "Siren Isle",           -- SI: Siren Isle
    id = "Isle of Dorn",         -- ID: Isle of Dorn
    hf = "Hallowfall",           -- HF: Hallowfall
    ud = "Undermine",            -- UD: Undermine
    vs = "Voidstorm",             -- VS: Voidstorm
    ew = "Eversong Woods",        -- EW: Eversong Woods
    ha = "Harandar",              -- HA: Harandar
    iq = "Isle of Quel'Danas",    -- IQ: Isle of Quel'Danas
    za = "Zul'Aman"               -- ZA: Zul'Aman
}

--------------------------------------------
-- 3) BLACKBOX PREDICTION LOGIC (FIRING ON MAP PIN)
--------------------------------------------
-- This frame listens for chat events (or other events) and checks the user waypoint.
--[[local predictionFrame = CreateFrame("Frame")
predictionFrame:RegisterEvent("CHAT_MSG_SAY")
predictionFrame:RegisterEvent("CHAT_MSG_YELL")
predictionFrame:RegisterEvent("CHAT_MSG_RAID_WARNING")
predictionFrame:RegisterEvent("CHAT_MSG_RAID_LEADER")
predictionFrame:RegisterEvent("CHAT_MSG_PARTY")
predictionFrame:RegisterEvent("CHAT_MSG_PARTY_LEADER")

predictionFrame:SetScript("OnEvent", function(self, event, msg, sender, ...)
    DebugPrint("predictionFrame triggered:", event)
    
    -- Filter out non-relevant messages
    local lowerMsg = string.lower(msg)
    if lowerMsg:find("opportunity's knocking") or 
       lowerMsg:find("i see some valuable resources") or 
       lowerMsg:find("treasure nearby") or 
       lowerMsg:find("cache of resources nearby") then
        DebugPrint("Message filtered out.")
        return 
    end

    -- Get the current waypoint pin from the map.
    local pin = C_Map.GetUserWaypoint()
    if not pin or not pin.position then 
        DebugPrint("No valid waypoint found.")
        return 
    end

    local mapID = pin.uiMapID
    local pinPos = pin.position
    if not mapID or not pinPos then 
        DebugPrint("Missing mapID or pin position.")
        return 
    end

    -- Convert normalized coordinates to percentages.
    local px, py = pinPos.x * 100, pinPos.y * 100
    DebugPrint("User waypoint:", px, py)
    local startPoint = { x = px, y = py }
    
    -- Calculate a projection from the waypoint using the default angle.
    local endPoint = {
        x = startPoint.x + math.cos(DEFAULT_ANGLE) * PROJECTION_DISTANCE,
        y = startPoint.y + math.sin(DEFAULT_ANGLE) * PROJECTION_DISTANCE
    }
    DebugPrint("Projected endpoint:", endPoint.x, endPoint.y)

    -- Get the current zone name from the map.
    local mapInfo = C_Map.GetMapInfo(mapID)
    if not mapInfo or not mapInfo.name then
        DebugPrint("Unable to determine zone from mapID.")
        return 
    end
    local currentZoneName = mapInfo.name
    DebugPrint("Current zone:", currentZoneName)

    -- Helper functions: get angle and difference.
    local function getAngle(a, b)
        local angle = math.atan2(b.y - a.y, b.x - a.x)
        DebugPrint("Angle between", a.x, a.y, "and", b.x, b.y, "=", angle)
        return angle
    end
    local function angleDiff(a1, a2)
        local diff = math.abs(a1 - a2)
        local ret = math.min(diff, 2 * math.pi - diff)
        DebugPrint("Angle diff:", ret)
        return ret
    end

    local heading = getAngle(startPoint, endPoint)
    DebugPrint("Heading from waypoint:", heading)

    BlackBoxDB.zoneAbbreviations = BlackBoxDB.zoneAbbreviations or {
        rd = "The Ringing Deeps",
        ak = "Azj%-Kahet",
        si = "Siren Isle",
        id = "Isle of Dorn",
        hf = "Hallowfall",
        ud = "Undermine"
    }
    -- Check if the current zone is one of our valid zones.
    local validZones = {}
    for _, fullName in pairs(BlackBoxDB.zoneAbbreviations) do
        validZones[fullName] = true
    end

    local bestMatch, smallestDiff
    if validZones[currentZoneName] then
        -- Look for the drop spot (from our predefined table) whose direction best matches our heading.
        for zoneKey, drops in pairs(BlackBoxDB.dropSpots) do
            if zoneKey == currentZoneName then
                for _, drop in ipairs(drops) do
                    local dropAngle = getAngle(startPoint, drop)
                    local diff = angleDiff(heading, dropAngle)
                    DebugPrint("Zone", zoneKey, "drop at", drop.x, drop.y, "diff =", diff)
                    if not smallestDiff or diff < smallestDiff then
                        smallestDiff = diff
                        bestMatch = { zone = zoneKey, coords = drop }
                    end
                end
            end
        end
    else
        DebugPrint("Current zone", currentZoneName, "is not recognized.")
    end

    if bestMatch then
        -- Format the zone abbreviation (e.g., "RD" for The Ringing Deeps)
        local zoneFullName = bestMatch.zone
        local zoneAbbr = zoneFullName
        for abbr, fullName in pairs(BlackBoxDB.zoneAbbreviations) do
            if fullName == zoneFullName then
                zoneAbbr = string.upper(abbr)
                break
            end
        end

        local x = string.format("%.1f", bestMatch.coords.x)
        local y = string.format("%.1f", bestMatch.coords.y)
        local message = "Crate Landing in (" .. zoneAbbr .. ") (" .. x .. ", " .. y .. ")"
        DebugPrint(message)

        -- Optionally, update the addon’s map overview to plot the pin.
        BlackBox.currentZone = zoneFullName
        BlackBox.currentDrop = bestMatch.coords  -- Save the drop coordinates
        if BlackBox.UpdateMapOverview then
            BlackBox.UpdateMapOverview(zoneFullName)
        end

        -- Delay sending or logging the chat message by a few seconds.
        local delay = 3
        C_Timer.After(delay, function()
            if BlackBoxDB.settings.sendChatMessage then
                if IsInRaid() then
                    SendChatMessage(message, "RAID")
                elseif IsInGroup() then
                    SendChatMessage(message, "PARTY")
                else
                    DebugPrint(message)
                end
            else
                DebugPrint("Chat messaging is disabled.")
            end
        end)
    else
        DebugPrint("No matching drop spot found for zone", currentZoneName)
    end
end) ]]

--[[ 
  Note: The above prediction logic will fire when one of the registered chat events occurs.
  It obtains the user's current map waypoint, calculates a projected endpoint using DEFAULT_ANGLE,
  compares that with the predefined drop spots for the current zone, logs the result, sends a chat
  message (if enabled), and calls BlackBox.UpdateMapOverview so that the addon’s map window can update
  to display the current zone and the predicted drop coordinates.
  
  To complete the integration, ensure your Map Overview window code (sections 7 and 8 in your addon)
  uses BlackBox.currentZone and/or BlackBox.currentDrop to mark the location on the displayed map.
]]


--------------------------------------------
-- 4) SETTINGS PANEL (Dragonflight-Compatible)
--------------------------------------------
local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", function(self, event, addonName)
    if addonName == "BlackBox" then
        DebugPrint("ADDON_LOADED event received for addon:", addonName)
        BlackBoxDB = BlackBoxDB or {}
        BlackBoxDB.settings = BlackBoxDB.settings or {}
        local db = BlackBoxDB.settings

        local function DebugPrintSettings(...)
            if db.debugMode then
                print("|cff00ff00[BlackBox DEBUG]:|r", ...)
            end
        end

        C_Timer.After(1, function()
            if db.debugMode then
                print("|cff00ff00[BlackBox]:|r Debug mode set to true")
            end
        end)

        local originalSendChatMessage = SendChatMessage
        SendChatMessage = function(msg, chatType, language, target, ...)
            if BlackBoxDB.settings and not BlackBoxDB.settings.sendChatMessage then
                DebugPrint("Blocking message due to Send Chat Message being disabled")
                return
            end
            originalSendChatMessage(msg, chatType, language, target, ...)
        end

        local function configureSettings()
            local category = Settings.RegisterVerticalLayoutCategory("War Supply Crates")
            BlackBox.category = category
            BlackBox.settingsCategoryID = category:GetID()
            
            -------------------------------
            -- Debug Mode Checkbox
            -------------------------------
            do
                local var = "debugMode"
                local name = "Enable Debug Mode"
                local tooltip = "Print extra debug output to the chat window"
                local default = false

                if db[var] == nil then
                    db[var] = default
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    DebugPrintSettings("Debug mode set to", val)
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Debug Mode Checkbox")
            end

            -------------------------------
            -- Toggle Minimap Icon
            -------------------------------
            do
                local var = "minimapIconVisible"
                local name = "Show Minimap Icon"
                local tooltip = "Toggle the visibility of the minimap icon"
                local default = true

                if db[var] == nil then
                    db[var] = default
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    BlackBoxDB.minimapIcon = BlackBoxDB.minimapIcon or { hide = false, minimapPos = 225 }
                    if val then
                        print("|cff00ff00[BlackBox]:|r Minimap icon will be displayed")
                        BlackBoxDB.minimapIcon.hide = false
                        if LDBIcon then
                            LDBIcon:Show("BlackBox")
                        end
                    else
                        print("|cff00ff00[BlackBox]:|r Minimap icon will be hidden")
                        BlackBoxDB.minimapIcon.hide = true
                        if LDBIcon then
                            LDBIcon:Hide("BlackBox")
                        end
                    end
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Minimap Icon Toggle Checkbox")
            end

            -------------------------------
            -- Send Chat Message Toggle
            -------------------------------
            do
                local var = "sendChatMessage"
                local name = "Send Chat Message"
                local tooltip = "Toggle whether chat messages are sent to the group or raid"
                local default = true

                if db[var] == nil then
                    db[var] = default
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    DebugPrintSettings("Send Chat Message set to", val)
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Send Chat Message Toggle Checkbox")
            end

            -------------------------------
            -- Announce Flying Machine On Mouseover
            -------------------------------
            do
                local var = "announceFlyingMachine"
                local name = "Announce Flying Machine On Mouseover"
                local tooltip = "Toggle whether to announce Flying Machine coordinates on mouseover"
                local default = true

                if db[var] == nil then
                    db[var] = default
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    DebugPrintSettings("Announce Flying Machine On Mouseover set to", val)
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Announce Flying Machine On Mouseover Checkbox")
            end

            -------------------------------
            -- Only Captere Flying Machine Messages
            -------------------------------
            do
                local var = "onlyFlyingMachineLog"
                local name = "Only Capture Flying Machine Messages"
                local tooltip = "Toggle whether the flight log only captures messages containing 'flying maching'"
                local default = true
            
                if db[var] == nil then
                    db[var] = default
                end
            
                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    DebugPrintSettings("Only Capture Flying Machine Messages set to", val)
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Only Capture Flying Machine Messages Toggle Checkbox")
            end

            -------------------------------
            -- Flight Log Toggle
            -------------------------------
            do
                local var = "flightLogEnabled"
                local name = "Flight Log"
                local tooltip = "Toggle the display of the Flight Log window for testing."
                local default = false

                if db[var] == nil then
                    db[var] = default
                    DebugPrintSettings("Flight Log toggle default set to " .. tostring(default))
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    if FlightLogFrame then
                        if val then
                            FlightLogFrame:Show()
                            print("|cff00ff00[BlackBox]:|r Flight Log window enabled.")
                            DebugPrintSettings("FlightLogFrame:Show() called.")
                        else
                            FlightLogFrame:Hide()
                            print("|cff00ff00[BlackBox]:|r Flight Log window disabled.")
                            DebugPrintSettings("FlightLogFrame:Hide() called.")
                        end
                    else
                        print("|cffff0000[BlackBox]:|r FlightLogFrame is not defined!")
                        DebugPrintSettings("FlightLogFrame is nil in Flight Log toggle callback.")
                    end
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Flight Log Toggle Checkbox")
            end

            if db.flightLogEnabled and FlightLogFrame then
                FlightLogFrame:Show()
                DebugPrintSettings("FlightLogFrame:Show() called on reload because flightLogEnabled is true.")
            else
                if FlightLogFrame then FlightLogFrame:Hide() end
            end
            
            if FlightLogFrame and FlightLogFrame:IsShown() then
                C_Timer.After(0.1, function()
                    BlackBox.UpdateFlightLogUI(true)
                end)
            end
            
            -------------------------------
            -- Toggle Map Overview Window
            -------------------------------
            do
                local var = "mapOverviewEnabled"
                local name = "Show Map Overview"
                local tooltip = "Toggle the display of the Map Overview window (full-size map with zone buttons) for data review."
                local default = false
            
                if BlackBoxDB.settings[var] == nil then
                    BlackBoxDB.settings[var] = default
                end
            
                local setting = Settings.RegisterAddOnSetting(BlackBox.category, var, var, BlackBoxDB.settings, "boolean", name, BlackBoxDB.settings[var])
                setting:SetValueChangedCallback(function(_, val)
                    BlackBoxDB.settings[var] = val
                    if val then
                        BlackBox.MapOverviewFrame:Show()
                        BlackBox.UpdateMapOverview(BlackBox.currentZone or "The Ringing Deeps")
                        BlackBox.UpdateMapOverview(BlackBox.currentZone)
                    else
                        BlackBox.MapOverviewFrame:Hide()
                    end
                end)
                Settings.CreateCheckbox(BlackBox.category, setting, tooltip)
            end


            -------------------------------
            -- Shared Pin Color Toggle
            -------------------------------
            do
                local var = "useGreenSharedPins"
                local name = "Use Green for Synced Pins"
                local tooltip = "If enabled, synced pins will be green instead of yellow."
                local default = false

                if db[var] == nil then
                    db[var] = default
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    DebugPrintSettings("useGreenSharedPins set to", val)
                    -- Optionally: refresh map visuals if needed
                    if BlackBox.currentZone then
                        BlackBox.PlotMarkersForZone(BlackBox.currentZone)
                    end
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Shared Pin Color Toggle")
            end

            -------------------------------
            -- Toggle Conquest Icon Visibility
            -------------------------------
            do
                local var = "showConquestIcon"
                local name = "Show Conquest Icon"
                local tooltip = "Toggle the visibility of the conquest icon on the timer frame"
                local default = true

                if db[var] == nil then
                    db[var] = default
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    if BlackBox_ConquestFrame then
                        if val then
                            BlackBox_ConquestFrame:Show()
                        else
                            BlackBox_ConquestFrame:Hide()
                        end
                    end
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Conquest Icon Visibility Toggle Checkbox")
            end

            -------------------------------
            -- Enable Crate Coordinate Print Toggle
            -------------------------------
            do
                local var = "throttleCratePrint"
                local name = "Enable Crate Coordinate Print"
                local tooltip = "If enabled, Next Zone coordinates will print after Looting A Crate. If disabled, nothing will be printed."
                local default = true

                if db[var] == nil then
                    db[var] = default
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    DebugPrintSettings("Enable Crate Coordinate Print set to", val)
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Crate Coordinate Print Toggle")
            end


--[[
            -------------------------------
            -- Predicted Announcements Toggle
            -------------------------------
            do
                local var = "predictedAnnouncements"
                local name = "Enable Predicted Announcements"
                local tooltip = "Toggle whether predicted drop announcements are sent."
                local default = false

                if db[var] == nil then
                    db[var] = default
                end

                local setting = Settings.RegisterAddOnSetting(category, var, var, db, "boolean", name, db[var])
                setting:SetValueChangedCallback(function(_, val)
                    db[var] = val
                    DebugPrintSettings("Predicted Announcements set to", val)
                end)
                Settings.CreateCheckbox(category, setting, tooltip)
                DebugPrintSettings("Created Predicted Announcements Toggle Checkbox")
            end ]]
            

            Settings.RegisterAddOnCategory(category)
        end

        configureSettings()
        self:UnregisterEvent("ADDON_LOADED")
        
    end
end)

--------------------------------------------
-- 5) UNIFIED MOUSEOVER HANDLER (Merged Flying Machine + Crate + Throttling + Settings)
--------------------------------------------
local mouseoverFrame = CreateFrame("Frame")
mouseoverFrame:RegisterEvent("UPDATE_MOUSEOVER_UNIT")

local lastFlyingLogTime = 0
local lastCrateLogTime = 0
local throttleSeconds = 2

mouseoverFrame:SetScript("OnEvent", function()
    if not UnitExists("mouseover") then return end
    local name = UnitName("mouseover")
    if not name then return end

    local mapID = C_Map.GetBestMapForUnit("player")
    if not mapID then return end
    local pos = C_Map.GetPlayerMapPosition(mapID, "player")
    if not pos then return end

    local x, y = pos:GetXY()
    x, y = x * 100, y * 100

    local zoneName = C_Map.GetMapInfo(mapID).name or "Unknown"
    if string.find(zoneName, "City of Threads") then
        zoneName = "Azj-Kahet"
    end

    -- FLYING MACHINE SECTION
    if name:find("Flying Machine") then
        if not BlackBoxDB.settings.announceFlyingMachine then return end
        if GetTime() - lastFlyingLogTime < throttleSeconds then return end
        lastFlyingLogTime = GetTime()
    
        -- Avoid duplicates
        for _, e in ipairs(BlackBoxFlightLogDB) do
            if e.zone == zoneName and math.abs(e.x - x) < 0.1 and math.abs(e.y - y) < 0.1 then
                return
            end
        end
    
        local message = string.format("Flying Machine %s %.1f %.1f", zoneName, x, y)
    
        -- Send addon sync message
        if C_ChatInfo.IsAddonMessagePrefixRegistered("BB_SYNC") then
            local channel = IsInRaid() and "RAID" or (IsInGroup() and "PARTY") or nil
            if channel then
                C_ChatInfo.SendAddonMessage("BB_SYNC", message, channel)
            end
        end
    
        -- Log it
        AddLogEntry(zoneName, x, y, message)
    
        -- Only plot markers if the map is visible
        if MapOverviewFrame and MapOverviewFrame:IsShown() and BlackBox.PlotMarkersForZone then
            BlackBox.PlotMarkersForZone(zoneName)
        end
    end
    




    -- WAR SUPPLY CRATE SECTION
    if name:find("War Supply Crate") then
        if GetTime() - lastCrateLogTime < throttleSeconds then return end
        lastCrateLogTime = GetTime()

        local message = string.format("War Supply Crate %s %.1f %.1f", zoneName, x, y)

        table.insert(BlackBoxFlightLogDB, {
            zone = zoneName,
            x = x,
            y = y,
            message = message,
            time = time(),
            eventType = "crate"
        })

        if C_ChatInfo.IsAddonMessagePrefixRegistered("BB_SYNC") then
            local channel = IsInRaid() and "RAID" or (IsInGroup() and "PARTY") or nil
            if channel then
                C_ChatInfo.SendAddonMessage("BB_SYNC", message, channel)
            end
        end

        if BlackBox.UpdateFlightLogUI then BlackBox.UpdateFlightLogUI() end
        if MapOverviewFrame and MapOverviewFrame:IsShown() then
            if BlackBox.PlotMarkersForZone then
                BlackBox.PlotMarkersForZone(zoneName)
            end
        end
        
    end
end)



--------------------------------------------
-- Saved Variables Initialization
--------------------------------------------
BlackBoxDB = BlackBoxDB or {}
BlackBoxFlightLogDB = BlackBoxFlightLogDB or {}
if not BlackBoxFlightLog_SavedToggles then
    BlackBoxFlightLog_SavedToggles = {
        say = false,       -- Default to off
        general = false,   -- Default to off
        party = true,
        raid = true,
    }
end

--------------------------------------------
-- 6) Flight Log Frame Creation and UI Setup
--------------------------------------------
local flightLogToggles = BlackBoxFlightLog_SavedToggles
-- Set default time format (false = 12-hour; true = 24-hour)
local use24Hour = false

FlightLogFrame = CreateFrame("Frame", "BlackBoxFlightLog", UIParent, "BasicFrameTemplateWithInset")
FlightLogFrame:SetSize(470, 300)  -- Wider frame
FlightLogFrame:SetPoint("CENTER")
FlightLogFrame:SetMovable(true)
FlightLogFrame:EnableMouse(true)
FlightLogFrame:RegisterForDrag("LeftButton")
FlightLogFrame:SetScript("OnDragStart", FlightLogFrame.StartMoving)
FlightLogFrame:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()

    local threshold = 20 -- Minimum visible height in pixels
    local screenWidth = UIParent:GetWidth()
    local screenHeight = UIParent:GetHeight()
    local frameLeft = self:GetLeft()
    local frameBottom = self:GetBottom()
    local frameWidth = self:GetWidth()
    local frameHeight = self:GetHeight()
    local newLeft = frameLeft
    local newBottom = frameBottom

    if frameBottom + frameHeight < threshold then
        newBottom = threshold - frameHeight
    end
    if frameLeft < -435 then
        newLeft = -435
    end
    if frameLeft + frameWidth > screenWidth then
        newLeft = screenWidth - (frameWidth * 0.05)
    end
    if frameBottom + frameHeight > screenHeight then
        newBottom = screenHeight - (frameHeight * 0.035)
    end

    self:ClearAllPoints()
    self:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", newLeft, newBottom)
end)
FlightLogFrame:Hide()  -- Hide by default

-- Function to reposition the frame so that only its top 20 pixels are visible
local function RepositionFrame(frame)
    local headerHeight = 20  -- Height of the header you want to remain visible
    local frameHeight = frame:GetHeight()
    local frameLeft = frame:GetLeft() or 0  -- Retain the current horizontal position

    -- Calculate the new bottom coordinate so that only the header (top 20 pixels) is exposed.
    -- Since the header is at the top of the frame, we set the bottom so that:
    -- (newBottom + frameHeight) == headerHeight
    local newBottom = headerHeight - frameHeight

    frame:ClearAllPoints()
    frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", frameLeft, newBottom)
end

-- Override the CloseButton's OnClick handler to reposition the frame instead of hiding it
FlightLogFrame.CloseButton:SetScript("OnClick", function(self)
    RepositionFrame(self:GetParent())
end)

-- Ensure the frame is set up to receive keyboard events
FlightLogFrame:EnableKeyboard(true)

-- Allow key events to propagate so they aren’t overridden
FlightLogFrame:SetPropagateKeyboardInput(true)

-- Set up an OnKeyDown handler that calls RepositionFrame when Escape is pressed
FlightLogFrame:SetScript("OnKeyDown", function(self, key)
    if key == "ESCAPE" then
        RepositionFrame(self)
    end
end)




-- Title aligned top-left
local FlightLogTitle = FlightLogFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
FlightLogTitle:SetPoint("TOPLEFT", FlightLogFrame, "TOPLEFT", 2, -2)
FlightLogTitle:SetFont("Fonts\\FRIZQT__.TTF", 16, "OUTLINE")
FlightLogTitle:SetText("Black Box")
FlightLogTitle:SetTextColor(1, 1, 1, 1)
FlightLogTitle:SetShadowColor(0, 0, 0, 1)
FlightLogTitle:SetShadowOffset(1, -1)

--------------------------------------------
-- Create Toggle CheckButtons for Channels
--------------------------------------------
local function CreateToggleButton(name, labelText, anchorPoint, relativeTo, relPoint, x, y, tooltipText)
    local btn = CreateFrame("CheckButton", nil, FlightLogFrame, "UICheckButtonTemplate")
    btn:SetPoint(anchorPoint, relativeTo, relPoint, x, y)
    btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    btn.text:SetPoint("LEFT", btn, "RIGHT", 2, 0)
    btn.text:SetText(labelText)
    btn:SetChecked(flightLogToggles[name])
    btn:SetScript("OnClick", function(self)
        flightLogToggles[name] = self:GetChecked()
        DebugPrint("Toggle", labelText, "set to", flightLogToggles[name])
    end)
    btn:SetScript("OnEnter", function()
        GameTooltip:SetOwner(btn, "ANCHOR_RIGHT")
        GameTooltip:SetText(tooltipText, nil, nil, nil, nil, true)
        GameTooltip:Show()
    end)
    btn:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)
    return btn
end

local toggleRaid = CreateToggleButton("raid", "Raid", "TOPRIGHT", FlightLogFrame, "TOPRIGHT", -58, 4, "Toggle sending Announcements to the Raid channel.")
local toggleParty = CreateToggleButton("party", "Party", "TOPRIGHT", FlightLogFrame, "TOPRIGHT", -128, 4, "Toggle sending Announcements to the Party channel.")
local toggleGeneral = CreateToggleButton("general", "General", "TOPRIGHT", FlightLogFrame, "TOPRIGHT", -210, 4, "Toggle sending Announcements to the General channel.")
local toggleSay = CreateToggleButton("say", "Say", "TOPRIGHT", FlightLogFrame, "TOPRIGHT", -268, 4, "Toggle sending Announcements to the Say channel.")

--------------------------------------------
-- Create a Scroll Frame for the Flight Log
--------------------------------------------
local scrollFrame = CreateFrame("ScrollFrame", "FlightLogScrollFrame", FlightLogFrame, "UIPanelScrollFrameTemplate")
scrollFrame:SetPoint("TOPLEFT", FlightLogFrame, "TOPLEFT", 10, -40)
scrollFrame:SetPoint("BOTTOMRIGHT", FlightLogFrame, "BOTTOMRIGHT", -30, 10)

local scrollChild = CreateFrame("Frame", "FlightLogScrollChild", scrollFrame)
scrollChild:SetSize(360, 1)  -- Resize dynamically
scrollFrame:SetScrollChild(scrollChild)

hooksecurefunc(FlightLogFrame, "Show", function()
    C_Timer.After(0.1, function()
        if BlackBox.UpdateFlightLogUI then
            BlackBox.UpdateFlightLogUI(true)
        end
    end)
end)


local flightLogEntries = {}
local lastEntryFrame = nil

--------------------------------------------
-- Helper Function: Create UI Entry for a Log Message
--------------------------------------------
local function CreateCoordinateEntryUI(zoneName, xCoord, yCoord, fullMsg, entryTime)
    local entryFrame = CreateFrame("Frame", nil, scrollChild)
    entryFrame:SetSize(290, 20)
    zoneName = zoneName or "Unknown"
    local timeFormat = use24Hour and "%H:%M:%S" or "%I:%M:%S %p"
    local timeString = date(timeFormat, entryTime)
    local displayText = string.format("[%s] %s", timeString, fullMsg or string.format("%s (%.2f, %.2f)", zoneName, xCoord, yCoord))
    
    local textFS = entryFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    textFS:SetPoint("LEFT", entryFrame, "LEFT", 0, 0)
    textFS:SetText(displayText)
    -- Make the timestamp clickable to toggle the time format.
    textFS:SetScript("OnMouseUp", function(self, button)
        if button == "LeftButton" then
            use24Hour = not use24Hour
            -- Refresh the entire flight log UI to update time format.
            BlackBox.UpdateFlightLogUI()
        end
    end)
    
    local announceButton = CreateFrame("Button", nil, entryFrame, "UIPanelButtonTemplate")
    announceButton:SetSize(70, 18)
    announceButton:SetPoint("LEFT", textFS, "RIGHT", 5, 0)
    announceButton:SetText("Announce")
    announceButton:SetScript("OnClick", function()
        DebugPrint("Announcing coordinates:", displayText)
        if flightLogToggles.say then
            SendChatMessage(displayText, "SAY")
        end
        if flightLogToggles.general then
            local chanNum = GetChannelName("General")
            if chanNum > 0 then
                SendChatMessage(displayText, "CHANNEL", nil, chanNum)
            end
        end
        if flightLogToggles.party then
            SendChatMessage(displayText, "PARTY")
        end
        if flightLogToggles.raid then
            SendChatMessage(displayText, "RAID")
        end
    end)
    
    if lastEntryFrame then
        entryFrame:SetPoint("TOPLEFT", lastEntryFrame, "BOTTOMLEFT", 0, -5)
    else
        entryFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, 0)
    end
    
    lastEntryFrame = entryFrame
    table.insert(flightLogEntries, entryFrame)
    
    local totalHeight = 0
    for _, eFrame in ipairs(flightLogEntries) do
        totalHeight = totalHeight + eFrame:GetHeight() + 5
    end
    scrollChild:SetHeight(totalHeight)
    
    --DebugPrint("Displaying log entry:", zoneName, string.format("(%.2f, %.2f)", xCoord, yCoord))
end

--------------------------------------------
-- Helper Function: Update the Flight Log UI with the Last 50 Entries
--------------------------------------------
BlackBox.UpdateFlightLogUI = function(force)
    local count = #BlackBoxFlightLogDB
    if not force and BlackBox._lastLogCount == count then return end
    BlackBox._lastLogCount = count

    for _, frame in ipairs(flightLogEntries) do
        frame:Hide()
    end
    flightLogEntries = {}
    lastEntryFrame = nil
    scrollChild:SetHeight(1)

    local lastCleared = BlackBoxDB.settings.lastClearedTime or 0

    for i = count, 1, -1 do
        local entry = BlackBoxFlightLogDB[i]
        if entry.time > lastCleared then
            CreateCoordinateEntryUI(entry.zone, entry.x, entry.y, entry.message, entry.time)
        end
    end
end
BlackBox.UpdateFlightLogUI = function(force)
    -- your existing logic here
end

-- Stop Rebuilding the UI
function BlackBox.AppendFlightLogEntry(entry)
    if not entry or not entry.zone then return end
    local lastCleared = BlackBoxDB.settings.lastClearedTime or 0
    if entry.time <= lastCleared then return end

    CreateCoordinateEntryUI(entry.zone, entry.x, entry.y, entry.message, entry.time)
end



--------------------------------------------
-- Helper Function: Extract Zone Name
--------------------------------------------
local function ExtractZoneNameFromMessage(msg)
    if not msg then return "Unknown" end
    local zone = msg:match("^Flying Machine ([^%d]+)")
    if zone then
        return zone:match("^%s*(.-)%s*$")
    end
    return "Unknown"
end

--------------------------------------------
-- Helper Function: Normalize Zone Name
--------------------------------------------
local function NormalizeZoneName(zoneName)
    zoneName = zoneName or ""
    local lowerZone = zoneName:lower()
    if lowerZone:find("ringing") then
        return "The Ringing Deeps"
    elseif lowerZone:find("azj") then
        return "Azj%-Kahet"
    elseif lowerZone:find("hallow") then
        return "Hallowfall"
    elseif lowerZone:find("siren") then
        return "Siren Isle"
    elseif lowerZone:find("dorn") then
        return "Isle of Dorn"
    elseif lowerZone:find("undermine") then
        return "Undermine"
    end
    return zoneName
end



--------------------------------------------
-- Event Handler: Process Chat Messages with Coordinates
--------------------------------------------
local function OnChatMessage(self, event, msg, sender, ...)
    if BlackBoxDB.settings.onlyFlyingMachineLog and not msg:lower():find("flying machine") then
        DebugPrint("Ignoring message due to 'Only Capture Flying Machine Messages' setting.")
        return
    end

    local xStr, yStr = msg:match("(%d+%.?%d*)%s+(%d+%.?%d*)")
    if xStr and yStr then
        local xNum = tonumber(xStr)
        local yNum = tonumber(yStr)
        DebugPrint("Found coordinates ->", xNum, yNum)

        local zone = ExtractZoneNameFromMessage(msg)
        local formattedMessage = string.format("Flying Machine %s %.2f %.2f", zone, xNum, yNum)
        DebugPrint("Formatted message ->", formattedMessage)

        AddLogEntry(zone, xNum, yNum, formattedMessage)
    else
        DebugPrint("No numeric coordinates found in this message.")
    end
end

--------------------------------------------
-- Register for Chat Events
--------------------------------------------
local chatEvents = {
    "CHAT_MSG_SAY",
    "CHAT_MSG_PARTY",
    "CHAT_MSG_PARTY_LEADER",
    "CHAT_MSG_RAID",
    "CHAT_MSG_RAID_LEADER",
    "CHAT_MSG_GUILD",
    "CHAT_MSG_OFFICER",
    "CHAT_MSG_CHANNEL",
    "CHAT_MSG_WHISPER",
    "CHAT_MSG_BN_WHISPER",
    "CHAT_MSG_SYSTEM",
}

for _, event in ipairs(chatEvents) do
    FlightLogFrame:RegisterEvent(event)
end

FlightLogFrame:RegisterEvent("CHAT_MSG_ADDON")

local function HandleAddonMessage(prefix, msg, channel, sender)
    if prefix ~= "BB_SYNC" then return end

    if msg:lower():find("^flying machine") then
        local zone = msg:match("^Flying Machine ([^%d]+)")
        local xStr, yStr = msg:match("(%d+%.?%d*)%s+(%d+%.?%d*)")
        if zone and xStr and yStr then
            local x = tonumber(xStr)
            local y = tonumber(yStr)
            zone = NormalizeZoneName(zone)

            local formattedMessage = string.format("Flying Machine %s %.2f %.2f", zone, x, y)
            AddLogEntry(zone, x, y, formattedMessage)

            if not BlackBox.zoneMarkers then
                BlackBox.zoneMarkers = {}
            end
            if not BlackBox.zoneMarkers[zone] then
                BlackBox.zoneMarkers[zone] = {}
            end

            table.insert(BlackBox.zoneMarkers[zone], {
                x = x,
                y = y,
                isVirtual = true
            })

            if MapOverviewFrame and MapOverviewFrame:IsShown() and BlackBox.currentZone == zone then
                BlackBox.PlotMarkersForZone(zone)
            end
        end
    elseif msg:find("^REQUEST:") then
        local requestedZone = NormalizeZoneName(msg:match("^REQUEST:(.+)") or "")
        for _, entry in ipairs(BlackBoxFlightLogDB or {}) do
            if NormalizeZoneName(entry.zone) == requestedZone then
                local reply = string.format("Flying Machine %s %.2f %.2f", entry.zone, entry.x, entry.y)
                local channel = IsInRaid() and "RAID" or (IsInGroup() and "PARTY") or "WHISPER"
                C_ChatInfo.SendAddonMessage("BB_SYNC", reply, channel, sender)
            end
        end
    end
end

-- Save the original OnEvent handler before overriding it
local originalOnEvent = FlightLogFrame:GetScript("OnEvent")

FlightLogFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "CHAT_MSG_ADDON" then
        HandleAddonMessage(...)
    else
        -- Call the original OnEvent handler if it exists
        if originalOnEvent then
            originalOnEvent(self, event, ...)
        end
    end
end)


--------------------------------------------
-- ADDON_LOADED Handler: Rebuild UI and Load Data
--------------------------------------------
local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", function(self, event, addonName)
    if addonName == "BlackBox" then
        BlackBoxDB = BlackBoxDB or {}
        BlackBoxDB.settings = BlackBoxDB.settings or {}
        BlackBoxFlightLogDB = BlackBoxFlightLogDB or {}
        if not BlackBoxFlightLog_SavedToggles then
            BlackBoxFlightLog_SavedToggles = {
                say = false,
                general = false,
                party = true,
                raid = true,
            }
        end
        self:UnregisterEvent("ADDON_LOADED")
    end
end)


--------------------------------------------
-- Clear Button: Clear Only the Flight Log Display
-- (Flight log table remains intact; new entries after clearing will show.)
--------------------------------------------
local clearButton = CreateFrame("Button", nil, FlightLogFrame, "UIPanelButtonTemplate")
clearButton:SetSize(50, 18)
clearButton:SetPoint("TOPLEFT", FlightLogTitle, "BOTTOMLEFT", 0, -5)
clearButton:SetText("Clear")
clearButton:SetScript("OnClick", function()
    --Print("Clear flight log display clicked!")  -- Debug print

    -- Record the time at which the flight log display is cleared.
    BlackBoxDB.settings.lastClearedTime = time()

    -- Refresh the UI; only entries added after the clear time will now be displayed.
    BlackBox.UpdateFlightLogUI()

    DebugPrint("Flight log display permanently cleared (only entries after the clear will show).")
end)
clearButton:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText("Clear Flight Log")
    GameTooltip:AddLine("Clears the flight log display permanently; only new entries will be shown.", 0.8, 0.8, 0.8, true)
    GameTooltip:Show()
end)
clearButton:SetScript("OnLeave", function(self)
    GameTooltip:Hide()
end)





-----------------------------------------------------------
-- 8) MAP OVERVIEW WINDOW (Blizzard Frame with 20px Header, Header Buttons, & Marker Plotting)
-----------------------------------------------------------

-- Set image dimensions.
local imgHeight = 465                -- Desired image height.
local imgWidth = imgHeight * 1.505   -- Compute width as 1.505 times the height.

-- Define header height and minimal padding.
local headerHeight = 20
local padding = 1  -- Minimal padding

-- Calculate overall window dimensions.
local windowWidth = imgWidth + (padding * 2)
local windowHeight = headerHeight + imgHeight + (padding * 2)

-- Create the Map Overview window using BasicFrameTemplateWithInset.
BlackBox = BlackBox or {}
BlackBox.MapOverviewFrame = CreateFrame("Frame", "BlackBoxMapOverview", UIParent, "BasicFrameTemplateWithInset")
local MapOverviewFrame = BlackBox.MapOverviewFrame
MapOverviewFrame:SetSize(windowWidth, windowHeight)
MapOverviewFrame:SetPoint("CENTER")
MapOverviewFrame:SetMovable(true)
MapOverviewFrame:EnableMouse(true)
MapOverviewFrame:RegisterForDrag("LeftButton")
MapOverviewFrame:SetScript("OnDragStart", MapOverviewFrame.StartMoving)
MapOverviewFrame:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()

    local threshold = 20
    local screenWidth = UIParent:GetWidth()
    local screenHeight = UIParent:GetHeight()
    local frameLeft = self:GetLeft()
    local frameBottom = self:GetBottom()
    local frameWidth = self:GetWidth()
    local frameHeight = self:GetHeight()

    local newLeft = frameLeft
    local newBottom = frameBottom

    if frameBottom + frameHeight < threshold then
        newBottom = threshold - frameHeight
    end
    if frameLeft < 0 then
        newLeft = 0
    end
    if frameLeft + frameWidth > screenWidth then
        newLeft = screenWidth - (frameWidth * 0.035)
    end
    if frameBottom + frameHeight > screenHeight then
        newBottom = screenHeight - (frameHeight * 0.035)
    end

    self:ClearAllPoints()
    self:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", newLeft, newBottom)
end)

--  Set default zone to player's current map, if available
C_Timer.After(0.5, function()
    local mapID = C_Map.GetBestMapForUnit("player")
    if mapID then
        local mapInfo = C_Map.GetMapInfo(mapID)
        if mapInfo and mapInfo.name then
            if NormalizeZoneName then
                local normalized = NormalizeZoneName(mapInfo.name)
                BlackBox.currentZone = normalized
                BlackBox.UpdateMapOverview(normalized)
            else
                BlackBox.currentZone = mapInfo.name
                BlackBox.UpdateMapOverview(mapInfo.name)
            end
        end
    end

    if BlackBoxDB.settings and BlackBoxDB.settings.mapOverviewEnabled then
        MapOverviewFrame:Show()
    else
        MapOverviewFrame:Hide()
    end
end)


-- Function to reposition the frame so that only its top 20 pixels are visible
local function RepositionFrame(frame)
    local headerHeight = 20  -- Height of the header you want to remain visible
    local frameHeight = frame:GetHeight()
    local frameLeft = frame:GetLeft() or 0  -- Retain the current horizontal position

    -- Calculate the new bottom coordinate so that only the header (top 20 pixels) is exposed.
    -- Since the header is at the top of the frame, we set the bottom so that:
    -- (newBottom + frameHeight) == headerHeight
    local newBottom = headerHeight - frameHeight

    frame:ClearAllPoints()
    frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", frameLeft, newBottom)
end

-- Override the CloseButton's OnClick handler to reposition the frame instead of hiding it
MapOverviewFrame.CloseButton:SetScript("OnClick", function(self)
    RepositionFrame(self:GetParent())
end)

-- Ensure the frame is set up to receive keyboard events
MapOverviewFrame:EnableKeyboard(true)

-- Allow key events to propagate so they aren’t overridden
MapOverviewFrame:SetPropagateKeyboardInput(true)

-- Set up an OnKeyDown handler that calls RepositionFrame when Escape is pressed
MapOverviewFrame:SetScript("OnKeyDown", function(self, key)
    if key == "ESCAPE" then
        RepositionFrame(self)
    end
end)


-- Create a header frame (20px tall) at the top.
local headerFrame = CreateFrame("Frame", nil, MapOverviewFrame)
headerFrame:SetPoint("TOPLEFT", MapOverviewFrame, "TOPLEFT", padding, -padding)
headerFrame:SetSize(windowWidth - (padding * 2), headerHeight)
-- Zone buttons will be placed in this header.
local btnRinging = CreateFrame("Button", nil, headerFrame, "UIPanelButtonTemplate")
btnRinging:SetSize(40, headerHeight - 2)
btnRinging:SetPoint("LEFT", headerFrame, "LEFT", 0, 0)
btnRinging:SetText("RD")
btnRinging:SetScript("OnClick", function(self)
    BlackBox.UpdateMapOverview("The Ringing Deeps")
end)

local btnSiren = CreateFrame("Button", nil, headerFrame, "UIPanelButtonTemplate")
btnSiren:SetSize(40, headerHeight - 2)
btnSiren:SetPoint("LEFT", btnRinging, "RIGHT", 5, 0)
btnSiren:SetText("SI")
btnSiren:SetScript("OnClick", function(self)
    BlackBox.UpdateMapOverview("Siren Isle")
end)

local btnAzj = CreateFrame("Button", nil, headerFrame, "UIPanelButtonTemplate")
btnAzj:SetSize(40, headerHeight - 2)
btnAzj:SetPoint("LEFT", btnSiren, "RIGHT", 5, 0)
btnAzj:SetText("AK")
btnAzj:SetScript("OnClick", function(self)
    BlackBox.UpdateMapOverview("Azj%-Kahet")
end)

local btnDorn = CreateFrame("Button", nil, headerFrame, "UIPanelButtonTemplate")
btnDorn:SetSize(40, headerHeight - 2)
btnDorn:SetPoint("LEFT", btnAzj, "RIGHT", 5, 0)
btnDorn:SetText("ID")
btnDorn:SetScript("OnClick", function(self)
    BlackBox.UpdateMapOverview("Isle of Dorn")
end)

local btnHallow = CreateFrame("Button", nil, headerFrame, "UIPanelButtonTemplate")
btnHallow:SetSize(40, headerHeight - 2)
btnHallow:SetPoint("LEFT", btnDorn, "RIGHT", 5, 0)
btnHallow:SetText("HF")
btnHallow:SetScript("OnClick", function(self)
    BlackBox.UpdateMapOverview("Hallowfall")
end)

local btnUndermine = CreateFrame("Button", nil, headerFrame, "UIPanelButtonTemplate")
btnUndermine:SetSize(40, headerHeight - 2)
btnUndermine:SetPoint("LEFT", btnHallow, "RIGHT", 5, 0)
btnUndermine:SetText("UN")
btnUndermine:SetScript("OnClick", function(self)
    BlackBox.UpdateMapOverview("Undermine")
end)


-- Create a Clear button in the header.
local btnClear = CreateFrame("Button", nil, headerFrame, "UIPanelButtonTemplate")
btnClear:SetSize(40, headerHeight - 2)
btnClear:SetPoint("RIGHT", headerFrame, "RIGHT", -25, 0)
btnClear:SetText("Clear")

btnClear:SetScript("OnClick", function(self)
    --Print("Clear button clicked!")  -- Debug print to verify the click.

    -- Determine the current zone (defaulting if needed).
    local currentZone = BlackBox.currentZone or "The Ringing Deeps"

    -- Normalize the zone if needed (Azj-Kahet vs Azj%-Kahet)
    local normalizedZone = currentZone
    if normalizedZone == "Azj-Kahet" then
        normalizedZone = "Azj%-Kahet"
    end

    -- Clear the displayed map image.
    if MapOverviewDisplay and MapOverviewDisplay.mapTexture then
        MapOverviewDisplay.mapTexture:SetTexture("")
    end

    -- Clear zone markers
    if BlackBox.zoneMarkers and BlackBox.zoneMarkers[normalizedZone] then
        for _, marker in ipairs(BlackBox.zoneMarkers[normalizedZone]) do
            marker:Hide()
        end
        BlackBox.zoneMarkers[normalizedZone] = nil
        --Print("Cleared markers for zone:", normalizedZone)
    end

    -- Clean up flight log entries for this zone
if BlackBoxFlightLogDB then
    local cleanedLog = {}
    local zoneToMatch = normalizedZone:lower():gsub("%%", "")

    for _, entry in ipairs(BlackBoxFlightLogDB) do
        local entryZone = tostring(entry.zone or ""):lower()
        local matchesZone = entryZone:find(zoneToMatch, 1, true)

        if not matchesZone then
            table.insert(cleanedLog, entry)
        else
            --print(string.format("Removing entry from flight log: %s (%.2f, %.2f)", entry.zone or "Unknown", entry.x or 0, entry.y or 0))
        end
    end

    BlackBoxFlightLogDB = cleanedLog
end


    -- Reset current zone
    BlackBox.currentZone = nil
end)

-- Add tooltip to the Clear button.
btnClear:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText("Clear Map")
    GameTooltip:AddLine("Permanently deletes the current map image and its plotted markers.", 0.8, 0.8, 0.8, true)
    GameTooltip:Show()
end)

btnClear:SetScript("OnLeave", function(self)
    GameTooltip:Hide()
end)


-- Create the display frame for the map image.
BlackBox.MapOverviewDisplay = CreateFrame("Frame", nil, MapOverviewFrame)
local MapOverviewDisplay = BlackBox.MapOverviewDisplay
-- Anchor it immediately below the header.
MapOverviewDisplay:SetPoint("TOPLEFT", headerFrame, "BOTTOMLEFT", 0, 0)
MapOverviewDisplay:SetSize(imgWidth, imgHeight)
MapOverviewDisplay:Show()

-- Create a texture for the map image.
MapOverviewDisplay.mapTexture = MapOverviewDisplay:CreateTexture(nil, "ARTWORK")
MapOverviewDisplay.mapTexture:SetAllPoints(MapOverviewDisplay)
-- Set a default texture using a placeholder key.
MapOverviewDisplay.mapTexture:SetTexture("Interface\\AddOns\\BlackBox\\Maps\\RingingDeeps.tga")

-- Debug print the dimensions of the display frame.
local dispW, dispH = MapOverviewDisplay:GetWidth(), MapOverviewDisplay:GetHeight()
--print("MapOverviewDisplay dimensions:", dispW, dispH)


-----------------------------------------------------------
-- Utility: Clean the zone string from a flight log entry.
-- This function checks the entry string against known zone names
-- from our zoneImages table and returns a clean zone name.
-----------------------------------------------------------
local function CleanZoneString(zoneString)
    if BlackBoxDB and BlackBoxDB.zoneImages then
        for zoneName, _ in pairs(BlackBoxDB.zoneImages) do
            -- Remove any pattern characters (like %) from the key.
            local plainZone = zoneName:gsub("%%", "")
            if zoneString:find(plainZone, 1, true) then
                return plainZone
            end
        end
    end
    return zoneString
end

-----------------------------------------------------------
-- 9) Plot Map Pins (Using the Image's 0–100 Coordinate System)
-----------------------------------------------------------
function BlackBox.PlotMarkersForZone(zone)
    -- Normalize the zone name so both "Azj-Kahet" and "Azj%-Kahet" become "Azj%-Kahet"
    local normalizedZone = zone
    if zone == "Azj-Kahet" or zone == "Azj%-Kahet" then
        normalizedZone = "Azj%-Kahet"
    end

    if not normalizedZone or not MapOverviewDisplay then 
        return 
    end

    -- Ensure our zoneMarkers table exists.
    BlackBox.zoneMarkers = BlackBox.zoneMarkers or {}

    local mapWidth = MapOverviewDisplay:GetWidth()
    local mapHeight = MapOverviewDisplay:GetHeight()

    -- Hide markers for all zones so that only the active zone's markers will be visible.
    for z, markers in pairs(BlackBox.zoneMarkers) do
        for _, marker in ipairs(markers) do
            if marker and type(marker.Hide) == "function" then
                marker:Hide()
            end
        end
    end

    -- Clear any existing markers for the current (normalized) zone.
    BlackBox.zoneMarkers[normalizedZone] = {}

    -- Create new markers for this zone based on the flight log.
    for _, entry in ipairs(BlackBoxFlightLogDB or {}) do
        -- Use NormalizeZoneName to ensure we compare the proper zone names.
        local entryZoneNorm = NormalizeZoneName(entry.zone)
        if entryZoneNorm == normalizedZone then
            local entryColor
            if entry.eventType == "crate" then
                entryColor = { r = 1, g = 0, b = 0, a = 1 }  -- red marker for crate events
            else
                local isGreenEnabled = BlackBoxDB.settings.useGreenSharedPins
                entryColor = isGreenEnabled and { r = 0, g = 1, b = 0, a = 1 } or { r = 1, g = 1, b = 0, a = 1 }
            end

            local marker = MapOverviewDisplay:CreateTexture(nil, "OVERLAY")
            marker:SetColorTexture(entryColor.r, entryColor.g, entryColor.b, entryColor.a)
            marker:SetSize(6, 6)

            local markerX = (entry.x / 100) * mapWidth
            local markerY = (entry.y / 100) * mapHeight

            marker:ClearAllPoints()
            marker:SetPoint("TOPLEFT", MapOverviewDisplay, "TOPLEFT", markerX, -markerY)
            marker:Show()

            table.insert(BlackBox.zoneMarkers[normalizedZone], marker)
        end
    end
end

-----------------------------------------------------------
-- Update Map Overview: Set the image and plot markers.
-----------------------------------------------------------
function BlackBox.UpdateMapOverview(zone)
    if not zone then 
        zone = BlackBox.currentZone or "The Ringing Deeps" 
    else
        BlackBox.currentZone = zone
    end

    -- When the zone changes, reset any block flags for Flying Machine recordings.
    if BlackBox.lastZone ~= zone then
        BlackBox.blockFlyingMachine = false
        BlackBox.lastZone = zone
    end

    -- Normalize zone for the zoneImages table.
    local normalizedZone = zone
    if zone == "Azj-Kahet" or zone == "Azj%-Kahet" then
        normalizedZone = "Azj%-Kahet"
    end

    local imagePath = (BlackBoxDB and BlackBoxDB.zoneImages and BlackBoxDB.zoneImages[normalizedZone])
                        or ("Interface\\AddOns\\BlackBox\\Maps\\" .. normalizedZone .. ".tga")
    MapOverviewDisplay.mapTexture:SetTexture(imagePath)
    BlackBox.PlotMarkersForZone(normalizedZone)
end


-----------------------------------------------------------
-- ADDON_LOADED Handler: Initialize saved variables and zoneImages.
-----------------------------------------------------------
local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:SetScript("OnEvent", function(self, event, addonName)
    if addonName == "BlackBox" then
        BlackBoxDB = BlackBoxDB or {}
        BlackBoxDB.settings = BlackBoxDB.settings or {}
        BlackBoxFlightLogDB = BlackBoxFlightLogDB or {}

        BlackBoxDB.zoneImages = BlackBoxDB.zoneImages or {
            ["The Ringing Deeps"] = "Interface\\AddOns\\BlackBox\\Maps\\RingingDeeps.tga",
            ["Siren Isle"]        = "Interface\\AddOns\\BlackBox\\Maps\\SirenIsle.tga",
            ["Azj%-Kahet"]        = "Interface\\AddOns\\BlackBox\\Maps\\AzjKahet.tga",
            ["Isle of Dorn"]      = "Interface\\AddOns\\BlackBox\\Maps\\IsleOfDorn.tga",
            ["Hallowfall"]        = "Interface\\AddOns\\BlackBox\\Maps\\Hallowfall.tga",
            ["Undermine"]         = "Interface\\AddOns\\BlackBox\\Maps\\Undermine.tga",
        }

        if BlackBoxDB.settings.mapOverviewEnabled then
            MapOverviewFrame:Show()
            BlackBox.UpdateMapOverview(BlackBox.currentZone)
        else
            MapOverviewFrame:Hide()
        end

        self:UnregisterEvent("ADDON_LOADED")
    end
end)


SLASH_FIXZONES1 = "/fixzones"
SlashCmdList["FIXZONES"] = function()
    local fixed = 0
    for _, e in ipairs(BlackBoxFlightLogDB or {}) do
        if e.zone and e.zone:lower():find("ringing") then
            e.zone = "The Ringing Deeps"
            fixed = fixed + 1
        elseif e.zone and e.zone:lower():find("azj") then
            e.zone = "Azj-Kahet"
            fixed = fixed + 1
        elseif e.zone and e.zone:lower():find("hallow") then
            e.zone = "Hallowfall"
            fixed = fixed + 1
        end
    end
    print("Fixed", fixed, "zones")
end

-- Insert global AddLogEntry function if not defined
-- Insert global AddLogEntry function if not defined
if not AddLogEntry then
    function AddLogEntry(zone, x, y, message)
        local entry = {
            zone = zone,
            x = x,
            y = y,
            message = message,
            time = time()
        }

        table.insert(BlackBoxFlightLogDB, entry)

        if FlightLogFrame and FlightLogFrame:IsShown() then
            if BlackBox.AppendFlightLogEntry then
                BlackBox.AppendFlightLogEntry(entry)
            else
                BlackBox.UpdateFlightLogUI() -- fallback, not ideal, but just in case
            end
        end
    end
end
