AddonDiagnostics = AddonDiagnostics or {}
AddonDiagnostics.ReportPreview = {}
local ReportPreview = AddonDiagnostics.ReportPreview

local PREVIEW_WIDTH = 760
local PREVIEW_HEIGHT = 660
local MIN_SCROLL_HEIGHT = 500
local MAX_SCROLL_HEIGHT = 12000
local MAX_COPY_CHARACTERS = 196000

local previewFrame = nil
local statusText = nil
local instructionText = nil
local scrollFrame = nil
local scrollChild = nil
local reportEditBox = nil
local reportMeasureText = nil
local previewButton = nil
local previousIncidentButton = nil
local nextIncidentButton = nil
local incidentPositionText = nil
local reportText = ""
local restoringReportText = false
local currentFamilyIndex = nil
local currentFamily = nil
local currentCopyIncidentIDs = {}
local currentCopyIncidentCount = 0
local currentReportTruncated = false
local currentBatchMode = false
local copyUncopiedButton = nil
local clearCopiedButton = nil

local function GetCopyStatusLabel(copied)
    if copied == true then return "|cff33ff66[COPIED LOCALLY]|r" end
    return "|cffffb347[NOT COPIED]|r"
end

local function CountBoundedIncidentIDs(items)
    local count = 0
    if type(items) ~= "table" then return count end
    for index = 1, 20 do
        if not items[index] then return count end
        count = count + 1
    end
    return count
end

local function BoundScrollHeight(value)
    local height = tonumber(value) or MIN_SCROLL_HEIGHT
    if height < MIN_SCROLL_HEIGHT then return MIN_SCROLL_HEIGHT end
    if height > MAX_SCROLL_HEIGHT then return MAX_SCROLL_HEIGHT end
    return height
end
local function UpdateReportLayout()
    if not scrollFrame or not scrollChild or not reportEditBox or not reportMeasureText then return end
    local width = math.max(520, scrollFrame:GetWidth() - 20)
    reportMeasureText:SetWidth(width - 16)
    reportMeasureText:SetText(reportText)
    local textHeight = 0
    if reportMeasureText.GetStringHeight then textHeight = tonumber(reportMeasureText:GetStringHeight()) or 0 end
    reportMeasureText:SetText("")
    local childHeight = BoundScrollHeight(textHeight + 32)
    scrollChild:SetSize(width, childHeight)
    reportEditBox:SetSize(width - 16, math.max(1, childHeight - 16))
    scrollFrame:SetVerticalScroll(0)
end

local function RestoreReportText()
    if not reportEditBox or reportEditBox:GetText() == reportText then return end
    restoringReportText = true
    reportEditBox:SetText(reportText)
    restoringReportText = false
    reportEditBox:SetCursorPosition(0)
    UpdateReportLayout()
end

local function OnReportTextChanged(_, userInput)
    if not userInput or restoringReportText then return end
    RestoreReportText()
end

local function OnEscapePressed()
    if previewFrame then previewFrame:Hide() end
    if reportEditBox then reportEditBox:ClearFocus() end
end
local function SetReportText(value)
    reportText = value or ""
    restoringReportText = true
    reportEditBox:SetText(reportText)
    restoringReportText = false
    reportEditBox:SetCursorPosition(0)
    reportEditBox:ClearFocus()
    UpdateReportLayout()
end

local function UpdateReportStatusText()
    if not statusText then return end
    local store = AddonDiagnostics.IncidentStore
    if currentBatchMode then
        statusText:SetText(string.format("Batch copy - %d retained incident(s) included%s", currentCopyIncidentCount, currentReportTruncated and " - fixed bound reached" or ""))
        return
    end
    if not currentFamily then return end
    local incidentCount = store and type(store.GetIncidentCount) == "function" and store:GetIncidentCount() or 0
    local familyCount = store and type(store.GetProblemFamilyCount) == "function" and store:GetProblemFamilyCount() or 0
    statusText:SetText(string.format("%s  %d incident(s) / %d report(s) - %d variant(s), %d occurrence(s)%s", GetCopyStatusLabel(currentFamily.copied), incidentCount, familyCount, tonumber(currentFamily.incidentCount) or 1, tonumber(currentFamily.occurrences) or 1, currentReportTruncated and " - report reached its fixed bound" or ""))
end

