local ADDON_NAME, ns = ...
local WF = ns.WF

WF.UI = WF.UI or {}
WF.UI.Minimap = WF.UI.Minimap or {}
local Mini = WF.UI.Minimap

-- If the file is accidentally loaded twice, do nothing on the second pass.
if Mini._minimapButtonLoaded then
  return
end
Mini._minimapButtonLoaded = true

-- ---------------------------------------------------------------------
-- Minimap button
--   - Prefer LibDataBroker + LibDBIcon when available (best compatibility)
--   - Fallback to manual button if libs are unavailable
--   - Enforces ONE visible button (prevents duplicates / double rings)
-- ---------------------------------------------------------------------

local LDB_NAME = "WhatFarm"
local ICON = "Interface\\AddOns\\WhatFarm\\Media\\MinimapIcon"
local ICON_COORDS = { 0, 1, 0, 1 }

-- Manual fallback sizing only
local FALLBACK_SIZE = 34
local FALLBACK_ICON_INSET = 4
local FALLBACK_RADIUS_PAD = 8

-- LibDBIcon icon layout (fixes "tiny icon inside big ring")
local LIB_ICON_PAD = 1       -- pixels inside the ring
local LIB_TEX_CROP = 0.03     -- slight crop to avoid edge bleed

-- ---------------------------------------------------------
-- Tooltip helpers
-- ---------------------------------------------------------
local function DisplayProfileName(name)
  name = tostring(name or "")
  if name == "" then
    return "Default"
  end
  return name
end

local function _Theme()
  local t = (WF and WF.UI and WF.UI.Theme) or {}
  local accent = t.accent or { 0.35, 0.78, 1.00, 1.00 }
  local muted  = t.muted  or { 0.65, 0.65, 0.65, 1.00 }
  local text   = t.text   or { 1.00, 1.00, 1.00, 1.00 }
  return accent, muted, text
end

local function _HexByte(n)
  n = tonumber(n) or 0
  if n < 0 then n = 0 end
  if n > 255 then n = 255 end
  return string.format("%02x", math.floor(n + 0.5))
end

local function _AccentPrefix()
  local a = (WF and WF.UI and WF.UI.Theme and WF.UI.Theme.accent) or { 0.35, 0.78, 1.00, 1.00 }
  local r = _HexByte((a[1] or 0) * 255)
  local g = _HexByte((a[2] or 0) * 255)
  local b = _HexByte((a[3] or 0) * 255)
  return "|cff" .. r .. g .. b
end

local function _Accent(s)
  return _AccentPrefix() .. tostring(s or "") .. "|r"
end

local function _FmtDuration(sec)
  sec = tonumber(sec) or 0
  if sec < 0 then sec = 0 end
  sec = math.floor(sec + 0.5)

  local h = math.floor(sec / 3600)
  local m = math.floor((sec % 3600) / 60)
  local s = sec % 60

  if h > 0 then
    return string.format("%d:%02d:%02d", h, m, s)
  end
  return string.format("%d:%02d", m, s)
end

local function _GetMemoryMB()
  if UpdateAddOnMemoryUsage then
    pcall(UpdateAddOnMemoryUsage)
  end
  if GetAddOnMemoryUsage then
    local kb = GetAddOnMemoryUsage(ADDON_NAME) or 0
    if kb < 0 then kb = 0 end
    return kb / 1024
  end
  return 0
end

local function GetDB()
  if not WF or not WF.DB or not WF.DB.Get then
    return nil
  end
  local db = WF.DB:Get()
  if not db then
    return nil
  end
  db.minimap = db.minimap or {}
  return db
end

local function _GetActiveMode()
  if WF and WF.DB and WF.DB.GetActiveProfileName then
    local name = WF.DB:GetActiveProfileName()
    if type(name) == "string" and name ~= "" then
      return name
    end
  end

  local tr = WF and WF.Tracker
  local sess = tr and tr.current
  local mode = sess and sess.mode or nil
  if type(mode) == "string" and mode ~= "" then
    return mode
  end

  return "Default"
end

local function _Trim(s)
  s = tostring(s or "")
  s = s:gsub("^%s+", ""):gsub("%s+$", "")
  return s
end

