AddonDiagnostics = AddonDiagnostics or {}
AddonDiagnostics.SessionController = {}
local SessionController = AddonDiagnostics.SessionController

local MAX_MARKERS = 25
local MAX_PERFORMANCE_SNAPSHOTS = 2
local DIAGNOSTICS_VERSION = "1.0.0"
local MAX_VISIBLE_ADDON_ROWS = 12
local ADDON_ROW_HEIGHT = 20
local BASE_CONTROL_HEIGHT = 178
local DISCORD_URL = "https://discord.gg/xVmydh94SB"
local discordCopyFrame = nil
local discordCopyEditBox = nil
local recording = false
local startedAt = nil
local markers = {}
local markerCount = 0
local droppedMarkerCount = 0
local lastMarkerElapsed = nil
local sessionEnvironmentEvidence = nil
local sessionEnvironmentTruncated = false
local sessionLoadedAddonCount = 0
local sessionDroppedLoadedAddonCount = 0
local startPerformanceSnapshot = nil
local stopPerformanceSnapshot = nil
local performanceSnapshotCount = 0
local performanceEvidenceTruncated = false
local controlFrame = nil
local recordButton = nil
local markButton = nil
local reloadButton = nil
local reloadGlow = nil
local addonUsageCurrent = nil
local addonUsageAverage = nil
local addonUsagePeak = nil
local addonListScrollFrame = nil
local addonListChild = nil
local addonRows = {}
local addonRowCount = 0
local visibleAddonRows = 1
local trackerRestoreFrame = nil
local trackerRestoreShown = false
local trackerHiddenByWindow = false

local function SetHUDRecording(isRecording)
    if AddonDiagnostics.PerformanceHUD and AddonDiagnostics.PerformanceHUD.SetRecording then
        AddonDiagnostics.PerformanceHUD:SetRecording(isRecording)
    end
end

local function GetPerformanceHUDFrame()
    if AddonDiagnostics.PerformanceHUD and AddonDiagnostics.PerformanceHUD.GetFrame then
        return AddonDiagnostics.PerformanceHUD:GetFrame()
    end
    return nil
end

local function IsEnhancedAddon(name)
    local broker = AddonDiagnostics.EnhancedDiagnosticsBroker
    if not broker or type(broker.GetProviderSummary) ~= "function" then
        return false
    end

    local summary = broker:GetProviderSummary()
    if type(summary) ~= "string" then
        return false
    end

    local marker = string.format("%s |", name)
    return string.find(summary, marker, 1, true) ~= nil
end

local function HideTooltip()
    if GameTooltip then
        GameTooltip:Hide()
    end
end

local function ShowEnhancedTooltip(owner)
    if not GameTooltip then
        return
    end

    GameTooltip:SetOwner(owner, "ANCHOR_RIGHT")
    GameTooltip:SetText("Enhanced Diagnostics")
    GameTooltip:AddLine(
        "This addon provides additional diagnostic information to Addon Diagnostics.",
        1.0,
        1.0,
        1.0,
        true
    )
    GameTooltip:Show()
end

local function ShowSwitchTooltip(owner, locked, controlAvailable)
    if not GameTooltip then
        return
    end

    GameTooltip:SetOwner(owner, "ANCHOR_RIGHT")
    if locked then
        GameTooltip:SetText("Addon Diagnostics stays enabled")
        GameTooltip:AddLine("The diagnostic tool cannot disable itself from this test-loadout menu.", 1.0, 1.0, 1.0, true)
    elseif controlAvailable then
        GameTooltip:SetText("Test Loadout")
        GameTooltip:AddLine("Set this addon's state for the next Reload UI.", 1.0, 1.0, 1.0, true)
    else
        GameTooltip:SetText("Test Loadout")
        GameTooltip:AddLine("Addon enable/disable control is unavailable in this client state.", 1.0, 1.0, 1.0, true)
    end
    GameTooltip:Show()
end

local function FormatProfilerPercent(value)
    local percent = tonumber(value) or 0
    if percent >= 1 then
        return string.format("%.0f%%", percent)
    end
    if percent >= 0.1 then
        return string.format("%.1f%%", percent)
    end
    if percent >= 0.01 then
        return string.format("%.2f%%", percent)
    end
    return "0%"
end

local function GetOverallAddonMetricPercent(metric)
    if not C_AddOnProfiler then
        return nil
    end
    if type(C_AddOnProfiler.IsEnabled) ~= "function" then
        return nil
    end
    if type(C_AddOnProfiler.GetApplicationMetric) ~= "function" then
        return nil
    end
    if type(C_AddOnProfiler.GetOverallMetric) ~= "function" then
        return nil
    end

    local okayEnabled, enabled = pcall(C_AddOnProfiler.IsEnabled)
    if not okayEnabled or enabled ~= true then
        return nil
    end

    local okayApplication, applicationValue = pcall(C_AddOnProfiler.GetApplicationMetric, metric)
    local okayOverall, overallValue = pcall(C_AddOnProfiler.GetOverallMetric, metric)
    if not okayApplication or not okayOverall then
        return nil
    end

    local application = tonumber(applicationValue) or 0
    local overall = tonumber(overallValue) or 0
    if application <= 0 then
        return 0
    end

    local percent = (overall / application) * 100
    if percent < 0 then
        return 0
    end
    return percent