local function UpdateReportNavigation()
    if not previousIncidentButton or not nextIncidentButton or not incidentPositionText then return end
    local store = AddonDiagnostics.IncidentStore
    if not currentFamilyIndex or not store or type(store.GetProblemFamilyCount) ~= "function" then
        previousIncidentButton:Hide()
        nextIncidentButton:Hide()
        incidentPositionText:Hide()
        return
    end
    local count = math.max(0, tonumber(store:GetProblemFamilyCount()) or 0)
    incidentPositionText:SetText(string.format("Report %d of %d   %s", currentFamilyIndex, count, GetCopyStatusLabel(currentFamily and currentFamily.copied)))
    incidentPositionText:Show()
    if currentFamilyIndex < count then previousIncidentButton:Show() else previousIncidentButton:Hide() end
    if currentFamilyIndex > 1 then nextIncidentButton:Show() else nextIncidentButton:Hide() end
end

local function ShowFamilyByIndex(index)
    local store = AddonDiagnostics.IncidentStore
    local builder = AddonDiagnostics.ReportBuilder
    if not store or not builder or type(store.GetProblemFamilyByNewestIndex) ~= "function" or type(builder.BuildProblemFamilyReport) ~= "function" then return false end
    local family = store:GetProblemFamilyByNewestIndex(index)
    if not family then return false end
    currentBatchMode = false
    currentFamilyIndex = index
    currentFamily = family
    if type(store.MarkProblemFamilyReviewed) == "function" then store:MarkProblemFamilyReviewed(family) end
    local report, ready, truncated, reason, incidentIDs = builder:BuildProblemFamilyReport(family)
    if not ready then
        statusText:SetText("Report unavailable")
        instructionText:SetText(tostring(reason or "Problem-family report unavailable."))
        SetReportText("No problem-family report is available.")
        return false
    end
    currentCopyIncidentIDs = incidentIDs or {}
    currentCopyIncidentCount = CountBoundedIncidentIDs(currentCopyIncidentIDs)
    currentReportTruncated = truncated == true
    UpdateReportStatusText()
    instructionText:SetText("Automatic family grouping preserves exact incident evidence. Click in the report and press Ctrl+A, Ctrl+C to copy. Nothing is sent automatically.")
    SetReportText(report)
    UpdateReportNavigation()
    return true
end

local function RefreshBestReport()
    local builder = AddonDiagnostics.ReportBuilder
    local store = AddonDiagnostics.IncidentStore
    if store and type(store.GetLatestUnreadProblemFamily) == "function" then
        local family, index = store:GetLatestUnreadProblemFamily()
        if family and index and ShowFamilyByIndex(index) then return end
    end
    if store and type(store.GetProblemFamilyCount) == "function" and store:GetProblemFamilyCount() > 0 then
        if ShowFamilyByIndex(1) then return end
    end
    currentFamilyIndex = nil
    currentFamily = nil
    currentCopyIncidentIDs = {}
    currentCopyIncidentCount = 0
    currentReportTruncated = false
    currentBatchMode = false
    UpdateReportNavigation()
    if not builder or type(builder.BuildReport) ~= "function" then
        statusText:SetText("Report unavailable")
        instructionText:SetText("The report builder is unavailable.")
        SetReportText("No report is available.")
        return
    end
    local report, ready, truncated, reason = builder:BuildReport()
    if not ready then
        statusText:SetText("Report unavailable")
        instructionText:SetText(tostring(reason or "No recent incident or completed recording is available."))
        SetReportText("No recent incident or completed recording is available yet.")
        return
    end
    statusText:SetText(truncated and "Latest recording report - output reached its fixed bound" or "Latest recording report")
    instructionText:SetText("Plain-language guidance is first; developer technical detail is below. Click in the report and press Ctrl+A, Ctrl+C to copy. Nothing is sent automatically.")
    SetReportText(report)
end

local function OnPreviousIncidentClicked()
    if currentFamilyIndex then ShowFamilyByIndex(currentFamilyIndex + 1) end
end

local function OnNextIncidentClicked()
    if currentFamilyIndex and currentFamilyIndex > 1 then ShowFamilyByIndex(currentFamilyIndex - 1) end
end

