love.math.setRandomSeed(os.time())

local input = require "util.input"

-- Gamestates
--local won = require "gamestates.won" --TODO MAKE THIS
local lost = require "gamestates.lost"
local paused = require "gamestates.paused"

-- This Gamestate
local game = {}

-- Locals
local boxes = {}
local score, totalScore = 0, 0
local level, time, startingTime = 0, 0, 0
local previousState, gameSettings, controls
local pingTimer, session = 0, false
--these are defined on each entry to this gamestate
local screenWidth, screenHeight              --defines where things are rendered
local boxColumns, boxRows                    --defines how many boxes
--these are loaded from values passed on entry to this gamestate
local boxSize, colorStep, timeLimit = 20, 80, 60 --default values just in case

local function nextLevel()
	log("Creating the next level!")

	totalScore = totalScore + score
	score = 0
	level = level + 1
	time = time + timeLimit --your remaining time is added on to the next level
	startingTime = time     --save where you started on this level for scoring

	-- (re)create black boxes
	boxes = {}
	for i=0,boxColumns do
		boxes[i] = {}
		for j=0,boxRows do
			boxes[i][j] = {0, 0, 0}
		end
	end

	-- assign a random set of boxes random colors
	for i=1,math.floor(math.pow(level, 1.07) * 1.03 + 2) do --(level * 1.5 + 2)
		local x, y = love.math.random(0, #boxes), love.math.random(0, #boxes[1])
		boxes[x][y] = {love.math.random(0, 255), love.math.random(0, 255), love.math.random(0, 255)}
		boxes[x][y][1] = boxes[x][y][1] - boxes[x][y][1] % colorStep --is this right?
		boxes[x][y][2] = boxes[x][y][2] - boxes[x][y][2] % colorStep
		boxes[x][y][3] = boxes[x][y][3] - boxes[x][y][3] % colorStep
	end

	log("Done!")
end

local function colorsEqual(A, B)
	if A[1] == B[1] and A[2] == B[2] and A[3] == B[3] then
		return true
	end
	return false
end

local function copyColor(A)
	return {A[1], A[2], A[3]}
end

function game:enter(previous, settings, gameControls, gamejoltSession)
	log("Entering game...")
	-- save the state we came from
	previousState = previous
	-- set locals based on screen size
	screenWidth = love.graphics.getWidth()
	screenHeight = love.graphics.getHeight()
	boxColumns = math.floor(screenWidth / boxSize) - 1
	boxRows = math.floor(screenHeight / boxSize) - 5
	-- save the settings for later use
	gameSettings = settings or gameSettings
	controls = gameControls or controls
	session = gamejoltSession
	-- ping our active state immediately
	if session then
		local pingSuccess = Gamejolt.pingSession(true)
		if not pingSuccess then
			log("Couldn't ping Game Jolt session. Session may close.")
		end
	end
	-- set how to play the game based on settings
	boxSize = gameSettings.boxSize
	colorStep = gameSettings.colorStep
	timeLimit = gameSettings.timeLimit
	-- set the font we're going to use
	love.graphics.setNewFont(28)
	-- this is nextLevel shit
	nextLevel()
end

function game:resume(previous, action)
	if action == "LOST" then
		log("Game restarted.")
		game:enter(previousState) --we want to keep the old values
		totalScore = 0            --this should have happened in game:leave() but does not for an unknown reason
	end
	if action == "UNPAUSED" then
		log("Game resumed.")
		love.graphics.setNewFont(28) -- fix our font!
	end
end

function game:update(dt)
	-- ping every 30 seconds if we are in a session
	pingTimer = pingTimer + dt
	if pingTimer >= 30 then
		if session then
			local pingSuccess = Gamejolt.pingSession(true)
			if not pingSuccess then
				log("Couldn't ping Game Jolt session. Session may close.") --this is lazy but I don't care
			end
		end
		pingTimer = pingTimer - 30
	end

	-- check if level complete
	local coloredBoxes = {}
	for i=0,#boxes do
		for j=0,#boxes[i] do
			if not colorsEqual(boxes[i][j], {0, 0, 0}) then
				table.insert(coloredBoxes, boxes[i][j])
			end
		end
	end
	local won, color
	if #coloredBoxes >= 2 then
		won = true
		color = copyColor(coloredBoxes[1])
		for i=2,#coloredBoxes do
			if not colorsEqual(color, coloredBoxes[i]) then
				won = false
			end
		end
	end
	if won then
		log("Level beat!")
		-- TODO we need a brief push/pop of gamestate to display a winning message
		nextLevel()
	end

	-- else decrement time, and check if out of time
	time = time - dt
	if time <= 0 then
		-- TODO we need to pass an image of the screen and data about time of losing
		Gamestate.push(lost, love.graphics.newScreenshot(), totalScore + score, controls, session)
		-- call leave to clean up the gamestate
		game:leave()
	end

	-- update the current score
	score = #coloredBoxes / math.pow(startingTime - time, 0.02) * colorStep
end

function game:draw()
	--boxes
	for i=0,#boxes do
		for j=0,#boxes[i] do
			love.graphics.setColor(boxes[i][j])
			love.graphics.rectangle("fill", i * boxSize, j * boxSize + boxSize * 2, boxSize, boxSize)
		end
	end

	--lines
	-- vertical
	love.graphics.setColor(255, 255, 255)
	for i=0,boxColumns+1 do
		love.graphics.line(i * boxSize, 0 + boxSize * 2, i * boxSize, screenHeight - boxSize * 2)

	end
	-- horizontal
	for j=0,boxRows+1 do
		love.graphics.line(0, j * boxSize + boxSize * 2, screenWidth, j * boxSize + boxSize * 2)
	end

	-- Info Overlays
	--love.graphics.setNewFont(28) --purposely stays same no matter screen res
	love.graphics.setColor(255, 255, 255)
	-- top of screen stuff
	love.graphics.printf(string.format("Total Score: %.1f", totalScore), 0, 3, screenWidth / 2, "center")
	--love.graphics.printf(string.format("Best Score: %.1f", bestScore), screenWidth / 2, 3, screenWidth / 2, "center")

	-- bottom of screen stuff
	love.graphics.printf(string.format("Time: %.1f", time), 0, screenWidth / 2 + 25, screenWidth / 2, "center")
	love.graphics.printf("Level: "..level, 0, screenWidth / 2 + 25, screenWidth, "center")
	love.graphics.printf(string.format("Current Score: %.1f", score), screenWidth / 2, screenWidth / 2 + 25, screenWidth / 2, "center")
end

function game:mousepressed(x, y, button)
	-- new x/y adjusted for where boxes actually are
	local nx = math.floor(x / boxSize)
	local ny = math.floor((y - boxSize * 2) / boxSize)
	-- check if we are actually over a box first
	if boxes[nx][ny] then
		-- left, red
		if input(button, controls.red) then
			boxes[nx][ny][1] = boxes[nx][ny][1] + colorStep
			if boxes[nx][ny][1] > 255 then
				boxes[nx][ny][1] = 0
			end
		-- middle, green
		elseif input(button, controls.green) then
			boxes[nx][ny][2] = boxes[nx][ny][2] + colorStep
			if boxes[nx][ny][2] > 255 then
				boxes[nx][ny][2] = 0
			end
		-- right, blue
		elseif input(button, controls.blue) then
			boxes[nx][ny][3] = boxes[nx][ny][3] + colorStep
			if boxes[nx][ny][3] > 255 then
				boxes[nx][ny][3] = 0
			end
		end
	end
end

function game:keypressed(key, unicode)
	if input(key, controls.back) then
		log("Leaving game...")
		Gamestate.switch(previousState)
	elseif input(key, controls.pause) then
		Gamestate.push(paused, love.graphics.newScreenshot(), controls, session)
	end
end

function game:focus(isFocused)
	if not isFocused then
		Gamestate.push(paused, love.graphics.newScreenshot(), controls, session)
	end
end

function game:leave()
	-- clear the game upon any exit (except pause)
	level = 0
	score = 0
	totalScore = 0
	time = 0
	startingTime = 0
end

return game