end

local function RefreshAddonUsage()
    if not addonUsageCurrent or not addonUsageAverage or not addonUsagePeak then
        return
    end
    if controlFrame and controlFrame.IsShown and not controlFrame:IsShown() then
        return
    end
    if not Enum or not Enum.AddOnProfilerMetric then
        addonUsageCurrent:SetText("C: --")
        addonUsageAverage:SetText("A: --")
        addonUsagePeak:SetText("P: --")
        return
    end

    local current = GetOverallAddonMetricPercent(Enum.AddOnProfilerMetric.RecentAverageTime)
    local average = GetOverallAddonMetricPercent(Enum.AddOnProfilerMetric.SessionAverageTime)
    local peak = GetOverallAddonMetricPercent(Enum.AddOnProfilerMetric.PeakTime)

    if current == nil or average == nil or peak == nil then
        addonUsageCurrent:SetText("C: --")
        addonUsageAverage:SetText("A: --")
        addonUsagePeak:SetText("P: --")
        return
    end

    addonUsageCurrent:SetText(string.format("C: %s", FormatProfilerPercent(current)))
    addonUsageAverage:SetText(string.format("A: %s", FormatProfilerPercent(average)))
    addonUsagePeak:SetText(string.format("P: %s", FormatProfilerPercent(peak)))
end

local function RefreshReloadPending()
    if not reloadGlow then
        return
    end

    local pending = false
    local loadout = AddonDiagnostics.TestLoadout
    if loadout and type(loadout.HasPendingChanges) == "function" then
        pending = loadout:HasPendingChanges() == true
    end

    if pending then
        reloadGlow:Show()
    else
        reloadGlow:Hide()
    end
end

local function SetSwitchVisual(row, enabled, locked, controlAvailable)
    if not row or not row.switchTrack or not row.switchKnob or not row.switchButton then
        return
    end

    row.enabled = enabled == true
    row.locked = locked == true
    row.controlAvailable = controlAvailable == true

    if row.enabled then
        row.switchTrack:SetColorTexture(0.20, 0.58, 0.30, 0.90)
        row.switchKnob:ClearAllPoints()
        row.switchKnob:SetPoint("RIGHT", row.switchTrack, "RIGHT", -2, 0)
    else
        row.switchTrack:SetColorTexture(0.28, 0.28, 0.30, 0.90)
        row.switchKnob:ClearAllPoints()
        row.switchKnob:SetPoint("LEFT", row.switchTrack, "LEFT", 2, 0)
    end

    if row.locked or not row.controlAvailable then
        row.switchButton:Disable()
        row.switchTrack:SetAlpha(0.55)
        row.switchKnob:SetAlpha(0.65)
    else
        row.switchButton:Enable()
        row.switchTrack:SetAlpha(1.0)
        row.switchKnob:SetAlpha(1.0)
    end
end

local function OnAddonNameEnter(self)
    if self.row and self.row.enhanced then
        ShowEnhancedTooltip(self)
    end
end

local function OnAddonNameLeave()
    HideTooltip()
end

local function OnAddonSwitchEnter(self)
    if self.row then
        ShowSwitchTooltip(self, self.row.locked, self.row.controlAvailable)
    end
end

local function OnAddonSwitchLeave()
    HideTooltip()
end

local function OnAddonSwitchClicked(button)
    if not button or not button.row then
        return
    end

    local row = button.row
    if row.locked or not row.controlAvailable then
        return
    end

    local loadout = AddonDiagnostics.TestLoadout
    if not loadout or type(loadout.SetAddonEnabled) ~= "function" then
        print("Addon Diagnostics: Test-loadout control is unavailable.")
        return
    end

    local changed, reason = loadout:SetAddonEnabled(row.addonIndex, row.addonName, not row.enabled)
    if not changed then
        print(string.format("Addon Diagnostics: %s", tostring(reason or "Unable to change addon test-loadout state.")))
        return
    end

    SessionController:RefreshAddonList()
end