local function _GetCurrentZoneLabel()
  local Util = WF and WF.Util
  if Util and Util.GetZoneLabel then
    local zone = _Trim(Util:GetZoneLabel())
    if zone ~= "" then
      return zone
    end
  end
  return ""
end

local function _GetCurrentMapPosition()
  local Util = WF and WF.Util
  local mapId, x, y = nil, nil, nil

  if Util and Util.GetPlayerMapXY then
    mapId, x, y = Util:GetPlayerMapXY()
  end

  if (not mapId or x == nil or y == nil) and Util and Util.GetLastWorldMapXY then
    local lwMapId, lwX, lwY = Util:GetLastWorldMapXY()
    if lwMapId then
      mapId = mapId or lwMapId
      if x == nil then x = lwX end
      if y == nil then y = lwY end
    end
  end

  return mapId, x, y
end

local function _GetIdleFarmName()
  local zone = _GetCurrentZoneLabel()
  if zone ~= "" then
    return zone
  end
  return "—"
end

local function _SessionHasExplicitFarm(sess)
  if type(sess) ~= "table" then
    return false
  end

  if sess.farmId ~= nil then
    return true
  end

  local customName = _Trim(sess._wfCustomFarmName)
  if customName ~= "" then
    return true
  end

  return false
end

local function _ResolveRunningFarmName(sess)
  if type(sess) ~= "table" then
    return _GetIdleFarmName()
  end

  local liveZone = _GetCurrentZoneLabel()
  local mapId, x, y = _GetCurrentMapPosition()

  if liveZone ~= "" then
    sess.zone = liveZone
  end
  if mapId then
    sess.mapId = mapId
  end
  if x ~= nil then
    sess.x = x
  end
  if y ~= nil then
    sess.y = y
  end

  if _SessionHasExplicitFarm(sess) then
    local farmName = _Trim(sess._wfCustomFarmName or sess.farmName)
    if farmName ~= "" then
      return farmName
    end
  end

  local zone = _Trim(sess.zone)
  if zone ~= "" then
    return zone
  end

  return _GetIdleFarmName()
end

local function _FarmTooltipInfo()
  local tr = WF and WF.Tracker
  local sess = tr and tr.current

  local running = false
  if tr and tr.IsActive then
    running = tr:IsActive() and true or false
  end

  local farmName = nil
  local mode = _GetActiveMode()
  local elapsed = nil

  if running then
    farmName = _ResolveRunningFarmName(sess)
    if tr and tr.GetElapsed then
      elapsed = tr:GetElapsed()
    end
  else
    farmName = _GetIdleFarmName()
  end

  if type(farmName) ~= "string" or farmName == "" then
    farmName = "—"
  end

  if type(mode) ~= "string" or mode == "" then
    mode = _GetActiveMode()
  end

  return farmName, mode, running, elapsed
end

local function _AddDouble(tt, l, r, lr, lg, lb, rr, rg, rb)
  if tt and tt.AddDoubleLine then
    tt:AddDoubleLine(l or "", r or "", lr or 1, lg or 1, lb or 1, rr or 1, rg or 1, rb or 1)
    return
  end
  if tt and tt.AddLine then
    tt:AddLine((l or "") .. ": " .. (r or ""), lr or 1, lg or 1, lb or 1)
  end
end

local function _BuildTooltip(tt, dragHint)
  if not tt or not tt.AddLine then
    return
  end

  local ACCENT, MUTED, TEXT = _Theme()
  local ar, ag, ab = ACCENT[1], ACCENT[2], ACCENT[3]
  local mr, mg, mb = MUTED[1], MUTED[2], MUTED[3]
  local tr, tg, tb = TEXT[1], TEXT[2], TEXT[3]

  local farmName, mode, running, elapsed = _FarmTooltipInfo()

  tt:AddLine("What Farm?", ar, ag, ab)
  _AddDouble(tt, "Farm", farmName, tr, tg, tb, ar, ag, ab)
  _AddDouble(tt, "Mode", DisplayProfileName(mode or "Default"), tr, tg, tb, tr, tg, tb)

  if running then
    _AddDouble(tt, "Status", "RUNNING", tr, tg, tb, ar, ag, ab)
    if elapsed then
      _AddDouble(tt, "Run time", _FmtDuration(elapsed), tr, tg, tb, tr, tg, tb)
    end
  else
    _AddDouble(tt, "Status", "Idle", tr, tg, tb, mr, mg, mb)
  end

  local mem = _GetMemoryMB()
  if mem and mem > 0 then
    _AddDouble(tt, "Memory", string.format("%.2f MB", mem), tr, tg, tb, mr, mg, mb)
  end

  tt:AddLine(" ")
  tt:AddLine(_Accent("Left-click") .. ": Toggle window", 1, 1, 1)
  tt:AddLine(_Accent("Right-click") .. ": Settings", 1, 1, 1)

  if dragHint and dragHint ~= "" then
    tt:AddLine(dragHint, mr, mg, mb)
  end
