extends Node2D

@onready var spawnpoint = $Spawnpoint
@onready var blocks = $Blocks
@onready var tickerTimer = $Ticker
@onready var patterns = $Patterns
@onready var turnTickTimer = $TurnTick
@onready var loseArea = $LoseArea
@onready var gameTimer = $GameTimer


var nextBlocks =  []

var currentPattern = null

var patternsArray = []

var blockSpeed = 0.5

var stopped = false


func spawnBlock() -> void:
	var block = nextBlocks[0]
	GLOBAL.currentBlock = block
	spawnpoint.add_child(block)
	nextBlocks.pop_at(0)
	if nextBlocks.size() < 2:
		fillNextBlocks()

func _ready() -> void:
	tickerTimer.start(blockSpeed)
	getNewPatterns()
	PlacePattern()

func _physics_process(delta: float) -> void:	
	var blockGroups = getBlockGroupsList()
	#if Input.is_action_pressed("down"):
		
	if Input.is_action_pressed("down") and not stopped and not Input.is_action_just_released("down"):
		if not tickerTimer.is_stopped():
			blockSpeed = GLOBAL.maxSpeed
	else:
		if not tickerTimer.is_stopped():
			blockSpeed = GLOBAL.minSpeed
	if Input.is_action_just_pressed("rotate_right") and not stopped:
		if blockGroups.has(GLOBAL.currentUID):
			for i in blockGroups[GLOBAL.currentUID]:
				if i.turningPoint:
					if currentPattern != null:
						if not stopped:
							currentPattern.turn(GLOBAL.Direction.RIGHT,i.position-spawnpoint.position + Vector2(GLOBAL.GRID/2, GLOBAL.GRID/2))
						#turnBlocks()
						if turnTickTimer.is_stopped():
							turnTickTimer.start(9*delta)

	if Input.is_action_just_pressed("rotate_left") and not stopped:
		if blockGroups.has(GLOBAL.currentUID):
			for i in blockGroups[GLOBAL.currentUID]:
				if i.turningPoint:
					if currentPattern != null:
						if not stopped:
							currentPattern.turn(GLOBAL.Direction.LEFT,i.position-spawnpoint.position + Vector2(GLOBAL.GRID/2, GLOBAL.GRID/2))
						#turnBlocks()
						if turnTickTimer.is_stopped():
							turnTickTimer.start(9*delta)

	if Input.is_action_just_pressed("left"):
		moveUidGroup(GLOBAL.Direction.LEFT, GLOBAL.currentUID)
	if Input.is_action_just_pressed("right"):
		moveUidGroup(GLOBAL.Direction.RIGHT, GLOBAL.currentUID)


func fillNextBlocks():
	var newBlocks = []
	for i in GLOBAL.BLOCKS:
		var block = load(GLOBAL.BLOCKS[i]).instantiate()
		block.setId(GLOBAL.getNewId())
		block.setType(GLOBAL.BLOCKTYPES.LIGHT)
		newBlocks.append(block)
	newBlocks.shuffle()
	newBlocks[0].setType(GLOBAL.BLOCKTYPES.HEAVY)
	newBlocks.shuffle()
	nextBlocks.append_array(newBlocks)

## returns a Dictionary with the UIDs as the Key and a List of the Blocks as the content
func getBlockGroupsList():
	var blockLists : Dictionary = {}
	for i in blocks.get_children():
		if not blockLists.has(i.UID):
			blockLists[i.UID] = []
		blockLists[i.UID].append(i)
	return blockLists


func getBlockedDirection(direction : GLOBAL.Direction, uid : int) -> bool:
	#var blockslist = getBlockGroupsList()
	var isBlocked = false
	if getBlockGroupsList().has(uid):
		for i in getBlockGroupsList()[uid]:
			if i.getCollider(direction) != null:
				if i.getCollider(direction).is_in_group("Block"):
					if i.getCollider(direction).UID != i.UID:
						isBlocked = true
				else:
						isBlocked = true
		return isBlocked
	return true

func splitOphansUID(uid):
	var compareList = {}
	var group = []
	for i in getBlockGroupsList()[uid]:
		compareList[i] = i.getNeighboursUID(uid)
		if i.getNeighboursUID(uid) == []:
			i.UID = GLOBAL.getNewUID()

	for i in compareList:
		group.insert(0, compareList[i])
		group[0].append(i)
		for j in group[0]:
			if compareList[i].has(j) and not group[0].has(j):
				group[0].append(j)
	
	for i in group:
		var newUID = GLOBAL.getNewUID()
		for j in i:
			j.UID = newUID

func moveUidGroup(direction, uid):
	if getBlockGroupsList().has(uid):
		match direction:
			GLOBAL.Direction.BOTTOM:
				for i in getBlockGroupsList()[uid]:
					if not getBlockedDirection(GLOBAL.Direction.BOTTOM, i.UID):
						i.moveDown()
			GLOBAL.Direction.LEFT:
				for i in getBlockGroupsList()[uid]:
					if not getBlockedDirection(GLOBAL.Direction.LEFT, i.UID):
						i.moveLeft()
			GLOBAL.Direction.RIGHT:
					for i in getBlockGroupsList()[uid]:
						if not getBlockedDirection(GLOBAL.Direction.RIGHT, i.UID):
							i.moveRight()

