local have_ui = minetest.get_modpath("unified_inventory")
local have_cg = minetest.get_modpath("craftguide") and craftguide and
                    craftguide.register_craft
local S = ele.translator

elepm.craft = {}
elepm.craft.types = {}

local function item_string(...)
    -- body
end

function elepm.register_craft_type(name, def)
    elepm.craft.types[name] = {
        inputs = def.inputs or 2,
        description = def.description or name,
        overview = def.overview or name,
        time = def.time or 0,
        gui_name = def.gui_name
    }

    elepm.craft[name] = {}

    -- Don't register cooking or fuel types externally.
    if name == "cooking" or name == "fuel" then return end

    if have_ui and unified_inventory.register_craft_type then
        unified_inventory.register_craft_type(name, {
            description = def.description or name,
            icon = def.icon or "elepower_machine_side.png",
            width = def.inputs or 2,
            height = 1
        })
    end

    if have_cg then
        craftguide.register_craft_type(name, {
            description = def.description,
            icon = def.icon or "elepower_machine_side.png"
        })
    end
end

function elepm.register_craft(craftdef)
    if not craftdef.type or not elepm.craft.types[craftdef.type] then
        return nil
    end

    if craftdef.type == "cooking" or craftdef.type == "fuel" then
        minetest.register_craft(craftdef)
        return
    end

    local inputs = craftdef.recipe
    local outputs = craftdef.output
    local ctype = craftdef.type
    local ctypedef = elepm.craft.types[ctype]
    local time = (craftdef.time or craftdef.cooktime or 5) +
                     (ctypedef.time or 0)

    local craftrecipe = {}

    -- Recipe inputs are stored as hybridization of standard furnace and regular crafting
    -- Table is structured as example
    -- input{{[default:tin_ingot]=1},{[default:tin_ingot]=1}}
    -- to contrast "cooking" recipes are stored as
    -- input{[default:iron_ore]=1}
    -- to contrast normal craft recipes are stored as and always assume x1:
    -- input:{
    --       {item,item,item},
    --       {item,item,item},
    --       {item,item,item}
    --       }

    for _, input in ipairs(inputs) do
        local stack = ItemStack(input)
        if stack and not stack:is_empty() then
            table.insert(craftrecipe, {[stack:get_name()] = stack:get_count()})
        end
    end

    local craftresult = {}
    if type(outputs) == "table" then
        for _, output in ipairs(outputs) do
            local stack = ItemStack(output)
            if stack and not stack:is_empty() then
                craftresult[#craftresult + 1] = stack:to_string()
            end
        end
    else
        craftresult = ItemStack(outputs)
    end

    local recipe = {recipe = craftrecipe, output = craftresult, time = time}

    table.insert(elepm.craft[ctype], recipe)

    if have_ui or have_cg then
        local spec = {}
        local items = {}

        for _, def in pairs(recipe.recipe) do
            for item, count in pairs(def) do
                local stack = ItemStack(item)
                stack:set_count(count)
                spec[#spec + 1] = stack
                items[#items + 1] = stack:to_string()
            end
        end

        if type(recipe.output) == "table" then
            for _, itm in pairs(recipe.output) do
                local itmst = ItemStack(itm)
                if have_ui then
                    unified_inventory.register_craft({
                        type = craftdef.type,
                        output = itmst,
                        items = spec,
                        width = ctypedef.inputs
                    })
                end

                if have_cg then
                    craftguide.register_craft({
                        type = craftdef.type,
                        output = itmst:to_string(),
                        items = items,
                        width = ctypedef.inputs
                    })
                end
            end
            return
        end

        if have_ui then
            unified_inventory.register_craft({
                type = craftdef.type,
                output = recipe.output,
                items = spec,
                width = ctypedef.inputs
            })
        end

        if have_cg then
            craftguide.register_craft({
                type = craftdef.type,
                output = recipe.output:to_string(),
                items = items,
                width = ctypedef.inputs
            })
        end
    end
end

local no_recipe = {time = 0, new_input = {}, output = {}}

function elepm.get_recipe(type, inputs)

    if not elepm.craft[type] or not inputs then return no_recipe end

    -- Minetest's cooking builtin type
    if type == "cooking" then
        local result, new_input = minetest.get_craft_result({
            method = "cooking",
            width = 1,
            items = inputs
        })

        if not result or result.time == 0 then
            return no_recipe
        else
            return {
                time = result.time,
                new_input = new_input.items,
                output = result.item
            }
        end
    end

    -- Custom types
    local result = no_recipe
    local recipe_match = false
    local new_input = {}
    local sp_recipe
    local count

    for rec_num, recipe in pairs(elepm.craft[type]) do
        sp_recipe = 0
        count = 0

        for item_num, items in pairs(recipe.recipe) do -- items = {value4 = 1}			
            for pos, input in pairs(inputs) do
                local in_name = input:get_name()
                if items[in_name] and -- is input_name in recipe
                items[in_name] <= input:get_count() and -- do we have enough materials in input
                pos == item_num then -- are we in correct pos/slot

                    sp_recipe = rec_num
                    count = count + 1
                end
            end
        end

        if count == #inputs then
            recipe_match = true
            break
        end
    end

    if recipe_match == true then

        for item_num, items in pairs(elepm.craft[type][sp_recipe]["recipe"]) do

            for name, num in pairs(items) do

                local istack = ItemStack(name)
                istack:set_count(inputs[item_num]:get_count() - num)
                new_input[#new_input + 1] = istack

            end
        end

        result = elepm.craft[type][sp_recipe] -- includes recipe,time,output
        result.new_input = new_input
    else
        -- minetest.debug("no match")          -- useful for debugging
    end

    return result
end

-- Cooking craft type built-in.
elepm.register_craft_type("cooking", {
    description = S("Cooking"),
    overview = S("Cooking is more than just the preparation of food, " ..
                     "it provides access to the preparation of ores to metals " ..
                     "and the creation of glass and glass objects."),
    inputs = 1
})