end

local function EnsureSettingDefault()
  if WF and WF.DB and WF.DB.GetSetting and WF.DB.SetSetting then
    if WF.DB:GetSetting("showMinimapButton") == nil then
      WF.DB:SetSetting("showMinimapButton", true)
    end
  end
end

local function ShouldShow()
  EnsureSettingDefault()
  return WF.DB and WF.DB.GetSetting and WF.DB:GetSetting("showMinimapButton") == true
end

local function ToggleMain()
  if WF and WF.UI and WF.UI.Main and WF.UI.Main.Toggle then
    WF.UI.Main:Toggle()
  end
end

local function ShowSettings()
  if WF and WF.UI and WF.UI.Help and WF.UI.Help.Show then
    WF.UI.Help:Show("Settings")
  end
end

local function RefreshTooltipIfOwnedByMinimapButton()
  if not GameTooltip or not GameTooltip:IsShown() then
    return
  end

  local owner = GameTooltip.GetOwner and GameTooltip:GetOwner() or nil
  local libBtn = _G["LibDBIcon10_" .. LDB_NAME]
  local fallbackBtn = Mini and Mini._btn or nil
  if not owner then
    return
  end
  if owner ~= libBtn and owner ~= fallbackBtn then
    return
  end

  GameTooltip:ClearLines()
  if owner == libBtn then
    _BuildTooltip(GameTooltip, _Accent("Shift + drag") .. ": Move")
  else
    _BuildTooltip(GameTooltip, "Shift + drag: Move")
  end
  GameTooltip:Show()
end

-- ---------------------------------------------------------
-- Utility: enforce ONE visible button
-- ---------------------------------------------------------
local function KillFrame(frame)
  if not frame then
    return
  end
  if frame.Hide then
    frame:Hide()
  end
  frame.Show = function() end
  if frame.SetScript then
    frame:SetScript("OnShow", frame.Hide)
  end
  if frame.UnregisterAllEvents then
    frame:UnregisterAllEvents()
  end
  if frame.SetParent then
    frame:SetParent(UIParent)
  end
end

local function KillManual()
  if Mini._btn then
    KillFrame(Mini._btn)
    Mini._btn = nil
  end
  local f = _G["WF_MinimapButton"]
  if f then
    KillFrame(f)
  end
end

local function KillLib()
  local btn = _G["LibDBIcon10_" .. LDB_NAME]
  if btn then
    KillFrame(btn)
  end
  if LibStub then
    local dbi = LibStub:GetLibrary("LibDBIcon-1.0", true)
    if dbi and dbi.IsRegistered and dbi:IsRegistered(LDB_NAME) then
      pcall(dbi.Hide, dbi, LDB_NAME)
    end
  end
  Mini._ldbObj = nil
  Mini._ldbIcon = nil
end

-- ---------------------------------------------------------
-- LibDBIcon implementation (preferred)
-- ---------------------------------------------------------
local function AcquireLibs()
  if not LibStub then
    return nil, nil
  end
  local ldb = LibStub:GetLibrary("LibDataBroker-1.1", true)
  local dbi = LibStub:GetLibrary("LibDBIcon-1.0", true)
  return ldb, dbi
end

local function NormalizeAngleDeg(deg)
  deg = tonumber(deg) or 0
  deg = deg % 360
  if deg < 0 then
    deg = deg + 360
  end
  return deg
end

