-- test_controller_wire_smoke.lua
-- ============================================================================
-- Controller:Wire() looks up widget IDs from the layout. If a widget ID is a
-- typo, rootFrame.widgets["typo"] returns nil. Production code guards with
-- `if w then w:SetScript(...) end` -- so no error fires. The button renders,
-- user clicks it, NOTHING happens. Silent dead UI.
--
-- This test wires each controller against a synthetic rootFrame populated
-- with spy widgets for every widget ID found in LayoutConfig, then verifies:
--   1. Wire() completes without error for every controller
--   2. For Title controller (representative): OnClick handlers dispatch known actions
--
-- LESSON (HDGR): "the most dangerous gap in the test suite before this file"
-- -- silent OnClick failures are invisible to other tests.

---@diagnostic disable: undefined-global
dofile("wow_mock.lua")
dofile("../Core/VDS_Constants.lua")
dofile("../Core/VDS_SchemeConstants.lua")
dofile("../Core/VDS_Paths.lua")
dofile("../Core/VDS_Log.lua")
dofile("../Core/VDS_Store.lua")
dofile("../Core/VDS_ActionMeta.lua")
VDS_DB = {}
VDS.Store:LoadFromSavedVariables()

dofile("../UI/VDS_Selectors.lua")

-- Load LayoutConfig + Controllers (defensive: optional in incremental builds).
local function tryDofile(path)
    local f = io.open(path, "r")
    if f then f:close(); dofile(path); return true end
    return false
end

-- Controllers attach tooltips via VDS.TooltipEngine; load the engine so
-- Wire() doesn't crash when the test wires a slot row.
tryDofile("../Core/VDS_TooltipEngine.lua")
tryDofile("../Core/VDS_TooltipRecipes.lua")
-- Controller_Live's Apply warn-paint routes through Theme:SetState/:Apply at
-- Wire() time; the Button skinner no-ops on spy widgets (guarded getters).
tryDofile("../UI/VDS_Theme.lua")

tryDofile("../UI/VDS_LayoutConfig.lua")
tryDofile("../UI/VDS_LayoutConfig_Default.lua")
tryDofile("../UI/VDS_LayoutConfig_Canvas.lua")
tryDofile("../UI/VDS_LayoutConfig_Live.lua")
tryDofile("../UI/VDS_Controller_Title.lua")
tryDofile("../UI/VDS_Controller_Browse.lua")
tryDofile("../UI/VDS_Controller_Detail.lua")
tryDofile("../UI/VDS_Controller_Search.lua")
tryDofile("../UI/VDS_Controller_Canvas.lua")
tryDofile("../UI/VDS_Controller_Live.lua")
tryDofile("../UI/VDS_Controller_LiveBridge.lua")
tryDofile("../UI/VDS_Controller_Minimap.lua")
tryDofile("../UI/VDS_Controller_Warehouse.lua")
tryDofile("../Core/VDS_ColorMath.lua")
tryDofile("../Core/VDS_HarmonyWheel.lua")
tryDofile("../Core/VDS_Harmony.lua")
tryDofile("../Modules/VDS_StaticData.lua")
-- Canvas selectors required by Controller_Canvas:Wire (harmonise gate calls Selectors:Call).
tryDofile("../UI/VDS_Selectors_Canvas.lua")
tryDofile("../UI/VDS_Controller_Harmony.lua")

local function assertTrue(v, label) if not v then error(label, 2) end end

-- ===== Spy widget factory =====
local function makeSpyWidget(id)
    local w = {
        id = id,
        _scripts = {},
        _shown   = true,
        _checked = false,
    }
    function w:SetScript(event, fn) self._scripts[event] = fn end
    function w:GetScript(event)     return self._scripts[event] end
    function w:HookScript(event, fn)
        local prev = self._scripts[event]
        self._scripts[event] = function(...) if prev then prev(...) end; fn(...) end
    end
    function w:Show()      self._shown = true end
    function w:Hide()      self._shown = false end
    function w:IsShown()   return self._shown end
    function w:SetText(t)  self._text = t end
    function w:GetText()   return self._text end
    function w:SetChecked(b) self._checked = b end
    function w:GetChecked() return self._checked end
    function w:Enable()    self._enabled = true end
    function w:Disable()   self._enabled = false end
    function w:SetEnabled(b) self._enabled = b end
    function w:IsEnabled() return self._enabled ~= false end
    function w:SetAlpha(a) self._alpha = a end
    function w:EnableMouse(b) self._mouseEnabled = b end
    function w:RegisterForClicks() end
    -- Nested check for labeled-checkbox widget kind
    w._check = nil
    return w
