if not WeakAuras.IsLibsOK() then return end
local AddonName = ...
local Private = select(2, ...)

local WeakAuras = WeakAuras
local L = WeakAuras.L
local prettyPrint = WeakAuras.prettyPrint
local LGF = LibStub("LibGetFrame-1.0")

local profileData = {}
profileData.systems = {}
profileData.auras = {}

local currentProfileState, ProfilingTimer

local RealTimeProfilingWindow = CreateFrame("Frame", "WeakAurasRealTimeProfiling", UIParent)
WeakAuras.XMLTemplates["PortraitFrameTemplate"](RealTimeProfilingWindow)
RealTimeProfilingWindow:HidePortrait(RealTimeProfilingWindow)
Private.frames["RealTime Profiling Window"] = RealTimeProfilingWindow
RealTimeProfilingWindow.width = 500
RealTimeProfilingWindow.height = 300
RealTimeProfilingWindow.barHeight = 20
RealTimeProfilingWindow.titleHeight = 20
RealTimeProfilingWindow.statsHeight = 15
RealTimeProfilingWindow.buttonsHeight = 22
RealTimeProfilingWindow.bars = {}
RealTimeProfilingWindow:SetMovable(true)
RealTimeProfilingWindow:EnableMouse(true)
RealTimeProfilingWindow:Hide()
WeakAuras.RealTimeProfilingWindow = RealTimeProfilingWindow

local table_to_string
table_to_string = function(tbl, depth)
  if depth and depth >= 3 then
    return "{ ... }"
  end
  local str
  for k, v in pairs(tbl) do
    if type(v) ~= "userdata" then
      if type(v) == "table" then
        v = table_to_string(v, (depth and depth + 1 or 1))
      elseif type(v) == "function" then
        v = "function"
      elseif type(v) == "string" then
        v = '"'.. v ..'"'
      end

      if type(k) == "string" then
        k = '"' .. k ..'"'
      end

      str = (str and str .. "|cff999999,|r " or "|cff999999{|r ") .. "|cffffff99["
            .. tostring(k) .. "]|r |cff999999=|r |cffffffff" .. tostring(v) .. "|r"
    end
  end
  return (str or "{ ") .. " }"
end

local profilePopup
local function CreateProfilePopup()
  local frame = CreateFrame("Frame", "WeakAurasProfilingReport", UIParent)
  WeakAuras.XMLTemplates["PortraitFrameTemplate"](frame)
  frame:HidePortrait(frame)
  WeakAurasProfilingReportTitleText:SetText(L["WeakAuras Profiling Report"])
  frame:SetMovable(true)
  frame:SetSize(450, 300)

  frame:SetScript("OnMouseDown", function(self, button)
    if button == "LeftButton" and not self.is_moving then
      self:StartMoving()
      self.is_moving = true
    elseif button == "RightButton" then
      self:Stop()
    end
  end)

  frame:SetScript("OnMouseUp", function(self, button)
    if button == "LeftButton" and self.is_moving then
      self:StopMovingOrSizing()
      local xOffset = self:GetLeft()
      local yOffset = self:GetTop() - GetScreenHeight()
      WeakAurasSaved.ProfilingWindow = WeakAurasSaved.ProfilingWindow or {}
      WeakAurasSaved.ProfilingWindow.xOffset = xOffset
      WeakAurasSaved.ProfilingWindow.yOffset = yOffset
      self.is_moving = nil
    end
  end)

  local scrollFrame = CreateFrame("ScrollFrame", "WeakAurasProfilingReportScrollFrame", frame, "UIPanelScrollFrameTemplate")
  scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 10, -28)
  scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -27, 15)

  local messageFrame = CreateFrame("EditBox", nil, scrollFrame)
  frame.messageFrame = messageFrame
  messageFrame:SetMultiLine(true)
  messageFrame:SetAutoFocus(false)
  messageFrame:SetFontObject(ChatFontNormal)
  messageFrame:SetSize(440, 260)
  messageFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, -5)
  messageFrame:SetPoint("BOTTOMRIGHT", scrollFrame, "BOTTOMRIGHT")
  messageFrame:Show()
  messageFrame:SetScript("OnChar", function() messageFrame:SetText(messageFrame.originalText) end)

  function frame:AddText(v)
    if not v then return end
    local m = self.messageFrame:GetText()
    if m ~= "" then
      m = m .. "|n"
    end
    if type(v) == "table" then
      v = table_to_string(v)
    end
    self.messageFrame.originalText = m .. v
    self.messageFrame:SetText(self.messageFrame.originalText)
  end

  scrollFrame:SetHitRectInsets(-8, -8, -8, -8)
  scrollFrame:SetScrollChild(messageFrame)

  profilePopup = frame