local function CreateAddonRow(index)
    local row = CreateFrame("Frame", nil, addonListChild)
    row:SetHeight(ADDON_ROW_HEIGHT)
    row:SetPoint("TOPLEFT", addonListChild, "TOPLEFT", 0, -((index - 1) * ADDON_ROW_HEIGHT))
    row:SetPoint("TOPRIGHT", addonListChild, "TOPRIGHT", 0, -((index - 1) * ADDON_ROW_HEIGHT))

    row.nameText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    row.nameText:SetPoint("LEFT", row, "LEFT", 2, 0)
    row.nameText:SetWidth(116)
    row.nameText:SetJustifyH("LEFT")

    row.versionText = row:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    row.versionText:SetPoint("RIGHT", row, "RIGHT", -42, 0)
    row.versionText:SetWidth(66)
    row.versionText:SetJustifyH("RIGHT")

    row.nameHitbox = CreateFrame("Frame", nil, row)
    row.nameHitbox:SetPoint("TOPLEFT", row, "TOPLEFT", 0, 0)
    row.nameHitbox:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -110, 0)
    row.nameHitbox:EnableMouse(true)
    row.nameHitbox.row = row
    row.nameHitbox:SetScript("OnEnter", OnAddonNameEnter)
    row.nameHitbox:SetScript("OnLeave", OnAddonNameLeave)

    row.switchButton = CreateFrame("Button", nil, row)
    row.switchButton:SetSize(34, 16)
    row.switchButton:SetPoint("RIGHT", row, "RIGHT", -2, 0)
    row.switchButton.row = row
    row.switchButton:SetScript("OnClick", OnAddonSwitchClicked)
    row.switchButton:SetScript("OnEnter", OnAddonSwitchEnter)
    row.switchButton:SetScript("OnLeave", OnAddonSwitchLeave)

    row.switchTrack = row.switchButton:CreateTexture(nil, "BACKGROUND")
    row.switchTrack:SetAllPoints(row.switchButton)
    row.switchTrack:SetColorTexture(0.28, 0.28, 0.30, 0.90)

    row.switchKnob = row.switchButton:CreateTexture(nil, "ARTWORK")
    row.switchKnob:SetSize(12, 12)
    row.switchKnob:SetPoint("LEFT", row.switchTrack, "LEFT", 2, 0)
    row.switchKnob:SetColorTexture(0.94, 0.94, 0.94, 1.0)

    addonRows[index] = row
    addonRowCount = math.max(addonRowCount, index)
    return row
end

local function GetAddonRow(index)
    local row = addonRows[index]
    if not row then
        row = CreateAddonRow(index)
    end
    return row
end

local function PositionControlFrame()
    local hudFrame = GetPerformanceHUDFrame()
    local width = 250

    if hudFrame and hudFrame.GetWidth then
        local hudWidth = tonumber(hudFrame:GetWidth()) or 0
        if hudWidth > 0 then
            width = math.floor(hudWidth)
        end
    end

    local height = BASE_CONTROL_HEIGHT + (visibleAddonRows * ADDON_ROW_HEIGHT)
    controlFrame:SetSize(width, height)
    controlFrame:ClearAllPoints()

    if hudFrame and hudFrame.GetObjectType then
        controlFrame:SetPoint("TOPRIGHT", hudFrame, "BOTTOMRIGHT", 0, -4)
    else
        controlFrame:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", -42, -267)
    end

    if addonListChild then
        addonListChild:SetWidth(math.max(1, width - 54))
    end
end