end

-- Build a rootFrame populated with every widget ID declared in LayoutConfig.
-- This is the union set; any controller that looks up a known ID will find
-- a spy stub, and any that looks up an UNKNOWN ID will get nil (the silent
-- failure we're hunting).
local function buildSpyRootFrame()
    local widgets = {}
    if VDS.LayoutConfig and VDS.LayoutConfig.widgets then
        for id, spec in pairs(VDS.LayoutConfig.widgets) do
            local w = makeSpyWidget(id)
            -- Kind-specific internals built by the real build() that Wire()
            -- reaches into (mock-fidelity: extend the spy, never guard
            -- production code). recentDyeStrip: fixed pool of swatch buttons.
            if spec.kind == "recentDyeStrip" then
                w._swatches = { makeSpyWidget(id .. ".swatch1"),
                                makeSpyWidget(id .. ".swatch2") }
                w._marker   = makeSpyWidget(id .. ".marker")
            end
            widgets[id] = w
        end
    end
    return { widgets = widgets }
end

-- ===== Wire smoke: every controller must Wire() without crashing =====
-- This catches typos in widget-ID lookups + nil-method calls early.
local controllers = {
    Controller_Title     = VDS.Controller_Title,
    Controller_Browse    = VDS.Controller_Browse,
    Controller_Detail    = VDS.Controller_Detail,
    Controller_Search    = VDS.Controller_Search,
    Controller_Canvas    = VDS.Controller_Canvas,
    Controller_Live      = VDS.Controller_Live,
    Controller_LiveBridge = VDS.Controller_LiveBridge,
    Controller_Minimap   = VDS.Controller_Minimap,
    Controller_Warehouse = VDS.Controller_Warehouse,
    Controller_Harmony   = VDS.Controller_Harmony,
}

local wired = 0
for name, ctrl in pairs(controllers) do
    if ctrl and ctrl.Wire then
        local root = buildSpyRootFrame()
        local ok, err = pcall(function() ctrl:Wire(root) end)
        assertTrue(ok, name .. ":Wire() must not crash. Error: " .. tostring(err))
        wired = wired + 1
    end
end
assertTrue(wired >= 5, "expected at least 5 controllers with Wire() methods, got " .. wired)

-- ===== Defensive: Wire on empty rootFrame MUST NOT crash =====
-- Production guard pattern -- Controllers handle missing widgets gracefully.
for name, ctrl in pairs(controllers) do
    if ctrl and ctrl.Wire then
        local emptyRoot = { widgets = {} }
        local ok, err = pcall(function() ctrl:Wire(emptyRoot) end)
        assertTrue(ok, name .. ":Wire() on empty widgets must not crash: " .. tostring(err))
    end
end

-- ===== Targeted dispatch test: Title controller =====
-- The most-used controller; covers the OnClick → Dispatch path that's the
-- most common silent-failure surface.
if VDS.Controller_Title and VDS.Controller_Title.Wire then
    -- Capture dispatches.
    local dispatched = {}
    local origDispatch = VDS.Store.Dispatch
    VDS.Store.Dispatch = function(self, action)
        dispatched[#dispatched + 1] = action
    end

    local root = buildSpyRootFrame()
    VDS.Controller_Title:Wire(root)

    -- Find a Title checkbox + simulate click.
    local titleIds = { "title.configBtn", "title.helpBtn",
                       "config.autoSaveCheck", "config.replaceCheck",
                       "config.minimapCheck", "config.debugCheck" }

    local knownActions = {}
    for _, v in pairs(VDS.Constants.ACTIONS) do knownActions[v] = true end

    local clickedAny = false
    for _, id in ipairs(titleIds) do
        local w = root.widgets[id]
        if w then
            local target = w._check or w
            local handler = target:GetScript("OnClick")
            if handler then
                clickedAny = true
                dispatched = {}
                local ok, err = pcall(function() handler(target) end)
                if ok and #dispatched > 0 then
                    -- A dispatch happened -- verify it's a known action type.
                    for _, action in ipairs(dispatched) do
                        assertTrue(action.type ~= nil,
                            "Click on " .. id .. " dispatched action with no type field")
                        assertTrue(knownActions[action.type] ~= nil,
                            "Click on " .. id .. " dispatched unknown action type: "
                            .. tostring(action.type))
                    end
                end
            end
        end
    end
    assertTrue(clickedAny, "Title controller should have attached at least one OnClick handler")

    VDS.Store.Dispatch = origDispatch
end

print(string.format("test_controller_wire_smoke.lua passed (%d controllers wired)", wired))
