local API = rawget(_G, "LIDCOUNCIL_API")
local INTERNAL_API = type(API) == "table" and type(API.__internal) == "table" and API.__internal or nil
if type(INTERNAL_API) ~= "table" then
  error("LidCouncil missing internal API registry.")
end

local function ResolveApi(name)
  local api = rawget(_G, "LIDCOUNCIL_API")
  if type(api) == "table" and type(api[name]) == "function" then
    return api[name]
  end
  return nil
end

local function FormatTimestamp(value)
  local timestamp = math.max(0, tonumber(value) or 0)
  if timestamp <= 0 then return "not started" end
  if type(date) == "function" then
    return tostring(date("%Y-%m-%d %H:%M:%S", timestamp))
  end
  return tostring(timestamp)
end

local function CreateAboutRaidTestTraceSection(editor, aboutContent, helpers)
  if not editor or not aboutContent then return nil end
  helpers = type(helpers) == "table" and helpers or {}
  local MakeAboutTitle = helpers.MakeAboutTitle
  local SafeHookScript = helpers.SafeHookScript
  local Print = helpers.Print
  if type(MakeAboutTitle) ~= "function" or type(SafeHookScript) ~= "function" then
    return nil
  end

  local frame = CreateFrame("Frame", nil, aboutContent)
  frame:SetAllPoints(aboutContent)
  frame:Hide()
  editor.aboutRaidTestTraceFrame = frame

  local title = MakeAboutTitle(frame, "Raid Test Trace", 0, 0)
  editor.aboutRaidTestTraceTitle = title

  local description = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  description:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -6)
  description:SetJustifyH("LEFT")
  description:SetWordWrap(true)
  description:SetText(
    "Use this low-overhead flight recorder for the 16-22 client test. It captures critical JOIN/session/sync boundaries, Test Raid Items and board-receipt lifecycles, measured UI and snapshot work, changed transport samples with a ten-second idle heartbeat, combat/encounter transitions, and main-thread frame gaps. Bulk chunks are not logged one by one, and recording never refreshes this page automatically. The trace is memory-only, so stop and copy it before /reload or before starting another trace."
  )
  editor.aboutRaidTestTraceDescription = description

  local stateText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
  stateText:SetJustifyH("LEFT")
  stateText:SetWordWrap(true)
  stateText:SetText("Trace status unavailable.")
  editor.aboutRaidTestTraceState = stateText

  local startButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
  startButton:SetSize(150, 22)
  startButton:SetText("Start New Trace")
  editor.aboutRaidTestTraceStartBtn = startButton

  local stopButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
  stopButton:SetSize(110, 22)
  stopButton:SetText("Stop Trace")
  editor.aboutRaidTestTraceStopBtn = stopButton

  local refreshButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
  refreshButton:SetSize(120, 22)
  refreshButton:SetText("Refresh Status")
  editor.aboutRaidTestTraceRefreshBtn = refreshButton

  local markerLabel = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  markerLabel:SetText("Marker note")
  markerLabel:SetJustifyH("LEFT")
  editor.aboutRaidTestTraceMarkerLabel = markerLabel

  local markerEdit = CreateFrame("EditBox", nil, frame, "InputBoxTemplate")
  markerEdit:SetSize(360, 22)
  markerEdit:SetAutoFocus(false)
  markerEdit:SetMaxLetters(180)
  markerEdit:SetText("")
  editor.aboutRaidTestTraceMarkerEdit = markerEdit

  local markerButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
  markerButton:SetSize(110, 22)
  markerButton:SetText("Add Marker")
  editor.aboutRaidTestTraceMarkerBtn = markerButton

  local copyButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
  copyButton:SetSize(160, 22)
  copyButton:SetText("Copy Raid Trace")
  editor.aboutRaidTestTraceCopyBtn = copyButton

  local clearButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
  clearButton:SetSize(105, 22)
  clearButton:SetText("Clear Trace")
  editor.aboutRaidTestTraceClearBtn = clearButton

  local summaryHeader = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
  summaryHeader:SetText("Diagnostic summary")
  summaryHeader:SetJustifyH("LEFT")
  editor.aboutRaidTestTraceSummaryHeader = summaryHeader

  local summaryText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  summaryText:SetJustifyH("LEFT")
  summaryText:SetWordWrap(true)
  summaryText:SetText("No trace captured yet.")
  editor.aboutRaidTestTraceSummary = summaryText

  local recentHeader = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
  recentHeader:SetText("Latest timeline entries")
  recentHeader:SetJustifyH("LEFT")
  editor.aboutRaidTestTraceRecentHeader = recentHeader

  local recentText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  recentText:SetJustifyH("LEFT")
  recentText:SetWordWrap(false)
  recentText:SetText("No events recorded.")
  editor.aboutRaidTestTraceRecent = recentText

  local function RefreshSection()
    local getStatus = ResolveApi("LIDCOUNCIL_GetRaidTestTraceStatus")
    local status = type(getStatus) == "function" and getStatus() or nil
    if type(status) ~= "table" then
      stateText:SetText("Raid Test Trace API is unavailable.")
      stateText:SetTextColor(1, 0.25, 0.25, 1)
      startButton:SetEnabled(false)
      stopButton:SetEnabled(false)
      markerButton:SetEnabled(false)
      copyButton:SetEnabled(false)
      clearButton:SetEnabled(false)
      return
    end
    local active = status.active == true
    local hasTrace = status.hasTrace == true
    local stateLabel = active and "RUNNING" or (hasTrace and "STOPPED" or "EMPTY")
    stateText:SetText(string.format(
      "%s | %d stored / %d recorded | %.1fs | Started %s",
      stateLabel,
      math.max(0, tonumber(status.eventCount) or 0),
      math.max(0, tonumber(status.totalEvents) or 0),
      math.max(0, tonumber(status.durationSeconds) or 0),
      FormatTimestamp(status.startedWall)
    ))
    if active then
      stateText:SetTextColor(0.2, 0.9, 0.35, 1)
    elseif hasTrace then
      stateText:SetTextColor(1, 0.78, 0.15, 1)
    else
      stateText:SetTextColor(0.75, 0.78, 0.85, 1)
    end

    local summary = type(status.summary) == "table" and status.summary or {}
    local context = type(status.context) == "table" and status.context or {}
    summaryText:SetText(table.concat({
      "Character/role: " .. tostring(context.character or "unknown") .. " / " .. tostring(context.role or "unknown"),
      "Session/profile: " .. tostring(context.sessionId or "none") .. " / " .. tostring(context.profileName or "none"),
      string.format("Max frame gap %.1fms | Editor refresh %.1fms | Snapshot prepare %.1fms",
        math.max(0, tonumber(summary.maxFrameGapMs) or 0),
        math.max(0, tonumber(summary.maxEditorRefreshMs) or 0),
        math.max(0, tonumber(summary.maxSnapshotPrepareMs) or 0)),
      string.format("Inbound JOIN %.1fms | JOIN follow-up %.1fms | Queue high-water %d",
        math.max(0, tonumber(summary.maxInboundJoinMs) or 0),
        math.max(0, tonumber(summary.maxJoinFollowupMs) or 0),
        math.max(0, tonumber(summary.maxQueueDepth) or 0)),
      string.format("Lockdown entries %d | Throttle cooldown entries %d | Markers %d | Unchanged samples skipped %d | Overwritten %d",
        math.max(0, tonumber(summary.lockdownEnters) or 0),
        math.max(0, tonumber(summary.throttleCooldownEnters) or 0),
        math.max(0, tonumber(summary.markerCount) or 0),
        math.max(0, tonumber(summary.suppressedQueueSamples) or 0),
        math.max(0, tonumber(status.overwritten) or 0)),
    }, "\n"))
    local recentLines = type(status.recentLines) == "table" and status.recentLines or {}
    recentText:SetText(#recentLines > 0 and table.concat(recentLines, "\n") or "No events recorded.")
    startButton:SetEnabled(not active)
    stopButton:SetEnabled(active)
    markerButton:SetEnabled(active)
    copyButton:SetEnabled(hasTrace)
    clearButton:SetEnabled(hasTrace and not active)
    if editor.UpdateAboutRaidTestTraceLayout then
      editor:UpdateAboutRaidTestTraceLayout()
    end
  end
  editor.RefreshRaidTestTraceSection = RefreshSection

  startButton:SetScript("OnClick", function()
    local startTrace = ResolveApi("LIDCOUNCIL_StartRaidTestTrace")
    local note = markerEdit:GetText() or ""
    local ok, reason = false, "Trace API unavailable."
    if type(startTrace) == "function" then
      ok, reason = startTrace(note)
    end
    markerEdit:SetText("")
    if Print then Print(ok and "Raid Test Trace started." or tostring(reason or "Raid Test Trace could not start.")) end
    RefreshSection()
  end)

  stopButton:SetScript("OnClick", function()
    local stopTrace = ResolveApi("LIDCOUNCIL_StopRaidTestTrace")
    local ok, reason = false, "Trace API unavailable."
    if type(stopTrace) == "function" then
      ok, reason = stopTrace("Stopped from About.")
    end
    if Print then Print(ok and "Raid Test Trace stopped. Copy the report before /reload or before starting a new trace." or tostring(reason or "Raid Test Trace could not stop.")) end
    RefreshSection()
  end)

  markerButton:SetScript("OnClick", function()
    local addMarker = ResolveApi("LIDCOUNCIL_AddRaidTestTraceMarker")
    local ok, reason = false, "Trace API unavailable."
    if type(addMarker) == "function" then
      ok, reason = addMarker(markerEdit:GetText())
    end
    if ok then markerEdit:SetText("") end
    if Print then Print(ok and "Raid Test Trace marker added." or tostring(reason or "Marker could not be added.")) end
    RefreshSection()
  end)

  copyButton:SetScript("OnClick", function()
    local buildReport = ResolveApi("LIDCOUNCIL_BuildRaidTestTraceReport")
    local showCopy = ResolveApi("LIDCOUNCIL_ShowCopyTextWindow")
    if type(buildReport) == "function" and type(showCopy) == "function" then
      showCopy("LidCouncil Raid Test Trace", buildReport())
    elseif Print then
      Print("Copyable Raid Test Trace report is unavailable.")
    end
  end)

  clearButton:SetScript("OnClick", function()
    local clearTrace = ResolveApi("LIDCOUNCIL_ClearRaidTestTrace")
    local ok, reason = false, "Trace API unavailable."
    if type(clearTrace) == "function" then
      ok, reason = clearTrace()
    end
    if Print then Print(ok and "Raid Test Trace cleared." or tostring(reason or "Raid Test Trace could not be cleared.")) end
    RefreshSection()
  end)

  refreshButton:SetScript("OnClick", RefreshSection)
  markerEdit:SetScript("OnEnterPressed", function(self)
    markerButton:Click()
    self:ClearFocus()
  end)
  markerEdit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)

  local function UpdateLayout()
    if editor.aboutSection and editor.aboutSection ~= "RaidTrace" then return end
    local width = math.max(520, (aboutContent:GetWidth() or 0) - 12)
    description:SetWidth(width)
    stateText:SetWidth(width)
    summaryText:SetWidth(width)
    recentText:SetWidth(width)

    description:ClearAllPoints()
    description:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -6)
    stateText:ClearAllPoints()
    stateText:SetPoint("TOPLEFT", description, "BOTTOMLEFT", 0, -14)
    startButton:ClearAllPoints()
    startButton:SetPoint("TOPLEFT", stateText, "BOTTOMLEFT", 0, -12)
    stopButton:ClearAllPoints()
    stopButton:SetPoint("LEFT", startButton, "RIGHT", 10, 0)
    refreshButton:ClearAllPoints()
    refreshButton:SetPoint("LEFT", stopButton, "RIGHT", 10, 0)
    markerLabel:ClearAllPoints()
    markerLabel:SetPoint("TOPLEFT", startButton, "BOTTOMLEFT", 0, -16)
    markerEdit:ClearAllPoints()
    markerEdit:SetPoint("TOPLEFT", markerLabel, "BOTTOMLEFT", 4, -6)
    markerEdit:SetWidth(math.min(480, math.max(240, width - 130)))
    markerButton:ClearAllPoints()
    markerButton:SetPoint("LEFT", markerEdit, "RIGHT", 10, 0)
    copyButton:ClearAllPoints()
    copyButton:SetPoint("TOPLEFT", markerEdit, "BOTTOMLEFT", -4, -14)
    clearButton:ClearAllPoints()
    clearButton:SetPoint("LEFT", copyButton, "RIGHT", 10, 0)
    summaryHeader:ClearAllPoints()
    summaryHeader:SetPoint("TOPLEFT", copyButton, "BOTTOMLEFT", 0, -18)
    summaryText:ClearAllPoints()
    summaryText:SetPoint("TOPLEFT", summaryHeader, "BOTTOMLEFT", 0, -6)
    recentHeader:ClearAllPoints()
    recentHeader:SetPoint("TOPLEFT", summaryText, "BOTTOMLEFT", 0, -18)
    recentText:ClearAllPoints()
    recentText:SetPoint("TOPLEFT", recentHeader, "BOTTOMLEFT", 0, -6)

    local descriptionHeight = (description.GetStringHeight and description:GetStringHeight()) or 40
    local summaryHeight = (summaryText.GetStringHeight and summaryText:GetStringHeight()) or 80
    local recentHeight = (recentText.GetStringHeight and recentText:GetStringHeight()) or 120
    local totalHeight = math.max(520, descriptionHeight + summaryHeight + recentHeight + 260)
    if editor.SetAboutContentHeight then
      editor:SetAboutContentHeight(totalHeight)
    end
  end
  editor.UpdateAboutRaidTestTraceLayout = UpdateLayout
  SafeHookScript(frame, "OnShow", function()
    RefreshSection()
    UpdateLayout()
  end)
  SafeHookScript(aboutContent, "OnSizeChanged", UpdateLayout)
  UpdateLayout()
  return frame
end

INTERNAL_API.LIDCOUNCIL_CreateAboutRaidTestTraceSection_Impl = CreateAboutRaidTestTraceSection