end

local function ProfilePopup()
  -- create/get and return reference to profile EditBox
  if not profilePopup then
    CreateProfilePopup()
  end

  profilePopup:Hide()
  return profilePopup
end

local function StartProfiling(map, id)
  if not map[id] then
    map[id] = {}
    map[id].count = 1
    map[id].start = debugprofilestop()
    map[id].elapsed = 0
    map[id].spike = 0
    return
  end

  if map[id].count == 0 then
    map[id].count = 1
    map[id].start = debugprofilestop()
  else
    map[id].count = map[id].count + 1
  end
end

local function StopProfiling(map, id)
  map[id].count = map[id].count - 1
  if map[id].count == 0 then
    local elapsed = debugprofilestop() - map[id].start
    map[id].elapsed = map[id].elapsed + elapsed
    if elapsed > map[id].spike then
      map[id].spike = elapsed
    end
  end
end

local function StartProfileSystem(system)
  StartProfiling(profileData.systems, "wa")
  StartProfiling(profileData.systems, system)
end

local function StartProfileAura(id)
  StartProfiling(profileData.auras, id)
end

local function StopProfileSystem(system)
  StopProfiling(profileData.systems, "wa")
  StopProfiling(profileData.systems, system)
end

local function StopProfileAura(id)
  StopProfiling(profileData.auras, id)
end

local function StartProfileUID(uid)
  StartProfiling(profileData.auras, Private.UIDtoID(uid))
end

local function StopProfileUID(uid)
  StopProfiling(profileData.auras, Private.UIDtoID(uid))
end

function Private.ProfileRenameAura(oldid, id)
  profileData.auras[id] = profileData.auras[id]
  profileData.auras[oldid] = nil
end

local RegisterProfile = function(startType)
  if startType == "boss" then startType = "encounter" end
  local delayedStart
  if startType == "encounter" then
    RealTimeProfilingWindow:UnregisterAllEvents()
    prettyPrint(L["Your next instance of combat will automatically be profiled."])
    RealTimeProfilingWindow:RegisterEvent("PLAYER_REGEN_DISABLED")
    RealTimeProfilingWindow:RegisterEvent("PLAYER_REGEN_ENABLED")
    currentProfileState = startType
    delayedStart = true
  elseif startType == "combat" then
    RealTimeProfilingWindow:UnregisterAllEvents()
    prettyPrint(L["Your next instance of combat will automatically be profiled."])
    RealTimeProfilingWindow:RegisterEvent("PLAYER_REGEN_DISABLED")
    RealTimeProfilingWindow:RegisterEvent("PLAYER_REGEN_ENABLED")
    currentProfileState = startType
    delayedStart = true
  elseif startType == "autostart" then
    prettyPrint(L["Profiling automatically started."])
    currentProfileState = "profiling"
  elseif startType and startType:match("%d") then
    RealTimeProfilingWindow:UnregisterAllEvents()
    local time = startType + 0
    prettyPrint(L["Profiling started. It will end automatically in %d seconds"]:format(time))
    ProfilingTimer = WeakAuras.timer:ScheduleTimer(WeakAuras.StopProfile, time)
    currentProfileState = "profiling"
  else
    RealTimeProfilingWindow:UnregisterAllEvents()
    prettyPrint(L["Profiling started."])
    currentProfileState = "profiling"
  end
  RealTimeProfilingWindow:UpdateButtons()
  return delayedStart
