-- Created by Percy yours truly
local addonName, addonTable = ...

-- Global/SavedVariables Database
UlatekCaveMapDB = UlatekCaveMapDB or {}

-- Forward declarations
local SafeInit
local CreateCustomMapFrame
local IsTargetNPC
local TriggerMapOpen
local SelectGossipOptionByText

-- -----------------------------------------------------------------------------
-- Helper Functions
-- -----------------------------------------------------------------------------

-- Extract NPC ID from a Unit GUID
local function GetNPCID(unit)
    local guid = UnitGUID(unit)
    if not guid then return nil end
    local unitType, _, _, _, _, npcID = strsplit("-", guid)
    if (unitType == "Creature" or unitType == "Vehicle") and npcID then
        return tonumber(npcID)
    end
    return nil
end

-- Check if unit matches configured NPC
local function IsTargetNPC(unit)
    if not unit then return false end
    local npcID = GetNPCID(unit)
    local name = UnitName(unit)
    
    if not UlatekCaveMapDB or not UlatekCaveMapDB.NPCs then return false end

    -- Check on ID
    if npcID and UlatekCaveMapDB.NPCs[npcID] then
        return true
    end
    
    -- Check on name
    if name then
        if UlatekCaveMapDB.NPCs[name] then
            return true
        end
        for k, v in pairs(UlatekCaveMapDB.NPCs) do
            if type(k) == "string" and string.lower(k) == string.lower(name) and v then
                return true
            end
        end
    end
    
    return false
end

-- Trigger the map opening flow
TriggerMapOpen = function()
    -- Ensure frame is initialized before displaying
    SafeInit()
    
    if UlatekCaveMapDB and UlatekCaveMapDB.CloseGossipOnOpen then
        -- Close the gossip/quest dialogs so the player can see the map
    end
    
    if UlatekCaveMapFrame then
        UlatekCaveMapFrame:Show()
    end
end

-- Check if a specific gossip option exists
local function DoesGossipOptionExist(searchText)
    local target = string.lower(searchText)
    
    -- Modern retail API
    if C_GossipInfo and C_GossipInfo.GetOptions then
        local options = C_GossipInfo.GetOptions()
        if options then
            for _, option in ipairs(options) do
                if option.name and string.find(string.lower(option.name), target) then
                    return true
                end
            end
        end
    end
    
    -- Fallback
    if GetGossipOptions then
        local options = { GetGossipOptions() }
        for i = 1, #options, 2 do
            local text = options[i]
            if text and string.find(string.lower(text), target) then
                return true
            end
        end
    end
    
    return false
end

-- Automatically select gossip option containing specific text
SelectGossipOptionByText = function(searchText)
    local target = string.lower(searchText)
    
    if C_GossipInfo and C_GossipInfo.GetOptions then
        local options = C_GossipInfo.GetOptions()
        if options then
            for _, option in ipairs(options) do
                if option.name and string.find(string.lower(option.name), target) then
                    C_GossipInfo.SelectOption(option.gossipOptionID)
                    if UlatekCaveMapFrame then UlatekCaveMapFrame:Hide() end
                    return true
                end
            end
        end
    end
    
    -- Fallback
    if GetGossipOptions then
        local options = { GetGossipOptions() }
        for i = 1, #options, 2 do
            local text = options[i]
            if text and string.find(string.lower(text), target) then
                local index = math.floor(i / 2) + 1
                SelectGossipOption(index)
                if UlatekCaveMapFrame then UlatekCaveMapFrame:Hide() end
                return true
            end
        end
    end

    return false
end

-- -----------------------------------------------------------------------------
-- UI Setup 
-- -----------------------------------------------------------------------------