local function RefreshAddonList()
    if not addonListScrollFrame or not addonListChild then
        return
    end

    local loadout = AddonDiagnostics.TestLoadout
    if not loadout or type(loadout.GetInstalledAddons) ~= "function" then
        visibleAddonRows = 1
        PositionControlFrame()
        local unavailableRow = GetAddonRow(1)
        unavailableRow.nameText:SetText("Addon inventory unavailable")
        unavailableRow.nameText:SetTextColor(0.75, 0.75, 0.75)
        unavailableRow.nameText:SetShadowColor(0, 0, 0, 0)
        unavailableRow.versionText:SetText("")
        unavailableRow.switchButton:Hide()
        unavailableRow:Show()
        RefreshReloadPending()
        return
    end

    local items, retainedCount = loadout:GetInstalledAddons()
    local displayItems = {}
    local displayCount = 0
    local sourceCount = tonumber(retainedCount) or 0
    for index = 1, sourceCount do
        local item = items[index]
        local isSelf = false
        if item and type(loadout.IsSelfAddon) == "function" then
            isSelf = loadout:IsSelfAddon(item.name) == true
        end
        if item and not isSelf then
            displayCount = displayCount + 1
            displayItems[displayCount] = item
        end
    end

    local totalRows = displayCount
    visibleAddonRows = totalRows
    if visibleAddonRows < 1 then
        visibleAddonRows = 1
    end
    if visibleAddonRows > MAX_VISIBLE_ADDON_ROWS then
        visibleAddonRows = MAX_VISIBLE_ADDON_ROWS
    end

    PositionControlFrame()
    addonListChild:SetHeight(math.max(ADDON_ROW_HEIGHT, totalRows * ADDON_ROW_HEIGHT))

    for index = 1, totalRows do
        local item = displayItems[index]
        local row = GetAddonRow(index)
        row.addonIndex = item.index
        row.addonName = item.name
        row.enhanced = IsEnhancedAddon(item.name)
        row.nameText:SetText(item.name)
        row.versionText:SetText(item.version)
        row.switchButton:Show()

        if row.enhanced then
            row.nameText:SetTextColor(1.0, 0.82, 0.20)
            row.nameText:SetShadowColor(1.0, 0.56, 0.08, 0.80)
            row.nameText:SetShadowOffset(1, -1)
        else
            row.nameText:SetTextColor(1.0, 1.0, 1.0)
            row.nameText:SetShadowColor(0, 0, 0, 0)
            row.nameText:SetShadowOffset(0, 0)
        end

        SetSwitchVisual(row, item.enabled, item.locked, item.controlAvailable)
        row:Show()
    end

    if totalRows == 0 then
        local emptyRow = GetAddonRow(1)
        emptyRow.nameText:SetText("No installed addons found")
        emptyRow.nameText:SetTextColor(0.75, 0.75, 0.75)
        emptyRow.nameText:SetShadowColor(0, 0, 0, 0)
        emptyRow.nameText:SetShadowOffset(0, 0)
        emptyRow.versionText:SetText("")
        emptyRow.switchButton:Hide()
        emptyRow:Show()
    end

    for index = totalRows + 1, addonRowCount do
        if index > 1 or totalRows > 0 then
            addonRows[index]:Hide()
        end
    end

    addonListScrollFrame:SetVerticalScroll(0)
    if addonListScrollFrame.ScrollBar and addonListScrollFrame.ScrollBar.SetShown then
        addonListScrollFrame.ScrollBar:SetShown(totalRows > MAX_VISIBLE_ADDON_ROWS)
    end
    RefreshReloadPending()
end

local function RefreshActionControls()
    if not recordButton or not markButton then
        return
    end

    if recording then
        recordButton:SetText("Stop Recorder")
        markButton:Enable()
        return
    end

    recordButton:SetText("Start Recorder")
    markButton:Disable()
end

local function RefreshControls()
    SetHUDRecording(recording)
    RefreshAddonUsage()
    RefreshAddonList()
    RefreshActionControls()
end

local function GetObjectiveTrackerFrame()
    if _G then
        return _G.ObjectiveTrackerFrame or _G.ObjectiveTracker or _G.WatchFrame
    end
    return nil
end

local function HideObjectiveTrackerForWindow()
    if InCombatLockdown and InCombatLockdown() then
        return
    end

    local tracker = GetObjectiveTrackerFrame()
    if not tracker or not tracker.IsShown then
        return
    end

    trackerRestoreFrame = tracker
    trackerRestoreShown = tracker:IsShown() == true
    trackerHiddenByWindow = false

    if trackerRestoreShown and tracker.Hide then
        tracker:Hide()
        trackerHiddenByWindow = true
    end
end

local function RestoreObjectiveTrackerAfterWindow()
    if InCombatLockdown and InCombatLockdown() then
        return
    end

    if trackerHiddenByWindow and trackerRestoreShown and trackerRestoreFrame and trackerRestoreFrame.Show then
        trackerRestoreFrame:Show()
    end

    trackerRestoreFrame = nil
    trackerRestoreShown = false
    trackerHiddenByWindow = false
end

local function CaptureSessionEnvironmentEvidence()
    sessionEnvironmentEvidence = nil
    sessionEnvironmentTruncated = false
    sessionLoadedAddonCount = 0
    sessionDroppedLoadedAddonCount = 0

    if AddonDiagnostics.UniversalObserver and AddonDiagnostics.UniversalObserver.GetSessionEnvironmentEvidence then
        local evidence, truncated, loadedCount, droppedCount = AddonDiagnostics.UniversalObserver:GetSessionEnvironmentEvidence()
        sessionEnvironmentEvidence = evidence
        sessionEnvironmentTruncated = truncated == true
        sessionLoadedAddonCount = tonumber(loadedCount) or 0
        sessionDroppedLoadedAddonCount = tonumber(droppedCount) or 0
    end
end

local function CapturePerformanceSnapshot(label)
    if performanceSnapshotCount >= MAX_PERFORMANCE_SNAPSHOTS then
        performanceEvidenceTruncated = true
        return
    end

    if AddonDiagnostics.UniversalObserver and AddonDiagnostics.UniversalObserver.GetPerformanceSnapshot then
        local snapshot, truncated = AddonDiagnostics.UniversalObserver:GetPerformanceSnapshot(label)
        if snapshot and snapshot ~= "" then
            if label == "Stop" then
                stopPerformanceSnapshot = snapshot
            else
                startPerformanceSnapshot = snapshot
            end
            performanceSnapshotCount = performanceSnapshotCount + 1
            if truncated then
                performanceEvidenceTruncated = true
            end
        end
    end