end

function WeakAuras.StartProfile(startType)
  if currentProfileState == "profiling" then
    prettyPrint(L["Profiling already started."])
    return
  end

  if RegisterProfile(startType) then
    -- Scheduled for later
    return
  end

  profileData.systems = {}
  profileData.auras = {}
  profileData.systems.time = {}
  profileData.systems.time.start = debugprofilestop()
  profileData.systems.time.count = 1

  Private.StartProfileSystem = StartProfileSystem
  Private.StartProfileAura = StartProfileAura
  Private.StartProfileUID = StartProfileUID
  Private.StopProfileSystem = StopProfileSystem
  Private.StopProfileAura = StopProfileAura
  Private.StopProfileUID = StopProfileUID
  LGF.StartProfile()
end

local function doNothing()
end

function WeakAuras.StopProfile()
  if (currentProfileState ~= "profiling") then
    prettyPrint(L["Profiling not running."])
    return
  end

  prettyPrint(L["Profiling stopped."])

  profileData.systems.time.elapsed = debugprofilestop() - profileData.systems.time.start
  profileData.systems.time.count = 0

  Private.StartProfileSystem = doNothing
  Private.StartProfileAura = doNothing
  Private.StartProfileUID = doNothing
  Private.StopProfileSystem = doNothing
  Private.StopProfileAura = doNothing
  Private.StopProfileUID = doNothing
  LGF.StopProfile()

  currentProfileState = nil
  RealTimeProfilingWindow:UnregisterAllEvents()
  RealTimeProfilingWindow:UpdateButtons()
  if ProfilingTimer then
    WeakAuras.timer:CancelTimer(ProfilingTimer)
    ProfilingTimer = nil
  end
end

function WeakAuras.ToggleProfile()
  if (not profileData.systems.time or profileData.systems.time.count ~= 1) then
    WeakAuras.StartProfile()
  else
    WeakAuras.StopProfile()
  end
end

local function CancelScheduledProfile()
  prettyPrint(L["Your scheduled automatic profile has been cancelled."])
  currentProfileState = nil
  RealTimeProfilingWindow:UnregisterAllEvents()
  RealTimeProfilingWindow:UpdateButtons()
end

WeakAuras.CancelScheduledProfile = CancelScheduledProfile

local function AutoStartStopProfiling(frame, event)
  if event == "PLAYER_REGEN_DISABLED" then
    WeakAuras.StartProfile("autostart")
  elseif event == "PLAYER_REGEN_ENABLED" then
    WeakAuras.StopProfile()
  end
end
RealTimeProfilingWindow:SetScript("OnEvent", AutoStartStopProfiling)

local function PrintOneProfile(popup, name, map, total)
  if map.count ~= 0 then
    popup:AddText(name .. "  ERROR: count is not zero:" .. " " .. map.count)
  end
  local percent = ""
  if total then
    percent = (", %.2f%%"):format(100 * map.elapsed / total)
  end

  local spikeInfo = ""
  if map.spike then
    local r, g, b
    if map.spike < 2 then
      r, g, b = WeakAuras.GetHSVTransition(map.spike / 2, 0, 1, 0, 1, 1, 1, 0, 1)
    elseif map.spike < 2.5 then
      r, g, b = WeakAuras.GetHSVTransition((map.spike - 2) * 2, 1, 1, 0, 1, 1, 0.65, 0, 1)
    elseif map.spike < 3 then
      r, g, b = WeakAuras.GetHSVTransition((map.spike - 2.5) * 2, 1, 0.65, 0, 1, 1, 0, 0, 1)
    else
      r, g, b = 1, 0, 0
    end
    spikeInfo = ("|cff%02x%02x%02x(%.2fms)|r"):format(r * 255, g * 255, b * 255, map.spike)
  end

  popup:AddText(("%s |cff999999%.2fms%s %s|r"):format(name, map.elapsed, percent, spikeInfo))
