local Direction = require("lib.direction")
local TurtleController = require("controller.turtle_controller")

---@class TestingController
---@field controller TurtleController
local TestingController = {}
TestingController.__index = TestingController

---@return TestingController
function TestingController:Create()
	local t = {}
	setmetatable(t, TestingController)

	t.controller = TurtleController:Create()

	return t
end

-----------------------------------------------------------------------------------------------
-- Behavior Methods
-----------------------------------------------------------------------------------------------

function TestingController:TestRelativeMovementWithRelativeRotation()
	print("Testing relative movement with relative rotation...")

	-- N: BackCenter (Center)
	self.controller:MoveForward(3)
	self.controller:TurnRelative(1) -- E: FrontCenter (Center)
	self.controller:MoveForward(3)
	self.controller:TurnRelative(2) -- W: FrontRight (Center)
	self.controller:MoveVertical(3)
	self.controller:TurnRelative(8) -- W: FrontRight (Top)
	self.controller:MoveForward(3)
	self.controller:TurnRelative(3) -- S: FrontCenter (Top)
	self.controller:MoveForward(3)
	self.controller:TurnRelative(9) -- W: BackCenter (Top)
	self.controller:MoveVertical(-3)
	self.controller:TurnRelative(1) -- N: BackCenter (Center)

	print("The turtle should be in its original location.")
	print(
		("The turtle has internal position (%d, %d, %d) and internal direction %d"):format(
			self.controller.position.x,
			self.controller.position.y,
			self.controller.position.z,
			self.controller.position.dir
		)
	)
	print("Press Enter to continue")
	_ = io.read()
end

function TestingController:TestRelativeMovementWithAbsoluteRotation()
	print("Testing relative movement with absolute rotation...")

	-- N: BackCenter (Center)
	self.controller:MoveForward(3)
	self.controller:TurnToDirection(Direction.EAST) -- E: FrontCenter (Center)
	self.controller:MoveForward(3)
	self.controller:TurnToDirection(Direction.WEST) -- W: FrontRight (Center)
	self.controller:MoveVertical(3)
	self.controller:TurnToDirection(Direction.WEST) -- W: FrontRight (Top)
	self.controller:MoveForward(3)
	self.controller:TurnToDirection(Direction.SOUTH) -- S: FrontCenter (Top)
	self.controller:MoveForward(3)
	self.controller:TurnToDirection(Direction.WEST) -- W: BackCenter (Top)
	self.controller:MoveVertical(-3)
	self.controller:TurnToDirection(Direction.NORTH) -- N: BackCenter (Center)

	print("The turtle should be in its original location.")
	print(
		("The turtle has internal position (%d, %d, %d) and internal direction %d"):format(
			self.controller.position.x,
			self.controller.position.y,
			self.controller.position.z,
			self.controller.position.dir
		)
	)
	print("Press Enter to continue")
	_ = io.read()
end

function TestingController:TestAbsoluteMovementWithoutStack()
	print("Testing absolute movement without stack...")

	-- N: BackCenter (Center)
	self.controller:MoveToPosition(0, 0, 3, Direction.EAST) -- E: FrontCenter (Center)
	self.controller:MoveToPosition(3, 0, 3, Direction.WEST) -- W: FrontRight (Center)
	self.controller:MoveToPosition(3, 3, 3, Direction.WEST) -- W: FrontRight (Top)
	self.controller:MoveToPosition(0, 3, 3, Direction.SOUTH) -- S: FrontCenter (Top)
	self.controller:MoveToPosition(0, 3, 0, Direction.WEST) -- W: BackCenter (Top)
	self.controller:MoveToPosition(0, 0, 0, Direction.NORTH) -- N: BackCenter (Center)

	print("The turtle should be in its original location.")
	print(
		("The turtle has internal position (%d, %d, %d) and internal direction %d"):format(
			self.controller.position.x,
			self.controller.position.y,
			self.controller.position.z,
			self.controller.position.dir
		)
	)
	print("Press Enter to continue")
	_ = io.read()