end

local function StartLuaErrorCapture()
    if AddonDiagnostics.UniversalObserver and AddonDiagnostics.UniversalObserver.StartLuaErrorCapture then
        AddonDiagnostics.UniversalObserver:StartLuaErrorCapture(startedAt)
    end
end

local function StopLuaErrorCapture()
    if AddonDiagnostics.UniversalObserver and AddonDiagnostics.UniversalObserver.StopLuaErrorCapture then
        AddonDiagnostics.UniversalObserver:StopLuaErrorCapture()
    end
end

function SessionController:IsRecording()
    return recording
end

function SessionController:GetMarkerCount()
    return markerCount
end

function SessionController:GetDroppedMarkerCount()
    return droppedMarkerCount
end

function SessionController:GetMarkerTimes()
    return markers
end

function SessionController:GetLastMarkerElapsed()
    return lastMarkerElapsed
end

function SessionController:GetSessionEnvironmentEvidence()
    return sessionEnvironmentEvidence
end

function SessionController:IsSessionEnvironmentTruncated()
    return sessionEnvironmentTruncated
end

function SessionController:GetSessionLoadedAddonCount()
    return sessionLoadedAddonCount
end

function SessionController:GetSessionDroppedLoadedAddonCount()
    return sessionDroppedLoadedAddonCount
end

function SessionController:GetPerformanceSnapshots()
    return startPerformanceSnapshot, stopPerformanceSnapshot
end

function SessionController:GetPerformanceSnapshotCount()
    return performanceSnapshotCount
end

function SessionController:IsPerformanceEvidenceTruncated()
    return performanceEvidenceTruncated
end

function SessionController:RefreshCoverageSummary()
    RefreshAddonList()
end

function SessionController:RefreshAddonList()
    RefreshAddonList()
end

function SessionController:RefreshAddonUsage()
    RefreshAddonUsage()
end

function SessionController:Start()
    if recording then
        return false
    end

    recording = true
    startedAt = GetTime()
    markers = {}
    markerCount = 0
    droppedMarkerCount = 0
    lastMarkerElapsed = nil
    startPerformanceSnapshot = nil
    stopPerformanceSnapshot = nil
    performanceSnapshotCount = 0
    performanceEvidenceTruncated = false
    CaptureSessionEnvironmentEvidence()
    CapturePerformanceSnapshot("Start")
    StartLuaErrorCapture()
    RefreshControls()
    return true
end

function SessionController:Stop()
    if not recording then
        return false, 0
    end

    local elapsed = 0
    if startedAt then
        elapsed = math.max(0, GetTime() - startedAt)
    end

    CapturePerformanceSnapshot("Stop")
    StopLuaErrorCapture()
    recording = false
    startedAt = nil
    RefreshControls()
    return true, elapsed
end

function SessionController:ToggleRecording()
    if recording then
        return SessionController:Stop()
    end

    return SessionController:Start()
end

function SessionController:MarkProblemNow()
    if not recording or not startedAt then
        print("Addon Diagnostics: Start recording before marking a problem.")
        return false, 0
    end

    if markerCount >= MAX_MARKERS then
        droppedMarkerCount = droppedMarkerCount + 1
        print(string.format("Addon Diagnostics: Problem marker limit reached (%d).", MAX_MARKERS))
        return false, 0
    end

    local elapsed = math.max(0, GetTime() - startedAt)
    table.insert(markers, elapsed)
    markerCount = markerCount + 1
    lastMarkerElapsed = elapsed
    print(string.format("Addon Diagnostics: Problem marked at %.1fs.", elapsed))
    return true, elapsed
end

function SessionController:ShowWindow()
    if not controlFrame:IsShown() then
        controlFrame:Show()
    end
end

function SessionController:HideWindow()
    if controlFrame:IsShown() then
        controlFrame:Hide()
    end
end

function SessionController:ToggleWindow()
    if controlFrame:IsShown() then
        controlFrame:Hide()
    else
        controlFrame:Show()
    end
end

local function OnRecordClicked()
    SessionController:ToggleRecording()
end

local function OnReloadClicked()
    local loadout = AddonDiagnostics.TestLoadout
    local hasPendingChanges = loadout and type(loadout.HasPendingChanges) == "function" and loadout:HasPendingChanges()
    if hasPendingChanges and type(loadout.ApplyPendingChanges) == "function" then
        local applied, reason = loadout:ApplyPendingChanges()
        if not applied then
            local inCombat = InCombatLockdown and InCombatLockdown()
            if inCombat then
                print("Addon Diagnostics: pending test-loadout changes were not applied during combat; reloading UI anyway.")
            else
                print(string.format("Addon Diagnostics: %s", tostring(reason or "Unable to apply test-loadout changes.")))
                RefreshControls()
                return
            end
        end
    end

    if type(ReloadUI) == "function" then
        ReloadUI()
    end