local function AngleFromOffset(dx, dy)
  dx = tonumber(dx) or 0
  dy = tonumber(dy) or 0

  if dx == 0 and dy == 0 then
    return 0
  end

  if math.atan2 then
    return math.deg(math.atan2(dy, dx))
  end

  if dx == 0 then
    if dy > 0 then
      return 90
    end
    return 270
  end

  local ang = math.deg(math.atan(dy / dx))
  if dx < 0 then
    ang = ang + 180
  elseif dy < 0 then
    ang = ang + 360
  end
  return ang
end

local function UpdateAngleFromCursor(db)
  if not db or not Minimap then
    return
  end

  local scale = Minimap.GetEffectiveScale and Minimap:GetEffectiveScale() or 1
  if not scale or scale == 0 then
    scale = 1
  end

  local cx, cy = GetCursorPosition()
  cx, cy = cx / scale, cy / scale

  local mx, my = Minimap:GetCenter()
  if not mx or not my then
    return
  end

  local dx, dy = cx - mx, cy - my
  local ang = AngleFromOffset(dx, dy)
  db.minimap.minimapPos = NormalizeAngleDeg(ang)
end

local function ApplyLibIconLayout(btn)
  if not btn then
    return
  end

  local tex = btn.icon or (btn.GetNormalTexture and btn:GetNormalTexture())
  if not tex then
    return
  end

  tex:SetTexture(ICON)
  local c = LIB_TEX_CROP
  tex:SetTexCoord(c, 1 - c, c, 1 - c)

  -- Eliminate common "black icon" causes.
  tex:SetVertexColor(1, 1, 1, 1)
  if tex.SetDesaturated then
    tex:SetDesaturated(false)
  end

  -- Fix the "tiny icon inside large ring" by overriding anchors.
  tex:ClearAllPoints()
  tex:SetPoint("TOPLEFT", btn, "TOPLEFT", LIB_ICON_PAD, -LIB_ICON_PAD)
  tex:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -LIB_ICON_PAD, LIB_ICON_PAD)

  -- If a skin re-applies its own points/coords after we do, re-assert on show.
  if not btn._wfHooked then
    btn._wfHooked = true
    btn:HookScript("OnShow", function(self)
      if C_Timer and C_Timer.After then
        C_Timer.After(0, function()
          ApplyLibIconLayout(self)
        end)
      else
        ApplyLibIconLayout(self)
      end
    end)
  end
end

local function StyleLibButton(dbi, db)
  local btn = _G["LibDBIcon10_" .. LDB_NAME]
  if not btn then
    return
  end

  ApplyLibIconLayout(btn)

  -- Shift + drag only, stable math.
  btn:RegisterForDrag("LeftButton")
  btn:SetScript("OnDragStart", function(self)
    if not IsShiftKeyDown() then
      return
    end
    self._wfDragging = true
    UpdateAngleFromCursor(db)
    if dbi and dbi.Refresh then
      dbi:Refresh(LDB_NAME, db.minimap)
    end
    self:SetScript("OnUpdate", function()
      UpdateAngleFromCursor(db)
      if dbi and dbi.Refresh then
        dbi:Refresh(LDB_NAME, db.minimap)
      end
    end)
  end)

  btn:SetScript("OnDragStop", function(self)
    self._wfDragging = false
    self:SetScript("OnUpdate", nil)
  end)
end

local function EnsureLDB()
  if Mini._ldbObj and Mini._ldbIcon then
    return true
  end

  local ldb, dbi = AcquireLibs()
  if not ldb or not dbi then
    return false
  end

  local db = GetDB()
  if not db then
    return false
  end

  db.minimap = db.minimap or {}
  if db.minimap.hide == nil then
    db.minimap.hide = false
  end
  if db.minimap.minimapPos == nil then
    db.minimap.minimapPos = 220
  end

  local obj = ldb:NewDataObject(LDB_NAME, {
    type = "launcher",
    text = "What Farm?",
    icon = ICON,
  })

  obj.OnClick = function(_, button)
    if button == "LeftButton" then
      ToggleMain()
    else
      ShowSettings()
    end
  end

  obj.OnTooltipShow = function(tt)
    if not tt or not tt.AddLine then
      return
    end
    if tt.ClearLines then
      tt:ClearLines()
    end
    _BuildTooltip(tt, _Accent("Shift + drag") .. ": Move")
  end

  Mini._ldbObj = obj
  Mini._ldbIcon = dbi

  db.minimap.hide = not ShouldShow()

  if dbi.IsRegistered and dbi:IsRegistered(LDB_NAME) then
    dbi:Refresh(LDB_NAME, db.minimap)
  else
    dbi:Register(LDB_NAME, obj, db.minimap)
  end

  -- Enforce ONE button.
  KillManual()

  -- Style the LibDBIcon button after it exists (skins may apply right after Register).
  if C_Timer and C_Timer.After then
    C_Timer.After(0, function()
      StyleLibButton(dbi, db)
    end)
    C_Timer.After(0.2, function()
      StyleLibButton(dbi, db)
    end)
  else
    StyleLibButton(dbi, db)
  end

  return true