CreateCustomMapFrame = function()

    -- Prevent duplicate frame creation
    if UlatekCaveMapFrame then return UlatekCaveMapFrame end
    
    -- Main Window Frame
    local f = CreateFrame("Frame", "UlatekCaveMapFrame", UIParent)
    f:SetSize(600, 450)
    f:SetPoint("CENTER")
    f:SetMovable(true)
    f:SetResizable(false)
    f:SetFrameStrata("DIALOG")
    
    -- Prevent external UI fading from other addons
    f:SetIgnoreParentAlpha(true)
    local originalSetAlpha = f.SetAlpha
    f.SetAlpha = function(self, alpha)
        if alpha < 1 and self:IsShown() then
            originalSetAlpha(self, 1)
        else
            originalSetAlpha(self, alpha)
        end
    end
    
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetClampedToScreen(true)
    f:Hide()
    
    -- Automatic close
    f:SetScript("OnShow", function(self)
        self.elapsed = 0
        if self.UpdateMapTexture then
            self:UpdateMapTexture()
        end
    end)
    f:SetScript("OnUpdate", function(self, elapsed)
        self.elapsed = (self.elapsed or 0) + elapsed
        if self.elapsed > 0.3 then
            self.elapsed = 0
            
            -- Check if any standard dialog is currently shown
            local isDialogOpen = false
            if GossipFrame and GossipFrame:IsShown() then isDialogOpen = true end
            if QuestFrame and QuestFrame:IsShown() then isDialogOpen = true end
            if TaxiFrame and TaxiFrame:IsShown() then isDialogOpen = true end
            
            local dui = _G["DUIQuestFrame"]
            if dui and dui:IsShown() then isDialogOpen = true end
            
            -- Check if target NPC is still valid and within interaction range
            local hasTarget = UnitExists("target") and UnitIsVisible("target") and CheckInteractDistance("target", 3)
            
            -- If dialogue was closed hide map overlay
            if not isDialogOpen or not hasTarget then
                self:Hide()
            end
        end
    end)
    
    -- Make press Escape close the frame safely
    if UISpecialFrames then
        tinsert(UISpecialFrames, "UlatekCaveMapFrame")
    end
    
    -- Outer Border Frame
    local border = f:CreateTexture(nil, "BACKGROUND", nil, -2)
    border:SetAllPoints(f)
    border:SetColorTexture(0.2, 0.2, 0.2, 1) -- dark-gray
    
    -- Inner Frame Background
    local bg = f:CreateTexture(nil, "BACKGROUND", nil, -1)
    bg:SetPoint("TOPLEFT", 2, -2)
    bg:SetPoint("BOTTOMRIGHT", -2, 2)
    bg:SetColorTexture(0.08, 0.08, 0.08, 0.95) -- charcoal
    
    -- Window Drag Handlers
    f:SetScript("OnDragStart", function(self)
        self:StartMoving()
    end)
    f:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        -- Save frame coordinates
        if UlatekCaveMapDB then
            local point, _, relativePoint, xOfs, yOfs = self:GetPoint()
            UlatekCaveMapDB.FramePos = {
                point = point,
                relativePoint = relativePoint,
                xOfs = xOfs,
                yOfs = yOfs
            }
        end
    end)
    
    -- Title Text
    local title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOP", 0, -12)
    title:SetText("Vaults of Atal'Utek")
    
    -- Close Button
    local closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
    closeBtn:SetPoint("TOPRIGHT", -2, -2)
    closeBtn:SetScript("OnClick", function()
        f:Hide()
    end)
    
    -- Map Container
    local container = CreateFrame("Frame", nil, f)
    container:SetPoint("TOPLEFT", 8, -36)
    container:SetPoint("BOTTOMRIGHT", -8, 8)
    f.Container = container
    
    -- Map Sub-Container for static map texture and flightmaster icons
    local subContainer = CreateFrame("Frame", nil, container)
    subContainer:SetAllPoints(container)
    f.MapSubContainer = subContainer
    
    -- Static Map Texture
    local mapTexture = subContainer:CreateTexture("UlatekCaveMapTexture", "ARTWORK")
    mapTexture:SetAllPoints(subContainer)
    local texturePath = "Interface\\AddOns\\" .. addonName .. "\\UlatekMap"
    mapTexture:SetTexture(texturePath)
    f.MapTexture = mapTexture
    
    -- Flightmaster Icon for Eastern Amani Outpost
    local fmBtn1 = CreateFrame("Button", nil, subContainer)
    fmBtn1:SetSize(36, 36)
    fmBtn1:EnableMouse(true)
    
    local fmIcon1 = fmBtn1:CreateTexture(nil, "OVERLAY")
    fmIcon1:SetAllPoints(fmBtn1)
    fmIcon1:SetTexture("Interface\\Minimap\\Tracking\\FlightMaster")
    fmBtn1:SetHighlightTexture("Interface\\Minimap\\Tracking\\FlightMaster", "ADD")
    
    fmBtn1:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(true) end
        GameTooltip:SetText("Fly to: Eastern Amani Outpost", 1, 1, 1)
        GameTooltip:AddLine("Click to select this flight option.", 0.8, 0.8, 0.8, true)
        GameTooltip:Show()
    end)
    fmBtn1:SetScript("OnLeave", function(self)
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(false) end
        GameTooltip:Hide()
    end)
    fmBtn1:SetScript("OnClick", function()
        SelectGossipOptionByText("eastern amani outpost")
    end)
    
    -- Flightmaster Icon for Amani Foothold
    local fmBtn2 = CreateFrame("Button", nil, subContainer)
    fmBtn2:SetSize(36, 36)
    fmBtn2:EnableMouse(true)
    
    local fmIcon2 = fmBtn2:CreateTexture(nil, "OVERLAY")
    fmIcon2:SetAllPoints(fmBtn2)
    fmIcon2:SetTexture("Interface\\Minimap\\Tracking\\FlightMaster")
    fmBtn2:SetHighlightTexture("Interface\\Minimap\\Tracking\\FlightMaster", "ADD")
    
    fmBtn2:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(true) end
        GameTooltip:SetText("Fly to: Amani Foothold", 1, 1, 1)
        GameTooltip:AddLine("Click to select this flight option.", 0.8, 0.8, 0.8, true)
        GameTooltip:Show()
    end)
    fmBtn2:SetScript("OnLeave", function(self)
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(false) end
        GameTooltip:Hide()
    end)
    fmBtn2:SetScript("OnClick", function()
        SelectGossipOptionByText("amani foothold")
    end)
    
    -- Flightmaster Icon for Northern Amani Bulwark
    local fmBtn3 = CreateFrame("Button", nil, subContainer)
    fmBtn3:SetSize(36, 36)
    fmBtn3:EnableMouse(true)
    
    local fmIcon3 = fmBtn3:CreateTexture(nil, "OVERLAY")
    fmIcon3:SetAllPoints(fmBtn3)
    fmIcon3:SetTexture("Interface\\Minimap\\Tracking\\FlightMaster")
    fmBtn3:SetHighlightTexture("Interface\\Minimap\\Tracking\\FlightMaster", "ADD")
    
    fmBtn3:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(true) end
        GameTooltip:SetText("Fly to: Northern Amani Bulwark", 1, 1, 1)
        GameTooltip:AddLine("Click to select this flight option.", 0.8, 0.8, 0.8, true)
        GameTooltip:Show()
    end)
    fmBtn3:SetScript("OnLeave", function(self)
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(false) end
        GameTooltip:Hide()
    end)
    fmBtn3:SetScript("OnClick", function()
        SelectGossipOptionByText("northern amani bulwark")
    end)
    
    -- Flightmaster Icon for Venomous Abyss
    local fmBtn4 = CreateFrame("Button", nil, subContainer)
    fmBtn4:SetSize(36, 36)
    fmBtn4:EnableMouse(true)
    
    local fmIcon4 = fmBtn4:CreateTexture(nil, "OVERLAY")
    fmIcon4:SetAllPoints(fmBtn4)
    fmIcon4:SetTexture("Interface\\Minimap\\Tracking\\FlightMaster")
    fmBtn4:SetHighlightTexture("Interface\\Minimap\\Tracking\\FlightMaster", "ADD")
    
    fmBtn4:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(true) end
        local available = DoesGossipOptionExist("venomous abyss")
        if available then
            GameTooltip:SetText("Fly to: Venomous Abyss", 1, 1, 1)
            GameTooltip:AddLine("Click to select this flight option.", 0.8, 0.8, 0.8, true)
        else
            GameTooltip:SetText("Fly to: Venomous Abyss |cffff0000(Locked)|r", 0.5, 0.5, 0.5)
            GameTooltip:AddLine("This flight option is currently locked, you need to unlock |cff00ff00Spectral Shipping|r at the |cff00ff00Altar of Corruption|r.", 0.6, 0.6, 0.6, true)
        end
        GameTooltip:Show()
    end)
    fmBtn4:SetScript("OnLeave", function(self)
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(false) end
        GameTooltip:Hide()
    end)
    fmBtn4:SetScript("OnClick", function()
        if DoesGossipOptionExist("venomous abyss") then
            SelectGossipOptionByText("venomous abyss")
        end
    end)
    
    -- Flightmaster Icon for The Underbelly
    local fmBtn5 = CreateFrame("Button", nil, subContainer)
    fmBtn5:SetSize(36, 36)
    fmBtn5:EnableMouse(true)
    
    local fmIcon5 = fmBtn5:CreateTexture(nil, "OVERLAY")
    fmIcon5:SetAllPoints(fmBtn5)
    fmIcon5:SetTexture("Interface\\Minimap\\Tracking\\FlightMaster")
    fmBtn5:SetHighlightTexture("Interface\\Minimap\\Tracking\\FlightMaster", "ADD")
    
    fmBtn5:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(true) end
        local available = DoesGossipOptionExist("the underbelly")
        if available then
            GameTooltip:SetText("Fly to: The Underbelly", 1, 1, 1)
            GameTooltip:AddLine("Click to select this flight option.", 0.8, 0.8, 0.8, true)
        else
            GameTooltip:SetText("Fly to: The Underbelly |cffff0000(Locked)|r", 0.5, 0.5, 0.5)
            GameTooltip:AddLine("This flight option is currently locked, you need to unlock |cff00ff00Spectral Shipping|r at the |cff00ff00Altar of Corruption|r.", 0.6, 0.6, 0.6, true)
        end
        GameTooltip:Show()
    end)
    fmBtn5:SetScript("OnLeave", function(self)
        if GameTooltip.SetIgnoreParentAlpha then GameTooltip:SetIgnoreParentAlpha(false) end
        GameTooltip:Hide()
    end)
    fmBtn5:SetScript("OnClick", function()
        if DoesGossipOptionExist("the underbelly") then
            SelectGossipOptionByText("the underbelly")
        end
    end)
    
    -- Position updater for all icons based on percentage coordinates relative to the active map sub-container
    local function UpdateAllIconPositions()
        local w, h = subContainer:GetSize()
        if w == 0 or h == 0 then w, h = 584, 406 end
        
        -- Icon 1: 54.2, 39.9
        local x1 = w * (54.2 / 100)
        local y1 = -h * (39.9 / 100)
        fmBtn1:ClearAllPoints()
        fmBtn1:SetPoint("CENTER", subContainer, "TOPLEFT", x1, y1)
        
        -- Icon 2: 50.2, 62.0
        local x2 = w * (50.2 / 100)
        local y2 = -h * (62.0 / 100)
        fmBtn2:ClearAllPoints()
        fmBtn2:SetPoint("CENTER", subContainer, "TOPLEFT", x2, y2)
        
        -- Icon 3: 41.5, 23.3
        local x3 = w * (41.5 / 100)
        local y3 = -h * (23.3 / 100)
        fmBtn3:ClearAllPoints()
        fmBtn3:SetPoint("CENTER", subContainer, "TOPLEFT", x3, y3)
        
        -- Icon 4: 48.7, 27.1
        local x4 = w * (48.7 / 100)
        local y4 = -h * (27.1 / 100)
        fmBtn4:ClearAllPoints()
        fmBtn4:SetPoint("CENTER", subContainer, "TOPLEFT", x4, y4)
        
        -- Icon 5: 45.6, 11.9
        local x5 = w * (45.6 / 100)
        local y5 = -h * (11.9 / 100)
        fmBtn5:ClearAllPoints()
        fmBtn5:SetPoint("CENTER", subContainer, "TOPLEFT", x5, y5)
    end
    
    -- Map texture layout updater (guarantees static texture and icons are shown and correctly positioned)
    local function UpdateMapTexture(self)
        fmBtn1:Show()
        fmBtn2:Show()
        fmBtn3:Show()
        fmBtn4:Show()
        fmBtn5:Show()
        
        -- Grey out Venomous Abyss if not available
        if DoesGossipOptionExist("venomous abyss") then
            fmIcon4:SetDesaturated(false)
            fmIcon4:SetAlpha(1.0)
        else
            fmIcon4:SetDesaturated(true)
            fmIcon4:SetAlpha(0.7)
        end
        
        -- Grey out The Underbelly if not available
        if DoesGossipOptionExist("the underbelly") then
            fmIcon5:SetDesaturated(false)
            fmIcon5:SetAlpha(1.0)
        else
            fmIcon5:SetDesaturated(true)
            fmIcon5:SetAlpha(0.7)
        end
        
        UpdateAllIconPositions()
    end
    
    f.UpdateMapTexture = UpdateMapTexture
    
    -- Run initial layout update
    UpdateMapTexture(f)
    
    return f