end

local function OnMarkProblemClicked()
    SessionController:MarkProblemNow()
end

local function OnAddonListMouseWheel(self, delta)
    local maximum = math.max(0, addonListChild:GetHeight() - self:GetHeight())
    local nextScroll = self:GetVerticalScroll() - ((tonumber(delta) or 0) * ADDON_ROW_HEIGHT * 2)
    if nextScroll < 0 then
        nextScroll = 0
    end
    if nextScroll > maximum then
        nextScroll = maximum
    end
    self:SetVerticalScroll(nextScroll)
end

local function OnControlFrameShown()
    RefreshControls()
    PositionControlFrame()
    HideObjectiveTrackerForWindow()
end

local function OnControlFrameHidden()
    HideTooltip()
    RestoreObjectiveTrackerAfterWindow()
end

local function OnControlFrameCloseClicked()
    controlFrame:Hide()
end

local function HideDiscordCopyBox()
    if discordCopyFrame then
        discordCopyFrame:Hide()
    end
end

local function OnDiscordCopyEscapePressed(self)
    self:ClearFocus()
    HideDiscordCopyBox()
end

local function OnDiscordCopyEnterPressed(self)
    self:HighlightText()
end

local function OnDiscordCopyFrameShown()
    discordCopyEditBox:SetText(DISCORD_URL)
    discordCopyEditBox:SetFocus()
    discordCopyEditBox:HighlightText()
end

local function ShowDiscordLinkTooltip(owner)
    if GameTooltip then
        GameTooltip:SetOwner(owner, "ANCHOR_RIGHT")
        GameTooltip:SetText("Willbearal's Workshop")
        GameTooltip:AddLine("Click to copy the Discord link.", 1.0, 1.0, 1.0, true)
        GameTooltip:Show()
    end
end

local function ShowDiscordCopyBox()
    if not discordCopyFrame then
        discordCopyFrame = CreateFrame("Frame", "AddonDiagnosticsDiscordCopyFrame", UIParent)
        discordCopyFrame:SetSize(330, 92)
        discordCopyFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
        discordCopyFrame:SetFrameStrata("FULLSCREEN_DIALOG")
        discordCopyFrame:SetClampedToScreen(true)

        local copyBackground = discordCopyFrame:CreateTexture(nil, "BACKGROUND")
        copyBackground:SetAllPoints(discordCopyFrame)
        copyBackground:SetColorTexture(0.025, 0.025, 0.025, 0.98)

        local copyTitle = discordCopyFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        copyTitle:SetPoint("TOPLEFT", discordCopyFrame, "TOPLEFT", 14, -12)
        copyTitle:SetText("Copy Discord Link")

        discordCopyEditBox = CreateFrame("EditBox", nil, discordCopyFrame, "InputBoxTemplate")
        discordCopyEditBox:SetPoint("TOPLEFT", discordCopyFrame, "TOPLEFT", 16, -34)
        discordCopyEditBox:SetPoint("TOPRIGHT", discordCopyFrame, "TOPRIGHT", -38, -34)
        discordCopyEditBox:SetHeight(24)
        discordCopyEditBox:SetAutoFocus(false)
        discordCopyEditBox:SetText(DISCORD_URL)
        discordCopyEditBox:SetScript("OnEscapePressed", OnDiscordCopyEscapePressed)
        discordCopyEditBox:SetScript("OnEnterPressed", OnDiscordCopyEnterPressed)

        local copyInstruction = discordCopyFrame:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
        copyInstruction:SetPoint("BOTTOMLEFT", discordCopyFrame, "BOTTOMLEFT", 16, 12)
        copyInstruction:SetText("Press Ctrl+C to copy.")

        local copyCloseButton = CreateFrame("Button", nil, discordCopyFrame, "UIPanelCloseButton")
        copyCloseButton:SetSize(24, 24)
        copyCloseButton:SetPoint("TOPRIGHT", discordCopyFrame, "TOPRIGHT", 2, 2)
        copyCloseButton:SetScript("OnClick", HideDiscordCopyBox)

        discordCopyFrame:SetScript("OnShow", OnDiscordCopyFrameShown)
        discordCopyFrame:Hide()
    end

    discordCopyFrame:Show()
end