end

local function SortProfileMap(map)
  local result = {}
  for k, v in pairs(map) do
    tinsert(result, k)
  end

  sort(result, function(a, b)
    if map[a].spike and map[b].spike then
      return map[a].spike > map[b].spike
    end
    return map[a].elapsed > map[b].elapsed
  end)

  return result
end

local function TotalProfileTime(map)
  local total = 0
  for k, v in pairs(map) do
    total = total + v.elapsed
  end
  return total
end

local function unitEventToMultiUnit(event)
  local count
  event, count = event:gsub("nameplate%d+$", "nameplate")
  if count == 1 then return event end
  event, count = event:gsub("boss%d$", "boss")
  if count == 1 then return event end
  event, count = event:gsub("arena%d$", "arena")
  if count == 1 then return event end
  event, count = event:gsub("raid%d+$", "group")
  if count == 1 then return event end
  event, count = event:gsub("raidpet%d+$", "group")
  if count == 1 then return event end
  event, count = event:gsub("party%d$", "party")
  if count == 1 then return event end
  event, count = event:gsub("partypet%d$", "party")
  return event
end

function WeakAuras.PrintProfile()
  local popup = ProfilePopup()
  if not profileData.systems.time then
    prettyPrint(L["No Profiling information saved."])
    return
  end

  if profileData.systems.time.count == 1 then
    prettyPrint(L["Profiling still running, stop before trying to print."])
    return
  end

  if WeakAurasRealTimeProfiling and WeakAurasRealTimeProfiling:IsShown() then
    popup:ClearAllPoints()
    popup:SetPoint("TOPLEFT", WeakAurasRealTimeProfiling, "TOPRIGHT", 5, 0)
  else
    if WeakAurasSaved.ProfilingWindow then
      popup:SetPoint("TOPLEFT", UIParent, "TOPLEFT", WeakAurasSaved.ProfilingWindow.xOffset or 0,
                                                     WeakAurasSaved.ProfilingWindow.yOffset or 0)
    else
      popup:SetPoint("CENTER")
    end
  end

  popup.messageFrame:SetText("")

  PrintOneProfile(popup, "|cff9900ffTotal time:|r", profileData.systems.time)
  PrintOneProfile(popup, "|cff9900ffTime inside WA:|r", profileData.systems.wa)
  popup:AddText(string.format("|cff9900ffTime spent inside WA:|r %.2f%%",
                              100 * profileData.systems.wa.elapsed / profileData.systems.time.elapsed))

  popup:AddText("")
  popup:AddText("Note: Not every aspect of each aura can be tracked.")
  popup:AddText("You can ask on our discord https://discord.gg/classlesswow for help interpreting this output.")

  popup:AddText("")
  popup:AddText("|cff9900ffAuras:|r")
  local total = TotalProfileTime(profileData.auras)
  popup:AddText("Total time attributed to auras: ", floor(total) .."ms")
  for i, k in ipairs(SortProfileMap(profileData.auras)) do
    PrintOneProfile(popup, k, profileData.auras[k], total)
  end

  popup:AddText("")
  popup:AddText("|cff9900ffSystems:|r")

  -- make a new table for system data with multiUnits grouped
  local systemRegrouped = {}
  for k, v in pairs(profileData.systems) do
    local event = unitEventToMultiUnit(k)
    if systemRegrouped[event] == nil then
      systemRegrouped[event] = CopyTable(v)
    else
      if v.elapsed then
        systemRegrouped[event].elapsed = (systemRegrouped[event].elapsed or 0) + v.elapsed
      end
      if v.spike then
        systemRegrouped[event].spike = (systemRegrouped[event].spike or 0) + v.spike
      end
    end
  end

  for i, k in ipairs(SortProfileMap(systemRegrouped)) do
    if (k ~= "time" and k ~= "wa") then
      PrintOneProfile(popup, k, systemRegrouped[k], profileData.systems.wa.elapsed)
    end
  end

  popup:AddText("")
  popup:AddText("|cff9900ffLibGetFrame:|r")
  for id, map in pairs(LGF.GetProfileData()) do
    PrintOneProfile(popup, id, map)
  end

  popup:Show()
