extends Control

const TimeHand = preload("res://scenes/common/time/time_hand.tscn")

const WorkingDayStart = 8
const WorkingDayEnd = 21

const DigitsNumber = 12

enum State {
	SettingHours,
	SettingMinutes
}

@export var number_flash_time := 0.5

@onready var _main: Main = get_tree().get_current_scene()
@onready var _hours_label = $VerticalBar/Control/Time/Hours
@onready var _minutes_label = $VerticalBar/Control/Time/Minutes
@onready var _time = $VerticalBar/Control/Time
@onready var _face = $VerticalBar/Circle/Face
@onready var _arrow = $VerticalBar/Circle/Clock/Arrow
@onready var _numbers = $VerticalBar/Circle/Clock/Numbers

var _hours : int
var _minutes : int

var _state := State.SettingHours
var _time_after_last_flash := 0.0

var _blocked := false

signal time_is_set(hours: int, minutes: int)

func _ready():
	_set_initial_values()
	_start_hours_setting()

func _set_initial_values():
	_hours = WorkingDayStart
	_minutes = 0

func _process(delta):
	if _time_after_last_flash >= number_flash_time:
		_flash_number()
		_time_after_last_flash = 0.0

	_time_after_last_flash += delta

func _flash_number():
	match _state:
		State.SettingHours:
			_hours_label.text = str(_hours) \
				if _hours_label.text == '_' else '_'
		State.SettingMinutes:
			_minutes_label.text = _correct_minutes(str(_minutes)) \
				if _minutes_label.text == '_' else '_'

func _fill_with_hours():
	_remove_numbers()
	for part in range(0, DigitsNumber):
		var number = TimeHand.instantiate()
		_numbers.add_child(number)
		number.set_part(part)
		number.set_value(WorkingDayStart + part)

func _fill_with_minutes():
	_remove_numbers()
	for part in range(0, DigitsNumber):
		var number = TimeHand.instantiate()
		_numbers.add_child(number)
		number.set_part(part)
		number.set_value(5*part)

func _remove_numbers():
	for number in _numbers.get_children():
		number.queue_free()

func _clicked_on_face(pos: Vector2):
	var face_position = _face.global_position
	return (pos.x > face_position.x and pos.x < _face.size.x + face_position.x) and \
		(pos.y > face_position.y and pos.y < _face.size.y + face_position.y)

func _clicked_on_time(pos: Vector2):
	var time_position = _time.global_position
	return (pos.x > time_position.x and pos.x < _time.size.x + time_position.x) and \
		(pos.y > time_position.y and pos.y < _time.size.y + time_position.y)

func _input(event):
	if _blocked or not _main.get_current_page() == Main.Pages.TimeSetting:
		return

	if (event is InputEventScreenTouch and event.pressed) or \
	(event is InputEventMouseButton and event.pressed): # TODO: call on click or release, do not do anything if it was clicked
		if _clicked_on_face(event.position):
			var number = _get_closest_number(event.position)
			_arrow.rotation = number.rotation

			match _state:
				State.SettingHours:
					set_hours(number.get_value())
					await get_tree().create_timer(0.01, false).timeout
					_start_minutes_setting()
				State.SettingMinutes:
					set_minutes(number.get_value())
					time_is_set.emit(_hours, _minutes)
					await get_tree().create_timer(0.01, false).timeout
					_main.go_to_previous_page(false)
					_ready()

		elif _clicked_on_time(event.position):
			match _get_closest_unit(event.position):
				_hours_label:
					_start_hours_setting()
				_minutes_label:
					_start_minutes_setting()

		await event.is_released() == true

func _get_closest_number(pos: Vector2):
	var min_distance = INF
	var sought = null

	for number in _numbers.get_children():
		var distance = number.get_number_position().distance_to(pos)
		if (distance < min_distance):
			min_distance = distance
			sought = number

	return sought

func _get_closest_unit(pos: Vector2):
	var min_distance = INF
	var sought = null

	for unit in _time.get_children():
		var distance = unit.global_position.distance_to(pos)
		if (distance < min_distance):
			min_distance = distance
			sought = unit

	return sought

func set_hours(value):
	_hours = value
	_update_time()

func get_hours():
	return _hours

func set_minutes(value):
	_minutes = value
	_update_time()

func get_minutes():
	return _minutes

func _update_time():
	_arrow.rotation = 0.0
	_hours_label.text = str(_hours)
	_minutes_label.text = _correct_minutes(str(_minutes))

func _correct_minutes(value):
	return "0" + value if len(value) == 1 else value

func _start_hours_setting():
	_state = State.SettingHours
	_fill_with_hours()
	_update_time()

func _start_minutes_setting():
	_state = State.SettingMinutes
	_fill_with_minutes()
	_update_time()

func _block_click_for(seconds: float):
	_blocked = true
	await get_tree().create_timer(seconds, false).timeout
	_blocked = false

func update():
	_ready()
	_block_click_for(0.25)
