-- HousingDecorGuide/tests/test_mogul_lp.lua
---@diagnostic disable: undefined-global
package.path = "./?.lua;" .. package.path
local t = require("test_helpers")

_G.HDG = _G.HDG or {}
local Mogul = dofile("../modules/HDG_Mogul.lua")
local MogulLP = dofile("../modules/HDG_MogulLP.lua")

-- Same fixture style as test_mogul.lua
local function makeRecipe(spec)
    return {
        itemID = spec.id,
        name = spec.name,
        spellID = spec.spell or (1000 + spec.id),
        profession = spec.profession or "Carpentry",
        expansion = spec.expansion or "Midnight",
        reagents = spec.reagents,
        salePrice = spec.salePrice,
        uncollected = spec.uncollected or 0,
        knownByActive = spec.knownByActive ~= false,
        bestAlt = spec.bestAlt,
    }
end

local function makeCtx(spec)
    return {
        algorithm = "lp",
        lumberBudgets = spec.lumberBudgets or {},
        ownedMats = spec.ownedMats or {},
        matPrices = spec.matPrices or {},
        lumberIDs = spec.lumberIDs or { [190316] = true },
        candidates = spec.candidates,
        mode = spec.mode or "profit",
        optimizeBy = spec.optimizeBy or "lumberOnly",
        viewMode = spec.viewMode or "char",
    }
end

t.describe("HDG_MogulLP - basic correctness", function()
    t.it("produces empty plan when no candidates", function()
        local out = MogulLP.BuildPlan(makeCtx({
            lumberBudgets = { [190316] = 1000 },
            candidates = {},
        }))
        t.assert_eq(#out.rows, 0)
        t.assert_eq(out.totals.crafts, 0)
    end)

    t.it("matches greedy on single positive-profit single-tier recipe", function()
        local r = makeRecipe({
            id = 1, name = "Bookcase",
            reagents = { { id = 190316, qty = 24 } },
            salePrice = 10000,
        })
        local ctx = {
            lumberBudgets = { [190316] = 100 },
            candidates = { r },
            lumberIDs = { [190316] = true },
            mode = "profit",
            optimizeBy = "lumberOnly",
        }
        local greedyOut = Mogul.BuildPlan(ctx)
        local lpCtx = {}
        for k, v in pairs(ctx) do lpCtx[k] = v end
        lpCtx.algorithm = "lp"
        local lpOut = Mogul.BuildPlan(lpCtx)
        t.assert_eq(lpOut.rows[1].crafts, greedyOut.rows[1].crafts)
        t.assert_eq(lpOut.totals.revenue, greedyOut.totals.revenue)
    end)

    t.it("respects per-tier lumber budgets (Sturdy vs Polished)", function()
        local sturdy = makeRecipe({
            id = 10, name = "Sturdy",
            reagents = { { id = 190316, qty = 10 } },
            salePrice = 1000,
        })
        local polished = makeRecipe({
            id = 11, name = "Polished",
            reagents = { { id = 190317, qty = 10 } },
            salePrice = 1000,
        })
        local out = MogulLP.BuildPlan(makeCtx({
            lumberBudgets = { [190316] = 50, [190317] = 30 },
            candidates    = { sturdy, polished },
            lumberIDs     = { [190316] = true, [190317] = true },
        }))
        t.assert_eq(#out.rows, 2)
        local crafts = {}
        for _, row in ipairs(out.rows) do crafts[row.recipe.itemID] = row.crafts end
        t.assert_eq(crafts[10], 5)   -- 50 / 10
        t.assert_eq(crafts[11], 3)   -- 30 / 10
    end)

    t.it("ranks multi-tier by binding tier (matches greedy fix)", function()
        local x = makeRecipe({
            id = 40, name = "Multi-tier",
            reagents = { { id = 190316, qty = 5 }, { id = 190317, qty = 5 } },
            salePrice = 1500,
        })
        local y = makeRecipe({
            id = 41, name = "Sturdy-only",
            reagents = { { id = 190316, qty = 6 } },
            salePrice = 800,
        })
        local out = MogulLP.BuildPlan(makeCtx({
            lumberBudgets = { [190316] = 10, [190317] = 10 },
            candidates    = { x, y },
            lumberIDs     = { [190316] = true, [190317] = true },
        }))
        -- LP should pick X (uses both tiers in parallel; better total profit on this budget)
        t.assert_eq(#out.rows, 1)
        t.assert_eq(out.rows[1].recipe.itemID, 40)
        t.assert_eq(out.rows[1].crafts, 2)
    end)

    t.it("delegates collection mode to greedy", function()
        local r = makeRecipe({
            id = 50, name = "Uncoll",
            reagents = { { id = 190316, qty = 5 } },
            uncollected = 1,
            salePrice = 1000,
        })
        local out = MogulLP.BuildPlan(makeCtx({
            lumberBudgets = { [190316] = 100 },
            candidates    = { r },
            mode          = "collection",
            lumberIDs     = { [190316] = true },
        }))
        t.assert_eq(#out.rows, 1)
        t.assert_eq(out.rows[1].crafts, 1)        -- collection rule: one craft each
        t.assert_eq(out.totals.newAppearances, 1)
    end)

    t.it("dispatch via Mogul.BuildPlan(algorithm = lp) routes here", function()
        local r = makeRecipe({
            id = 1, name = "Test",
            reagents = { { id = 190316, qty = 10 } },
            salePrice = 1000,
        })
        local out = Mogul.BuildPlan({
            algorithm = "lp",
            mode = "profit",
            lumberBudgets = { [190316] = 50 },
            candidates = { r },
            lumberIDs = { [190316] = true },
        })
        t.assert_eq(#out.rows, 1)
        t.assert_eq(out.rows[1].crafts, 5)
    end)
end)