local function OnReportKeyDown(_, key)
    if key ~= "C" or currentCopyIncidentCount == 0 or type(IsControlKeyDown) ~= "function" or not IsControlKeyDown() then return end
    local store = AddonDiagnostics.IncidentStore
    if store and type(store.MarkIncidentsCopied) == "function" then
        local copiedCount = store:MarkIncidentsCopied(currentCopyIncidentIDs)
        if copiedCount > 0 then
            if currentBatchMode then
                statusText:SetText(string.format("|cff33ff66[COPIED LOCALLY]|r  Batch copy - %d retained incident(s)%s", currentCopyIncidentCount, currentReportTruncated and " - fixed bound reached" or ""))
                instructionText:SetText("Copy observed locally for the included reports. The selectable payload remains unchanged; nothing was sent automatically.")
                if currentFamilyIndex and type(store.GetProblemFamilyByNewestIndex) == "function" then
                    currentFamily = store:GetProblemFamilyByNewestIndex(currentFamilyIndex) or currentFamily
                    UpdateReportNavigation()
                end
            elseif currentFamily then
                currentFamily.copied = true
                UpdateReportStatusText()
                UpdateReportNavigation()
            end
            currentCopyIncidentIDs = {}
            currentCopyIncidentCount = 0
        end
    end
end

local function OnCopyUncopiedClicked()
    local builder = AddonDiagnostics.ReportBuilder
    if not builder or type(builder.BuildUncopiedProblemReports) ~= "function" then return end
    local report, ready, truncated, reason, incidentIDs = builder:BuildUncopiedProblemReports()
    if not ready then
        statusText:SetText("No uncopied problem reports")
        instructionText:SetText(tostring(reason or "No uncopied problem reports are retained."))
        return
    end
    currentBatchMode = true
    currentCopyIncidentIDs = incidentIDs or {}
    currentCopyIncidentCount = CountBoundedIncidentIDs(currentCopyIncidentIDs)
    currentReportTruncated = truncated == true
    UpdateReportStatusText()
    UpdateReportNavigation()
    instructionText:SetText("The combined uncopied payload below is selected and ready. Press Ctrl+C once. Only included reports become COPIED LOCALLY after that copy is observed.")
    SetReportText(report)
    reportEditBox:SetFocus()
    reportEditBox:HighlightText()
end

local function OnClearCopiedClicked()
    local store = AddonDiagnostics.IncidentStore
    if store and type(store.ClearCopied) == "function" then
        local removed = store:ClearCopied()
        RefreshBestReport()
        instructionText:SetText(string.format("Cleared %d copied retained incident(s) from local history. Clearing does not mean the underlying problems were fixed or resolved.", tonumber(removed) or 0))
    end
end