end

local texture = "Interface\\DialogFrame\\UI-DialogBox-Background"
local margin = 5
function RealTimeProfilingWindow:GetBar(name)
  if self.bars[name] then
    return self.bars[name]
  else
    local bar = CreateFrame("Frame", nil, self.barsFrame)
    self.bars[name] = bar
    WeakAuras.Mixin(bar, Private.SmoothStatusBarMixin)
    bar.name = name
    bar.parent = self
    bar:SetHeight(self.barHeight)

    local fg = bar:CreateTexture(nil, "ARTWORK")
    fg:SetTexture(texture)
    fg:SetDrawLayer("ARTWORK", 0)
    fg:ClearAllPoints()
    fg:SetPoint("TOPLEFT", bar)
    fg:SetHeight(self.barHeight)
    fg:Show()
    bar.fg = fg

    local bg = bar:CreateTexture(nil, "ARTWORK")
    bg:SetTexture(texture)
    bg:SetDrawLayer("ARTWORK", -1)
    bg:SetAllPoints()
    bg:Show()
    bar.bg = bg

    local txtName = bar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    bar.txtName = txtName
    txtName:SetPoint("TOPLEFT", bar, "TOPLEFT", margin, 0)
    txtName:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", -30, 0)
    txtName:SetJustifyH("LEFT")

    local txtPct = bar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    bar.txtPct = txtPct
    txtPct:SetPoint("TOPLEFT", bar, "TOPRIGHT", -55, 0)
    txtPct:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", - margin, 0)
    txtPct:SetJustifyH("RIGHT")

    function bar:SetValue(value)
      self.fg:SetWidth(self.parent.width / 100 * value)
    end

    function bar:SetText(time, pct, spike)
      self.txtName:SetText(("%s (%.2fms||%.2fms)"):format(self.name, time, spike))
      self.txtPct:SetText(("%.2f%%"):format(pct))
    end

    function bar:GetMinMaxValues()
      return 0, 100
    end

    function bar:GetValue()
      return self.value
    end

    function bar:SetProgress(value)
      self.value = value
      self:SetSmoothedValue(value)
    end

    function bar:SetPosition(pos)
      if self.parent.barHeight * pos >
         self.parent.height - self.parent.titleHeight - self.parent.statsHeight - self.parent.buttonsHeight
      then
        self:Hide()
      else
        self:ClearAllPoints()
        self:SetPoint("TOPLEFT", self.parent.barsFrame, "TOPLEFT", 0, - (pos - 1) * self.parent.barHeight)
        self:SetPoint("RIGHT", self.parent.barsFrame, "RIGHT")
        if pos % 2 == 0 then
          bar.fg:SetTexture(0.7, 0.7, 0.7, 0.7)
          bar.bg:SetTexture(0, 0, 0, 0.2)
        else
          bar.fg:SetTexture(0.5, 0.5, 0.5, 0.7)
          bar.bg:SetTexture(0, 0, 0, 0.4)
        end
        self:Show()
      end
    end

    return bar
  end
end

function RealTimeProfilingWindow:RefreshBars()
  if not profileData.systems.time or profileData.systems.time.count == 0 then
    return
  end

  local total = TotalProfileTime(profileData.auras)
  for i, name in ipairs(SortProfileMap(profileData.auras)) do
    if (name ~= "time" and name ~= "wa") then
      local bar = self:GetBar(name)
      local elapsed = profileData.auras[name].elapsed
      local pct = 100 * elapsed / total
      local spike = profileData.auras[name].spike
      bar:SetPosition(i)
      bar:SetProgress(pct)
      bar:SetText(elapsed, pct, spike)
    end
  end
  if profileData.systems.wa then
    local timespent = debugprofilestop() - profileData.systems.time.start
    self.statsFrameText:SetText(("|cFFFFFFFFTime in WA: %.2fs / %ds (%.1f%%)"):format(
      profileData.systems.wa.elapsed / 1000,
      timespent / 1000,
      100 * profileData.systems.wa.elapsed / timespent
    ))
  end
