-- IndustrialTest
-- Copyright (C) 2025 mrkubax10

-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.

-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.

-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.

local S=minetest.get_translator("industrialtest")

industrialtest.SimpleElectricItemProcessor=table.copy(industrialtest.ActivatedElectricMachine)
industrialtest.internal.unpackTableInto(industrialtest.SimpleElectricItemProcessor,{
	facedir=true,
	sounds="metal",
	storageLists={
		"src",
		"dst",
		"powerStorage",
		"upgrades"
	},
	powerLists={
		{
			list="powerStorage",
			direction="i"
		}
	},
	hasPowerInput=true,
	ioConfig="iiiiii"
})

function industrialtest.SimpleElectricItemProcessor.onConstruct(self,pos)
	local meta=minetest.get_meta(pos)
	local inv=meta:get_inventory()
	inv:set_size("src",1)
	inv:set_size("dst",1)
	inv:set_size("powerStorage",1)
	inv:set_size("upgrades",4)
	meta:set_float("srcTime",-1)
	meta:set_float("maxSrcTime",0)
	industrialtest.ActivatedElectricMachine.onConstruct(self,pos)
end

function industrialtest.SimpleElectricItemProcessor.getFormspec(self,pos)
	local parentFormspec=industrialtest.ActivatedElectricMachine.getFormspec(self,pos)
	local meta=minetest.get_meta(pos)
	local powerPercent=meta:get_int("industrialtest.powerAmount")/meta:get_int("industrialtest.powerCapacity")*100
	local srcPercent=meta:get_float("srcTime")/meta:get_float("maxSrcTime")*100
	local recipeOverride=self.isRecipeOverride(meta)
	local formspec={
		(recipeOverride and "label[3.4,1.5;"..S("Recipe override: @1", minetest.registered_items[recipeOverride].description).."]" or ""),
		industrialtest.internal.getItemSlotBg(3.4,1.8,1,1),
		"list[context;src;3.4,1.8;1,1]",
		(powerPercent>0 and "image[3.4,2.8;1,1;industrialtest_gui_electricity_bg.png^[lowpart:"..powerPercent..":industrialtest_gui_electricity_fg.png]"
		 or "image[3.4,2.8;1,1;industrialtest_gui_electricity_bg.png]"),
		industrialtest.internal.getItemSlotBg(3.4,3.9,1,1),
		"list[context;powerStorage;3.4,3.9;1,1]",
		(srcPercent>0 and "image[4.9,2.8;1,1;gui_furnace_arrow_bg.png^[lowpart:"..srcPercent..":gui_furnace_arrow_fg.png^[transformR270]"
		 or "image[4.9,2.8;1,1;gui_furnace_arrow_bg.png^[transformR270]"),
		industrialtest.internal.getItemSlotBg(6.4,2.8,1,1),
		"list[context;dst;6.4,2.8;1,1]",
		industrialtest.internal.getItemSlotBg(9,0.9,1,4),
		"list[context;upgrades;9,0.9;1,4]",
		"listring[context;src]",
		"listring[context;dst]"
	}
	return parentFormspec..table.concat(formspec,"")
end

function industrialtest.SimpleElectricItemProcessor.allowMetadataInventoryMove(self,pos,fromList,fromIndex,toList,count)
	if toList=="dst" then
		return 0
	end
	return industrialtest.ActivatedElectricMachine.allowMetadataInventoryMove(self,pos,fromList,fromIndex,toList,count)
end

function industrialtest.SimpleElectricItemProcessor.allowMetadataInventoryPut(self,pos,listname,index,stack)
	if listname=="dst" then
		return 0
	elseif listname=="src" then
		local meta=minetest.get_meta(pos)
		local inv=meta:get_inventory()
		local srcSlot=inv:get_stack("src",1)
		if srcSlot:get_name()~=stack:get_name() then
			meta:set_float("srcTime",-1)
			meta:set_float("maxSrcTime",0)
		end
	end
	return industrialtest.ActivatedElectricMachine.allowMetadataInventoryPut(self,pos,listname,index,stack)
end

function industrialtest.SimpleElectricItemProcessor.onMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count)
	industrialtest.ActivatedElectricMachine.onMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count)
	local meta=minetest.get_meta(pos)
	local inv=meta:get_inventory()
	local srcSlot=inv:get_stack("src",1)
	local dstSlot=inv:get_stack("dst",1)
	if fromList=="src" and srcSlot:is_empty() then
		meta:set_float("srcTime",-1)
		meta:set_float("maxSrcTime",0)
		self:updateFormspec(pos)
	elseif fromList=="dst" and dstSlot:get_free_space()>0 then
		self:triggerIfNeeded(pos)
	end
end

function industrialtest.SimpleElectricItemProcessor.onMetadataInventoryPut(self,pos,listname,index,stack)
	industrialtest.ActivatedElectricMachine.onMetadataInventoryPut(self,pos,listname,index,stack)
	self:triggerIfNeeded(pos)