local function CreatePreviewFrame()
    previewFrame = CreateFrame("Frame", "AddonDiagnosticsReportPreviewFrame", UIParent, "BasicFrameTemplateWithInset")
    previewFrame:SetSize(PREVIEW_WIDTH, PREVIEW_HEIGHT)
    previewFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    previewFrame:SetFrameStrata("DIALOG")
    previewFrame:SetClampedToScreen(true)
    previewFrame.TitleText:SetText("Addon Diagnostics Report")

    statusText = previewFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    statusText:SetPoint("TOPLEFT", previewFrame, "TOPLEFT", 18, -40)
    statusText:SetPoint("TOPRIGHT", previewFrame, "TOPRIGHT", -18, -40)
    statusText:SetJustifyH("LEFT")
    statusText:SetText("Report unavailable")

    instructionText = previewFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    instructionText:SetPoint("TOPLEFT", previewFrame, "TOPLEFT", 18, -60)
    instructionText:SetPoint("TOPRIGHT", previewFrame, "TOPRIGHT", -18, -60)
    instructionText:SetJustifyH("LEFT")
    instructionText:SetText("Recent captured problems appear here automatically; Start Recorder remains available for deeper reproductions.")

    previousIncidentButton = CreateFrame("Button", nil, previewFrame, "UIPanelButtonTemplate")
    previousIncidentButton:SetSize(112, 22)
    previousIncidentButton:SetPoint("TOPLEFT", previewFrame, "TOPLEFT", 18, -82)
    previousIncidentButton:SetText("Older Report")
    previousIncidentButton:SetScript("OnClick", OnPreviousIncidentClicked)
    nextIncidentButton = CreateFrame("Button", nil, previewFrame, "UIPanelButtonTemplate")
    nextIncidentButton:SetSize(112, 22)
    nextIncidentButton:SetPoint("LEFT", previousIncidentButton, "RIGHT", 8, 0)
    nextIncidentButton:SetText("Newer Report")
    nextIncidentButton:SetScript("OnClick", OnNextIncidentClicked)

    incidentPositionText = previewFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    incidentPositionText:SetPoint("LEFT", nextIncidentButton, "RIGHT", 12, 0)
    incidentPositionText:SetJustifyH("LEFT")

    scrollFrame = CreateFrame("ScrollFrame", nil, previewFrame, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", previewFrame, "TOPLEFT", 18, -112)
    scrollFrame:SetPoint("BOTTOMRIGHT", previewFrame, "BOTTOMRIGHT", -34, 48)

    scrollChild = CreateFrame("Frame", nil, scrollFrame)
    scrollChild:SetSize(PREVIEW_WIDTH - 64, MIN_SCROLL_HEIGHT)
    scrollFrame:SetScrollChild(scrollChild)

    reportEditBox = CreateFrame("EditBox", nil, scrollChild)
    reportEditBox:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 8, -8)
    reportEditBox:SetMultiLine(true)
    reportEditBox:SetAutoFocus(false)
    reportEditBox:SetFontObject(ChatFontNormal)
    reportEditBox:SetTextColor(1, 1, 1)
    reportEditBox:SetJustifyH("LEFT")
    reportEditBox:SetJustifyV("TOP")
    reportEditBox:SetMaxLetters(MAX_COPY_CHARACTERS)
    reportEditBox:SetScript("OnTextChanged", OnReportTextChanged)
    reportEditBox:SetScript("OnEscapePressed", OnEscapePressed)
    reportEditBox:SetScript("OnKeyDown", OnReportKeyDown)
    reportMeasureText = scrollChild:CreateFontString(nil, "ARTWORK", "ChatFontNormal")
    reportMeasureText:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 8, -8)
    reportMeasureText:SetJustifyH("LEFT")
    reportMeasureText:SetJustifyV("TOP")
    reportMeasureText:SetAlpha(0)

    copyUncopiedButton = CreateFrame("Button", nil, previewFrame, "UIPanelButtonTemplate")
    copyUncopiedButton:SetSize(126, 24)
    copyUncopiedButton:SetPoint("BOTTOMLEFT", previewFrame, "BOTTOMLEFT", 18, 16)
    copyUncopiedButton:SetText("Copy Uncopied")
    copyUncopiedButton:SetScript("OnClick", OnCopyUncopiedClicked)

    clearCopiedButton = CreateFrame("Button", nil, previewFrame, "UIPanelButtonTemplate")
    clearCopiedButton:SetSize(116, 24)
    clearCopiedButton:SetPoint("LEFT", copyUncopiedButton, "RIGHT", 8, 0)
    clearCopiedButton:SetText("Clear Copied")
    clearCopiedButton:SetScript("OnClick", OnClearCopiedClicked)

    local closeButton = CreateFrame("Button", nil, previewFrame, "UIPanelButtonTemplate")
    closeButton:SetSize(100, 24)
    closeButton:SetPoint("BOTTOMRIGHT", previewFrame, "BOTTOMRIGHT", -18, 16)
    closeButton:SetText("Close")
    closeButton:SetScript("OnClick", OnEscapePressed)
    previewFrame:Hide()
end

function ReportPreview:Show()
    if not previewFrame then CreatePreviewFrame() end
    previewFrame:Show()
    RefreshBestReport()
end

function ReportPreview:ShowLatestIncident()
    if not previewFrame then CreatePreviewFrame() end
    previewFrame:Show()
    RefreshBestReport()
end
function ReportPreview:Hide()
    if previewFrame then previewFrame:Hide() end
    if reportEditBox then reportEditBox:ClearFocus() end
end

function ReportPreview:GetFrame()
    return previewFrame
end

local function OnPreviewButtonClicked()
    ReportPreview:Show()
end

local function CreatePreviewButton()
    local controlFrame = _G and _G.AddonDiagnosticsControlFrame or nil
    if not controlFrame or previewButton then return end
    previewButton = CreateFrame("Button", nil, controlFrame, "UIPanelButtonTemplate")
    previewButton:SetPoint("BOTTOMLEFT", controlFrame, "BOTTOMLEFT", 14, 14)
    previewButton:SetPoint("BOTTOMRIGHT", controlFrame, "BOTTOM", -3, 14)
    previewButton:SetHeight(24)
    previewButton:SetText("Get Report")
    previewButton:SetScript("OnClick", OnPreviewButtonClicked)
end

CreatePreviewButton()