local function CreateControlFrame()
    controlFrame = CreateFrame("Frame", "AddonDiagnosticsControlFrame", UIParent)
    controlFrame:SetSize(250, 192)
    PositionControlFrame()
    controlFrame:SetFrameStrata("DIALOG")
    controlFrame:SetClampedToScreen(true)
    controlFrame:SetScript("OnShow", OnControlFrameShown)
    controlFrame:SetScript("OnHide", OnControlFrameHidden)

    local frameBackground = controlFrame:CreateTexture(nil, "BACKGROUND")
    frameBackground:SetAllPoints(controlFrame)
    frameBackground:SetColorTexture(0.025, 0.025, 0.025, 0.98)

    local topBorder = controlFrame:CreateTexture(nil, "BORDER")
    topBorder:SetPoint("TOPLEFT", controlFrame, "TOPLEFT", 0, 0)
    topBorder:SetPoint("TOPRIGHT", controlFrame, "TOPRIGHT", 0, 0)
    topBorder:SetHeight(2)
    topBorder:SetColorTexture(0.34, 0.34, 0.34, 1)

    local bottomBorder = controlFrame:CreateTexture(nil, "BORDER")
    bottomBorder:SetPoint("BOTTOMLEFT", controlFrame, "BOTTOMLEFT", 0, 0)
    bottomBorder:SetPoint("BOTTOMRIGHT", controlFrame, "BOTTOMRIGHT", 0, 0)
    bottomBorder:SetHeight(2)
    bottomBorder:SetColorTexture(0.34, 0.34, 0.34, 1)

    local leftBorder = controlFrame:CreateTexture(nil, "BORDER")
    leftBorder:SetPoint("TOPLEFT", controlFrame, "TOPLEFT", 0, 0)
    leftBorder:SetPoint("BOTTOMLEFT", controlFrame, "BOTTOMLEFT", 0, 0)
    leftBorder:SetWidth(2)
    leftBorder:SetColorTexture(0.34, 0.34, 0.34, 1)

    local rightBorder = controlFrame:CreateTexture(nil, "BORDER")
    rightBorder:SetPoint("TOPRIGHT", controlFrame, "TOPRIGHT", 0, 0)
    rightBorder:SetPoint("BOTTOMRIGHT", controlFrame, "BOTTOMRIGHT", 0, 0)
    rightBorder:SetWidth(2)
    rightBorder:SetColorTexture(0.34, 0.34, 0.34, 1)

    local headerBand = controlFrame:CreateTexture(nil, "BORDER")
    headerBand:SetPoint("TOPLEFT", controlFrame, "TOPLEFT", 2, -2)
    headerBand:SetPoint("TOPRIGHT", controlFrame, "TOPRIGHT", -2, -2)
    headerBand:SetHeight(38)
    headerBand:SetColorTexture(0.055, 0.055, 0.055, 1)

    local headerEdge = controlFrame:CreateTexture(nil, "ARTWORK")
    headerEdge:SetPoint("TOPLEFT", controlFrame, "TOPLEFT", 2, -40)
    headerEdge:SetPoint("TOPRIGHT", controlFrame, "TOPRIGHT", -2, -40)
    headerEdge:SetHeight(1)
    headerEdge:SetColorTexture(0.42, 0.42, 0.42, 0.95)

    local titleText = controlFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    titleText:SetPoint("TOP", controlFrame, "TOP", 0, -6)

    titleText:SetTextColor(1.0, 0.82, 0.0)
    titleText:SetText("Addon Diagnostics")
    controlFrame.TitleText = titleText

    local versionText = controlFrame:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    versionText:SetPoint("TOP", titleText, "BOTTOM", 0, -1)
    versionText:SetWidth(180)
    versionText:SetJustifyH("CENTER")
    versionText:SetText(DIAGNOSTICS_VERSION)

    local closeButton = CreateFrame("Button", nil, controlFrame, "UIPanelCloseButton")
    closeButton:SetSize(26, 26)
    closeButton:SetPoint("TOPRIGHT", controlFrame, "TOPRIGHT", 3, 3)
    closeButton:SetScript("OnClick", OnControlFrameCloseClicked)

    addonUsageCurrent = controlFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    addonUsageCurrent:SetPoint("TOPLEFT", controlFrame, "TOPLEFT", 14, -46)
    addonUsageCurrent:SetWidth(72)
    addonUsageCurrent:SetJustifyH("LEFT")
    addonUsageCurrent:SetText("C: --")

    addonUsageAverage = controlFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    addonUsageAverage:SetPoint("TOP", controlFrame, "TOP", 0, -46)
    addonUsageAverage:SetWidth(72)
    addonUsageAverage:SetJustifyH("CENTER")
    addonUsageAverage:SetText("A: --")

    addonUsagePeak = controlFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    addonUsagePeak:SetPoint("TOPRIGHT", controlFrame, "TOPRIGHT", -14, -46)
    addonUsagePeak:SetWidth(72)
    addonUsagePeak:SetJustifyH("RIGHT")
    addonUsagePeak:SetText("P: --")

    recordButton = CreateFrame("Button", nil, controlFrame, "UIPanelButtonTemplate")
    recordButton:SetPoint("TOPLEFT", controlFrame, "TOPLEFT", 14, -62)
    recordButton:SetPoint("TOPRIGHT", controlFrame, "TOP", -3, -62)
    recordButton:SetHeight(26)
    recordButton:SetText("Start Recorder")
    recordButton:SetScript("OnClick", OnRecordClicked)

    markButton = CreateFrame("Button", nil, controlFrame, "UIPanelButtonTemplate")
    markButton:SetPoint("TOPLEFT", controlFrame, "TOP", 3, -62)
    markButton:SetPoint("TOPRIGHT", controlFrame, "TOPRIGHT", -14, -62)
    markButton:SetHeight(26)
    markButton:SetText("Mark Problem")
    markButton:SetScript("OnClick", OnMarkProblemClicked)

    addonListScrollFrame = CreateFrame("ScrollFrame", nil, controlFrame, "UIPanelScrollFrameTemplate")
    addonListScrollFrame:SetPoint("TOPLEFT", controlFrame, "TOPLEFT", 14, -96)
    addonListScrollFrame:SetPoint("BOTTOMRIGHT", controlFrame, "BOTTOMRIGHT", -30, 84)
    addonListScrollFrame:EnableMouseWheel(true)
    addonListScrollFrame:SetScript("OnMouseWheel", OnAddonListMouseWheel)

    addonListChild = CreateFrame("Frame", nil, addonListScrollFrame)
    addonListChild:SetSize(196, ADDON_ROW_HEIGHT)
    addonListScrollFrame:SetScrollChild(addonListChild)

    local creatorInfoText = controlFrame:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    creatorInfoText:SetPoint("BOTTOMLEFT", controlFrame, "BOTTOMLEFT", 14, 58)
    creatorInfoText:SetPoint("BOTTOMRIGHT", controlFrame, "BOTTOMRIGHT", -14, 58)
    creatorInfoText:SetHeight(24)
    creatorInfoText:SetJustifyH("LEFT")
    creatorInfoText:SetJustifyV("MIDDLE")
    creatorInfoText:SetText("Created by Willbearal-Area52\nCommunity: Willbearal's Workshop")

    local discordButton = CreateFrame("Button", nil, controlFrame)
    discordButton:SetPoint("BOTTOMLEFT", controlFrame, "BOTTOMLEFT", 14, 44)
    discordButton:SetPoint("BOTTOMRIGHT", controlFrame, "BOTTOMRIGHT", -14, 44)
    discordButton:SetHeight(14)
    local discordText = discordButton:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    discordText:SetAllPoints(discordButton)
    discordText:SetJustifyH("LEFT")
    discordText:SetText("Discord: |cff3399ffhttps://discord.gg/xVmydh94SB|r")
    discordButton:SetScript("OnClick", ShowDiscordCopyBox)
    discordButton:SetScript("OnEnter", ShowDiscordLinkTooltip)
    discordButton:SetScript("OnLeave", HideTooltip)

    reloadButton = CreateFrame("Button", nil, controlFrame, "UIPanelButtonTemplate")
    reloadButton:SetPoint("BOTTOMLEFT", controlFrame, "BOTTOM", 3, 14)
    reloadButton:SetPoint("BOTTOMRIGHT", controlFrame, "BOTTOMRIGHT", -14, 14)
    reloadButton:SetHeight(24)
    reloadButton:SetText("Reload UI")
    reloadButton:SetScript("OnClick", OnReloadClicked)

    reloadGlow = reloadButton:CreateTexture(nil, "BACKGROUND")
    reloadGlow:SetPoint("TOPLEFT", reloadButton, "TOPLEFT", -3, 3)
    reloadGlow:SetPoint("BOTTOMRIGHT", reloadButton, "BOTTOMRIGHT", 3, -3)
    reloadGlow:SetColorTexture(1.0, 0.82, 0.10, 0.38)
    reloadGlow:SetBlendMode("ADD")
    reloadGlow:Hide()

    RefreshControls()
    controlFrame:Hide()
end

local function HandleSlashCommand(message)
    local command = string.lower(message or "")

    if command == "start" then
        SessionController:Start()
    elseif command == "stop" then
        SessionController:Stop()
    elseif command == "mark" then
        SessionController:MarkProblemNow()
    else
        SessionController:ToggleWindow()
    end
end

function AddonDiagnostics_ToggleRecording()
    SessionController:ToggleRecording()
end

function AddonDiagnostics_MarkProblemNow()
    SessionController:MarkProblemNow()
end

function AddonDiagnostics_ToggleWindow()
    SessionController:ToggleWindow()
end

CreateControlFrame()

SLASH_ADDONDIAGNOSTICS1 = "/addondiagnostics"
SLASH_ADDONDIAGNOSTICS2 = "/ad"
SlashCmdList.ADDONDIAGNOSTICS = HandleSlashCommand