end

-- -----------------------------------------------------------------------------
-- Addon Initializer
-- -----------------------------------------------------------------------------

local isInitialized = false
SafeInit = function()
    if isInitialized then return end
    isInitialized = true
    
    -- Initialize Saved Variables
    if UlatekCaveMapDB.NPCs == nil then
        UlatekCaveMapDB.NPCs = {
            [272197] = true, -- ID
            ["Amani Windcaller"] = true, -- name
        }
    end
    if UlatekCaveMapDB.CloseGossipOnOpen == nil then
        UlatekCaveMapDB.CloseGossipOnOpen = true
    end
    
    -- Construct the map frame
    CreateCustomMapFrame()
    
    -- Restore saved frame position
    if UlatekCaveMapDB.FramePos and UlatekCaveMapFrame then
        UlatekCaveMapFrame:ClearAllPoints()
        UlatekCaveMapFrame:SetPoint(
            UlatekCaveMapDB.FramePos.point,
            UIParent,
            UlatekCaveMapDB.FramePos.relativeProfile or UlatekCaveMapDB.FramePos.relativePoint,
            UlatekCaveMapDB.FramePos.xOfs,
            UlatekCaveMapDB.FramePos.yOfs
        )
    end
end

-- -----------------------------------------------------------------------------
-- Event Handler
-- -----------------------------------------------------------------------------

local eventFrame = CreateFrame("Frame")

eventFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "ADDON_LOADED" then
        local name = ...
        if name == addonName then
            SafeInit()
            print("|cff00ff00UlatekCaveMap loaded successfully!|r")
        end
    elseif event == "GOSSIP_SHOW" or event == "QUEST_GREET" or event == "QUEST_DETAIL" then
        if IsTargetNPC("npc") or IsTargetNPC("target") then
            TriggerMapOpen()
        end
    end
end)

eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("GOSSIP_SHOW")
eventFrame:RegisterEvent("QUEST_GREET")
eventFrame:RegisterEvent("QUEST_DETAIL")