end

-- ---------------------------------------------------------
-- Manual fallback (no libs)
-- ---------------------------------------------------------
local MinimapShapes = {
  ROUND = { true, true, true, true },
  SQUARE = { false, false, false, false },
  ["CORNER-TOPLEFT"] = { false, false, false, true },
  ["CORNER-TOPRIGHT"] = { false, false, true, false },
  ["CORNER-BOTTOMLEFT"] = { false, true, false, false },
  ["CORNER-BOTTOMRIGHT"] = { true, false, false, false },
  ["SIDE-LEFT"] = { false, true, false, true },
  ["SIDE-RIGHT"] = { true, false, true, false },
  ["SIDE-TOP"] = { false, false, true, true },
  ["SIDE-BOTTOM"] = { true, true, false, false },
  ["TRICORNER-TOPLEFT"] = { false, true, true, true },
  ["TRICORNER-TOPRIGHT"] = { true, false, true, true },
  ["TRICORNER-BOTTOMLEFT"] = { true, true, false, true },
  ["TRICORNER-BOTTOMRIGHT"] = { true, true, true, false },
}

local function GetShape()
  if GetMinimapShape then
    local ok, shape = pcall(GetMinimapShape)
    if ok and shape then
      return shape
    end
  end
  return "ROUND"
end

local function ClampXY(x, y, radius)
  local shape = MinimapShapes[GetShape()] or MinimapShapes.ROUND

  local q = 1
  if x < 0 then q = q + 1 end
  if y < 0 then q = q + 2 end

  if not shape[q] then
    local diag = radius * 0.70710678
    if x > diag then x = diag end
    if x < -diag then x = -diag end
    if y > diag then y = diag end
    if y < -diag then y = -diag end
  end

  return x, y
end

local function UpdateFallbackPosition()
  local btn = Mini._btn
  if not btn or not Minimap then
    return
  end

  local db = GetDB()
  if not db then
    return
  end

  local pos = NormalizeAngleDeg(db.minimap and db.minimap.minimapPos or 220)
  local angle = math.rad(pos)

  local radius = (Minimap:GetWidth() / 2) + FALLBACK_RADIUS_PAD
  local x = math.cos(angle) * radius
  local y = math.sin(angle) * radius
  x, y = ClampXY(x, y, radius)

  btn:ClearAllPoints()
  btn:SetPoint("CENTER", Minimap, "CENTER", x, y)
end