end

function RealTimeProfilingWindow:ResetBars()
  for k, v in pairs(self.bars) do
    v:Hide()
  end
end

function RealTimeProfilingWindow:Init()
  self:ClearAllPoints()
  self:SetSize(self.width, self.height)
  self:SetClampedToScreen(true)

  if WeakAurasSaved.RealTimeProfilingWindow then
    self:SetPoint("TOPLEFT", UIParent, "TOPLEFT",
                  WeakAurasSaved.RealTimeProfilingWindow.xOffset or 0,
                  WeakAurasSaved.RealTimeProfilingWindow.yOffset or 0)
  else
    self:SetPoint("TOPLEFT", UIParent, "TOPLEFT")
  end
  self:Show()

  WeakAurasRealTimeProfilingTitleText:SetText(L["WeakAuras Profiling"])

  local barsFrame = CreateFrame("Frame", nil, self)
  self.barsFrame = barsFrame
  barsFrame:SetPoint("TOPLEFT", 7, -20)
  barsFrame:SetPoint("BOTTOMRIGHT", -3, 30)
  barsFrame:Show()

  local statsFrameText = self:CreateFontString(nil, "OVERLAY", "GameFontNormal")
  self.statsFrameText = statsFrameText
  statsFrameText:SetPoint("BOTTOMLEFT", 15, 25)

  local minimizeButton = CreateFrame("Button", nil, self)
  WeakAuras.XMLTemplates["MaximizeMinimizeButtonFrameTemplate"](minimizeButton)
  minimizeButton:SetPoint("RIGHT", self.CloseButton, "LEFT")
  minimizeButton:SetOnMaximizedCallback(function()
    self.minimized = false
    self.barsFrame:Show()
    self.toggleButton:Show()
    self.reportButton:Show()
    self.combatButton:Show()
    self.encounterButton:Show()
    self.statsFrameText:Show()
    self:ClearAllPoints()
    self:SetPoint("TOPRIGHT", UIParent, "BOTTOMLEFT", self.right, self.top)
    self:SetHeight(self.prevHeight)
  end)
  minimizeButton:SetOnMinimizedCallback(function()
    self.minimized = true
    self.barsFrame:Hide()
    self.toggleButton:Hide()
    self.reportButton:Hide()
    self.combatButton:Hide()
    self.encounterButton:Hide()
    self.statsFrameText:Hide()
    self.right, self.top = self:GetRight(), self:GetTop()
    self:ClearAllPoints()
    self:SetPoint("TOPRIGHT", UIParent, "BOTTOMLEFT", self.right, self.top)
    self.prevHeight = self:GetHeight()
    self:SetHeight(60)
  end)

  local width = 120
  local spacing = 2

  local toggleButton = CreateFrame("Button", nil, self, "UIPanelButtonTemplate")
  self.toggleButton = toggleButton
  toggleButton:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -spacing, spacing)
  toggleButton:SetFrameLevel(self:GetFrameLevel() + 1)
  toggleButton:SetHeight(20)
  toggleButton:SetWidth(width)
  toggleButton:SetText(L["Start Now"])
  toggleButton:SetScript("OnClick", function(self)
    local parent = self:GetParent()
    if (not profileData.systems.time or profileData.systems.time.count ~= 1) then
      parent:ResetBars()
      WeakAuras.StartProfile()
    else
      WeakAuras.StopProfile()
    end
  end)


  local reportButton = CreateFrame("Button", nil, self, "UIPanelButtonTemplate")
  self.reportButton = reportButton
  reportButton:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", spacing, spacing)
  reportButton:SetFrameLevel(self:GetFrameLevel() + 1)
  reportButton:SetHeight(20)
  reportButton:SetWidth(width)
  reportButton:SetText(L["Report Summary"])
  reportButton:SetScript("OnClick", function(self)
    WeakAuras.PrintProfile()
  end)
  reportButton:Hide()

  local combatButton = CreateFrame("Button", nil, self, "UIPanelButtonTemplate")
  self.combatButton = combatButton
  combatButton:SetPoint("BOTTOMRIGHT", -spacing - width , spacing)
  combatButton:SetFrameLevel(self:GetFrameLevel() + 1)
  combatButton:SetHeight(20)
  combatButton:SetWidth(width)
  combatButton:SetScript("OnClick", function(self)
    local parent = self:GetParent()
    parent:ResetBars()
    if currentProfileState ~= "combat" then
      WeakAuras.StartProfile("combat")
    else
      CancelScheduledProfile()
    end
  end)

  local encounterButton = CreateFrame("Button", nil, self, "UIPanelButtonTemplate")
  self.encounterButton = encounterButton
  encounterButton:SetPoint("BOTTOMRIGHT", -spacing - 2 * width, spacing)
  encounterButton:SetFrameLevel(self:GetFrameLevel() + 1)
  encounterButton:SetHeight(20)
  encounterButton:SetWidth(width)
  encounterButton:SetScript("OnClick", function(self)
    local parent = self:GetParent()
    parent:ResetBars()
    if currentProfileState ~= "encounter" then
      WeakAuras.StartProfile("encounter")
    else
      CancelScheduledProfile()
    end
  end)

  self:SetScript("OnMouseDown", function(self, button)
    if button == "LeftButton" and not self.is_moving then
      self:StartMoving()
      self.is_moving = true
    elseif button == "RightButton" then
      self:Stop()
    end
  end)

  self:SetScript("OnMouseUp", function(self, button)
    if button == "LeftButton" and self.is_moving then
      self:StopMovingOrSizing()
      local xOffset = self:GetLeft()
      local yOffset = self:GetTop() - GetScreenHeight()
      WeakAurasSaved.RealTimeProfilingWindow = WeakAurasSaved.RealTimeProfilingWindow or {}
      WeakAurasSaved.RealTimeProfilingWindow.xOffset = xOffset
      WeakAurasSaved.RealTimeProfilingWindow.yOffset = yOffset
      self.is_moving = nil
    end
  end)

  self:SetScript("OnUpdate", self.RefreshBars)
  self.initt = true
  self:UpdateButtons()
