-- VDS_Controller_Search
-- ============================================================================
-- Wires search boxes to their dispatch actions. Loop guard: OnTextChanged
-- only dispatches when text differs from current state (BindingEngine's
-- SetText fires OnTextChanged; dedupe stops the cycle).

VDS = VDS or {}
VDS.Controller_Search = VDS.Controller_Search or {}

local C = VDS.Controller_Search
local A = VDS.Constants.ACTIONS

local function wireSearchBox(box, actionType, dedupeReader)
    if not box then return end
    -- HookScript (not SetScript): SearchBoxTemplate owns the "Search" placeholder
    -- + clear-button visibility via its own OnTextChanged. SetScript would
    -- overwrite Blizzard's handler and leave the placeholder visible on input.
    box:HookScript("OnTextChanged", function(self)
        local text = (self.GetText and self:GetText()) or ""
        text = text:lower()
        if text == dedupeReader() then return end
        VDS.Store:Dispatch({ type = actionType, payload = { text = text } })
    end)
    box:HookScript("OnEscapePressed", function(self)
        self:SetText("")
        VDS.Store:Dispatch({ type = actionType, payload = { text = "" } })
    end)
end

function C:Wire(rootFrame)
    if not (rootFrame and rootFrame.widgets) then return end  -- exception(false-positive): Wire-on-empty-rootFrame is a supported no-op (wire smoke contract)

    wireSearchBox(
        rootFrame.widgets["search.input"],
        A.SET_SEARCH_TEXT,
        function()
            return VDS.Store:GetState().session.ui.searchText  -- top-level only: OnTextChanged dedupe
        end
    )

    -- Canvas picker has its own search scope (separate from center list).
    wireSearchBox(
        rootFrame.widgets["canvasPicker.search"],
        A.CANVAS_SET_PICKER_SEARCH,
        function()
            return VDS.Store:GetState().session.ui.canvas.pickerSearch  -- top-level only: OnTextChanged dedupe
        end
    )
end