local function CreateFallback()
  if Mini._btn or not Minimap then
    return
  end

  -- Enforce ONE button.
  KillLib()

  local db = GetDB()
  if db then
    db.minimap = db.minimap or {}
    if db.minimap.hide == nil then
      db.minimap.hide = false
    end
    if db.minimap.minimapPos == nil then
      db.minimap.minimapPos = 220
    end
    db.minimap.hide = not ShouldShow()
    db.minimap.minimapPos = NormalizeAngleDeg(db.minimap.minimapPos)
  end

  local btn = CreateFrame("Button", "WF_MinimapButton", Minimap)
  btn:SetSize(FALLBACK_SIZE, FALLBACK_SIZE)
  btn:SetFrameStrata("MEDIUM")
  btn:SetFrameLevel((Minimap.GetFrameLevel and Minimap:GetFrameLevel() or 1) + 25)
  btn:SetClampedToScreen(true)
  btn:SetHitRectInsets(-6, -6, -6, -6)

  local icon = btn:CreateTexture(nil, "ARTWORK")
  icon:SetPoint("TOPLEFT", btn, "TOPLEFT", FALLBACK_ICON_INSET, -FALLBACK_ICON_INSET)
  icon:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -FALLBACK_ICON_INSET, FALLBACK_ICON_INSET)
  icon:SetTexture(ICON)
  local c = LIB_TEX_CROP
  icon:SetTexCoord(c, 1 - c, c, 1 - c)
  icon:SetVertexColor(1, 1, 1, 1)
  if icon.SetDesaturated then
    icon:SetDesaturated(false)
  end
  btn.icon = icon

  if btn.CreateMaskTexture and icon.AddMaskTexture then
    local mask = btn:CreateMaskTexture()
    mask:SetTexture("Interface\\CHARACTERFRAME\\TempPortraitAlphaMask", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
    mask:SetAllPoints(icon)
    icon:AddMaskTexture(mask)
    btn._mask = mask
  end

  btn:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight", "ADD")

  btn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
  btn:SetScript("OnClick", function(_, b)
    if b == "LeftButton" then
      ToggleMain()
    else
      ShowSettings()
    end
  end)

  btn:RegisterForDrag("LeftButton")
  btn:SetScript("OnDragStart", function(self)
    if not IsShiftKeyDown() then
      return
    end
    self._wfDragging = true
    local d = GetDB()
    if d then
      UpdateAngleFromCursor(d)
      UpdateFallbackPosition()
    end
    self:SetScript("OnUpdate", function()
      local d = GetDB()
      if not d then
        return
      end
      UpdateAngleFromCursor(d)
      UpdateFallbackPosition()
    end)
  end)

  btn:SetScript("OnDragStop", function(self)
    self._wfDragging = false
    self:SetScript("OnUpdate", nil)
  end)

  btn:SetScript("OnEnter", function(self)
    local Widgets = WF and WF.UI and WF.UI.Widgets
    if Widgets and Widgets.EnsureTooltipSkin then Widgets:EnsureTooltipSkin() end
    GameTooltip:SetOwner(self, "ANCHOR_LEFT")
    GameTooltip:ClearLines()
    _BuildTooltip(GameTooltip, "Shift + drag: Move")
    GameTooltip:Show()
  end)

  btn:SetScript("OnLeave", function()
    GameTooltip:Hide()
  end)

  Mini._btn = btn
  UpdateFallbackPosition()
end

-- ---------------------------------------------------------
-- Public API
-- ---------------------------------------------------------
function Mini:SetShown(show)
  EnsureSettingDefault()
  show = show and true or false

  local db = GetDB()
  if db and db.minimap then
    db.minimap.hide = not show
  end

  if Mini._ldbIcon and Mini._ldbObj then
    if show then
      Mini._ldbIcon:Show(LDB_NAME)
    else
      Mini._ldbIcon:Hide(LDB_NAME)
    end

    -- Re-assert our icon layout in case a minimap skin addon touched it.
    local btn = _G["LibDBIcon10_" .. LDB_NAME]
    if btn then
      ApplyLibIconLayout(btn)
    end
    return
  end

  if Mini._btn then
    Mini._btn:SetShown(show)
  end
end

function Mini:Create()
  EnsureSettingDefault()

  if EnsureLDB() then
    Mini:SetShown(ShouldShow())
    return
  end

  CreateFallback()
  Mini:SetShown(ShouldShow())
end

function Mini:Refresh()
  if EnsureLDB() then
    Mini:SetShown(ShouldShow())
    RefreshTooltipIfOwnedByMinimapButton()
    return
  end

  if Mini._btn then
    UpdateFallbackPosition()
    Mini._btn:SetShown(ShouldShow())
  end

  RefreshTooltipIfOwnedByMinimapButton()
end


local function RegisterAutoRefreshEvents()
  if Mini._refreshEventsRegistered then
    return
  end
  Mini._refreshEventsRegistered = true

  if not (WF and WF.Events and WF.Events.On) then
    return
  end

  local function RefreshNow()
    if Mini and Mini.Refresh then
      Mini:Refresh()
    end
  end

  WF.Events:On("PLAYER_ENTERING_WORLD", RefreshNow)
  WF.Events:On("ZONE_CHANGED", RefreshNow)
  WF.Events:On("ZONE_CHANGED_INDOORS", RefreshNow)
  WF.Events:On("ZONE_CHANGED_NEW_AREA", RefreshNow)
end

RegisterAutoRefreshEvents()