end

function TestingController:TestAbsoluteMovementWithStack()
	print("Testing absolute movement with stack...")

	-- N: BotCenter (Center)
	self.controller:MoveToPosition(0, 0, 3, Direction.EAST) -- E: TopCenter (Center)
	self.controller:MoveBack() -- N: BotCenter (Center)
	self.controller:MoveToPosition(3, 3, 3, Direction.WEST) -- W: TopRight (Top)
	self.controller:MoveBack() -- N: BotCenter (Center)

	print("The turtle should be in its original location.")
	print(
		("The turtle has internal position (%d, %d, %d) and internal direction %d"):format(
			self.controller.position.x,
			self.controller.position.y,
			self.controller.position.z,
			self.controller.position.dir
		)
	)
	print("Press Enter to continue")
	_ = io.read()
end

function TestingController:TestUnstocking()
	print("Testing inventory unloading...")

	self.controller:MoveToPosition(3, 0, 3, Direction.WEST)
	print("Please fill the entire inventory with items.")
	print("Press Enter to continue")
	_ = io.read()
	self.controller:UnstockIfFull(true)
	print("Press Enter to continue")
	_ = io.read()
	self.controller:MoveBack()

	print("The turtle should be in its original location.")
	print("Press Enter to continue")
	_ = io.read()
end

function TestingController:TestRefueling()
	print("Testing refueling...")

	self.controller:MoveToPosition(3, 0, 3, Direction.WEST)
	print("Please fill multiple inventory slots with items.")
	print("Press Enter to continue")
	_ = io.read()
	self.controller:RefuelIfEmpty(true)
	print("Press Enter to continue")
	_ = io.read()
	self.controller:MoveBack()

	print("The turtle should be in its original location.")
	print("Press Enter to continue")
	_ = io.read()
end

-----------------------------------------------------------------------------------------------
-- Main Method
-----------------------------------------------------------------------------------------------

function TestingController:Run()
	self.controller:Configure()
	self.controller:DisableMiningForward()
	self.controller:DisableMiningAbove()
	self.controller:DisableMiningBelow()

	print("There are multiple tests available:")
	print("1: Relative movement with relative rotation")
	print("2: Relative movement with absolute rotation")
	print("3: Absolute movement without stack")
	print("4: Absolute movement with stack")
	print("5: All movement tests")
	print("6: Unloading")
	print("7: Refueling")
	print("8: All non-movement tests")
	print("9: All tests")

	local choice = 0
	while choice < 1 or choice > 9 do
		print("Choose a test by entering its number:")
		choice = tonumber(io.read()) or 0
	end

	if choice == 1 then
		self:TestRelativeMovementWithRelativeRotation()
	elseif choice == 2 then
		self:TestRelativeMovementWithAbsoluteRotation()
	elseif choice == 3 then
		self:TestAbsoluteMovementWithoutStack()
	elseif choice == 4 then
		self:TestAbsoluteMovementWithStack()
	elseif choice == 5 then
		self:TestRelativeMovementWithRelativeRotation()
		self:TestRelativeMovementWithAbsoluteRotation()
		self:TestAbsoluteMovementWithoutStack()
		self:TestAbsoluteMovementWithStack()
	elseif choice == 6 then
		self:TestUnstocking()
	elseif choice == 7 then
		self:TestRefueling()
	elseif choice == 8 then
		self:TestUnstocking()
		self:TestRefueling()
	elseif choice == 9 then
		self:TestRelativeMovementWithRelativeRotation()
		self:TestRelativeMovementWithAbsoluteRotation()
		self:TestAbsoluteMovementWithoutStack()
		self:TestAbsoluteMovementWithStack()
		self:TestUnstocking()
		self:TestRefueling()
	end
end

return TestingController