end

function RealTimeProfilingWindow:UpdateButtons()
  if not self.initt then
    return
  end
  if currentProfileState == "combat" then
    self.combatButton:SetText(L["Cancel"])
  else
    self.combatButton:SetText(L["Next Combat"])
  end
  if currentProfileState == "encounter" then
    self.encounterButton:SetText(L["Cancel"])
  else
    self.encounterButton:SetText(L["Next Encounter"])
  end
  if currentProfileState == "profiling" then
    self.toggleButton:SetText(L["Stop"])
    self.combatButton:Hide()
    self.encounterButton:Hide()
    self.reportButton:Hide()
  else
    self.toggleButton:SetText(L["Start Now"])
    self.combatButton:Show()
    self.encounterButton:Show()
    if profileData.systems.time then
      self.reportButton:Show()
    end
  end
end

function RealTimeProfilingWindow:Start()
  if not self.initt then
    self:Init()
  end
  self:Show()
end

function RealTimeProfilingWindow:Stop()
  self.reportButton:Show()
  self:Hide()
  self:ResetBars()
  WeakAuras.StopProfile()
  self.toggleButton:SetText(L["Start Now"])
end

function RealTimeProfilingWindow:Toggle()
  if self:IsShown() then
    self:Stop()
  else
    self:Start()
  end
end