end

function industrialtest.SimpleElectricItemProcessor.onMetadataInventoryTake(self,pos,listname,index,stack)
	industrialtest.ActivatedElectricMachine.onMetadataInventoryTake(self,pos,listname,index,stack)
	local meta=minetest.get_meta(pos)
	local inv=meta:get_inventory()
	local srcSlot=inv:get_stack("src",1)
	local dstSlot=inv:get_stack("dst",1)
	if listname=="src" and srcSlot:is_empty() then
		meta:set_float("srcTime",-1)
		meta:set_float("maxSrcTime",0)
		self:updateFormspec(pos)
	elseif listname=="dst" and dstSlot:get_free_space()>0 then
		self:triggerIfNeeded(pos)
	end
end

function industrialtest.SimpleElectricItemProcessor.register(self)
	industrialtest.ActivatedElectricMachine.register(self)
	industrialtest.api.addTag(self.name,"simpleElectricItemProcessor")
end

function industrialtest.SimpleElectricItemProcessor.shouldActivate(self,pos)
	local meta=minetest.get_meta(pos)
	local inv=meta:get_inventory()

	if meta:get_float("maxSrcTime")>0 and meta:get_float("srcTime")>=0 then
		return false
	end

	-- TODO: Take elapsed time into account
	local requiredPower=self.opPower*industrialtest.api.getMachineSpeed(meta)
	if meta:get_int("industrialtest.powerAmount")<requiredPower then
		return false
	end

	local srcSlot=inv:get_stack("src",1)
	if srcSlot:get_count()>0 then
		local output=self:getCraftResult(srcSlot)
		return output and output.time>0 and inv:room_for_item("dst",output.item)
	end

	return meta:contains("recipeOverride") and meta:contains("recipeOverrideMaxTime") and meta:get_string("recipeOverride")~=""
end

function industrialtest.SimpleElectricItemProcessor.shouldDeactivate(self,pos)
	local meta=minetest.get_meta(pos)
	local inv=meta:get_inventory()

	-- TODO: Take elapsed time into account
	local requiredPower=self.opPower*industrialtest.api.getMachineSpeed(meta)
	if meta:get_int("industrialtest.powerAmount")<requiredPower then
		return true
	end

	if meta:contains("recipeOverride") and meta:contains("recipeOverrideMaxTime") and meta:get_string("recipeOverride")~="" then
		return false
	end

	local srcSlot=inv:get_stack("src",1)
	if srcSlot:is_empty() then
		return true
	end

	local output=self:getCraftResult(srcSlot)
	return not output or output.time==0 or not inv:room_for_item("dst",output.item)
end

function industrialtest.SimpleElectricItemProcessor.activeUpdate(self,pos,elapsed,meta,inv)
	local srcSlot=inv:get_stack("src",1)

	local srcTime=0
	local maxSrcTime
	if meta:get_float("maxSrcTime")<=0 then
		local recipeOverride=self.isRecipeOverride(meta)
		if recipeOverride then
			maxSrcTime=meta:get_int("recipeOverrideMaxTime")
		else
			local output=self:getCraftResult(srcSlot)
			maxSrcTime=output.time*self.efficiency
		end
		meta:set_float("srcTime",0)
		meta:set_float("maxSrcTime",maxSrcTime)
	else
		srcTime=meta:get_float("srcTime")
		maxSrcTime=meta:get_float("maxSrcTime")
	end

	local speed=industrialtest.api.getMachineSpeed(meta)
	local requiredPower=elapsed*self.opPower*speed
	industrialtest.api.addPower(meta,-requiredPower)
	srcTime=srcTime+elapsed
	meta:set_int("srcTime",srcTime)

	if srcTime>=maxSrcTime then
		local recipeOverride=self.isRecipeOverride(meta)
		if recipeOverride then
			inv:add_item("dst",ItemStack(recipeOverride))
			meta:set_string("recipeOverride","")
		else
			local output=self:getCraftResult(srcSlot)
			local usedItems=srcSlot:get_count()-output.src:get_count()
			local multiplier=1
			if srcSlot:get_count()>=speed*usedItems then
				multiplier=speed
			end
			if output.item:get_count()>0 then
				output.item:set_count(output.item:get_count()*multiplier)
				inv:add_item("dst",output.item)
			end
			srcSlot:set_count(srcSlot:get_count()-multiplier*usedItems)
			inv:set_stack("src",1,srcSlot)
		end
		meta:set_float("srcTime",-1)
		meta:set_float("maxSrcTime",0)
	end

	return true
end

function industrialtest.SimpleElectricItemProcessor.isRecipeOverride(meta)
	if meta:contains("recipeOverride") and meta:contains("recipeOverrideMaxTime") and meta:get_string("recipeOverride")~="" then
		return meta:get_string("recipeOverride")
	end
	return false
end

function industrialtest.SimpleElectricItemProcessor.getCraftResult(self,itemstack)
	-- Dummy method
end