func PlacePattern():
	patternsArray.pop_at(0)
	for child in patterns.get_children():
		child.queue_free()
	if patternsArray.size() <= 2:
		getNewPatterns()
	currentPattern = patternsArray[0]
	patterns.add_child(currentPattern)
	var newUID = GLOBAL.getNewUID()
	GLOBAL.currentUID = newUID
	var newColor = Color.from_hsv((randi() % 12) / 12.0, 1, 1)
	for i in patterns.get_children():
		i.reset(Vector2())
	if currentPattern != null:
		for i in currentPattern.getPositions():
			var block = load("res://scenes/Blocks/block.tscn").instantiate()
			block.UID = newUID
			block.modulate = newColor
			block.position = spawnpoint.position + i.position
			block.type = currentPattern.type
			block.expand = currentPattern.expand
			if i.turningPoint:
				block.turningPoint = true
			blocks.add_child(block)
			block.setlook()
		

func getNewPatterns():
	var newPatterns = []
	for i in GLOBAL.BLOCKSPATTERS:
		newPatterns.append(load(GLOBAL.BLOCKSPATTERS[i]).instantiate())
	newPatterns.shuffle()
	newPatterns[0].type = GLOBAL.BLOCKTYPES.HEAVY
	newPatterns.shuffle()
	newPatterns[0].expand = true
	#for i in newPatterns:
		#i.expand = true
	newPatterns.shuffle()
	patternsArray.append_array(newPatterns)

func turnBlocks():
	var turningPointBlock
	for g in currentPattern.getPositions().size():
		if not getBlockGroupsList()[GLOBAL.currentUID][g].turningPoint:
			getBlockGroupsList()[GLOBAL.currentUID][g].global_position = currentPattern.getPositions()[g].global_position- Vector2(32,32) 
		else:
			turningPointBlock = getBlockGroupsList()[GLOBAL.currentUID][g]
	for g in currentPattern.getPositions():
		if g.turningPoint:
			turningPointBlock.global_position = g.global_position- Vector2(32,32)  

func _on_turn_tick_timeout() -> void:
	turnBlocks()

func _on_ticker_timeout() -> void:
	
	if getBlockedDirection(GLOBAL.Direction.BOTTOM, GLOBAL.currentUID):

		stopped = true
		test()


	for i in getBlockGroupsList():
		moveUidGroup(GLOBAL.Direction.BOTTOM, i)
	
	if not stopped:
		tickerTimer.start(blockSpeed)
		stopped = false
	elif stopped:
		if loseArea.get_overlapping_areas() != []:
			GLOBAL.lose()
		tickerTimer.start(GLOBAL.minSpeed)
		stopped = false



func _on_game_timer_timeout() -> void:
	if GLOBAL.time - 1 > 0:
		GLOBAL.time -= 1
	else:
		GLOBAL.lose()
	gameTimer.start(1)


func test():
	for i in $RowTests.get_children():
		for j in getBlockGroupsList():
			if j != GLOBAL.currentUID:
				moveUidGroup(GLOBAL.Direction.BOTTOM, i)
	stopped = true
	var previousPosition = currentPattern.position
	if currentPattern.expand:
		if currentPattern.get_scale() != Vector2(2,2):

			#currentPattern.position.y -= 64
			for i in getBlockGroupsList()[GLOBAL.currentUID]:
				if i.turningPoint:
					currentPattern.set_scale(Vector2(2,2))
					currentPattern.moveToPosition(i.global_position-spawnpoint.position)

				
				for j in await currentPattern.getCollidingBorder():
					if j.is_in_group("Floor"):
						currentPattern.position.y -= GLOBAL.GRID
						if await currentPattern.getCollidingBorder() == []:
								break
					if j.is_in_group("LeftBorder"):
						for s in range(1,7):
							currentPattern.position.x += GLOBAL.GRID
							if await currentPattern.getCollidingBorder() == []:
								break
					elif j.is_in_group("RightBorder"):
						for s in range(1,7):
							currentPattern.position.x -= GLOBAL.GRID
							if await currentPattern.getCollidingBorder() == []:
								break

			if await currentPattern.getCollidingBorder() == []:
				for i in getBlockGroupsList()[GLOBAL.currentUID].size():
					getBlockGroupsList()[GLOBAL.currentUID][i].global_position = currentPattern.getPositions()[i].global_position - Vector2(GLOBAL.GRID, GLOBAL.GRID)
					getBlockGroupsList()[GLOBAL.currentUID][i].set_scale(Vector2(2,2))
		for i in await currentPattern.getCollidingBlocks():
			i.queue_free()

	testRows()
	PlacePattern()

func testRows():
	for i in $RowTests.get_children():
		if i.isCompleted():
			for j in i.getRow():
				splitOphansUID(j.UID)
				if j.expand:
					GLOBAL.points += j.type * 2
					GLOBAL.time += j.type
				elif not j.expand:
					GLOBAL.points += j.type 
					GLOBAL.time += j.type
				j.queue_free()
		for j in getBlockGroupsList():
			if j != GLOBAL.currentUID:	
				moveUidGroup(GLOBAL.Direction.BOTTOM, j)

func toggleButton():
	$Camera2D/CanvasLayer/Control.toggleButton()
