@tool
extends Main
class_name MainTablet

const BgColors = {
	"standart": Color("22262d"),
	"busy": Color("4e0003"),
	"free": Color("003c18"),
	"temporarily_free": Color("3a2c00")
}
const MinutesForTemporarilyFree := 15
const StatusCheckInterval := 1.0 # 5.0

enum Status {
	FREE,
	BUSY
}

@onready var _reservation_repo : AbstractReservationRepo = $Repos/Reservation
@onready var _room_repo : AbstractRoomRepo = $Repos/Room
@onready var _event_handler : EventHandler = $Repos/EventHandler
@onready var _reservation_service : ReservationService = $Services/ReservationService
@onready var _keyboard = $Keyboard/OnscreenKeyboard

@export var current_page : Pages:
	set(value):
		current_page = value
		load_page(value, false)

@onready var _pages := {
	Pages.Board: $Left/Pages/Board,
	Pages.ReservationCreation: $Left/Pages/ReservationCreation,
	Pages.ReservationEdit: $Left/Pages/ReservationEdit,
	Pages.TimeSetting: $Left/Pages/TimeSetting,
	Pages.CalendarSetting: $Left/Pages/CalendarSetting,
	Pages.RoomSelection: $Left/Pages/RoomSelection
}
@onready var _time_status_indent := $Left/TimeStatusContainer/Indent
@onready var _time_label := $Left/TimeStatusContainer/TimeLabel
@onready var _status_label := $Left/TimeStatusContainer/StatusLabel
@onready var _will_be_available_label := $Left/TimeStatusContainer/WillBeAvailableLabel
@onready var _background := $Background

@onready var _create_reservation_button := $RightBottom/CreateReservationButton
@onready var _reserve_now_label := $Left/TimeStatusContainer/ReserveNowBox/ReserveNowLabel
@onready var _15_min_button := $Left/TimeStatusContainer/ReserveNowBox/InstantButtons/_15min
@onready var _30_min_button := $Left/TimeStatusContainer/ReserveNowBox/InstantButtons/_30min
@onready var _45_min_button := $Left/TimeStatusContainer/ReserveNowBox/InstantButtons/_45min
@onready var _1_hour_button := $Left/TimeStatusContainer/ReserveNowBox/InstantButtons/_1h

var _current_page := Pages.Board
var _previous_page : Pages

var _status : Status
var _status_check_timer := 0.0

var _selected_date := get_current_date()

func _ready():
	initialize_signals()

func initialize_signals():
	_event_handler.reservations_updated.connect(_on_reservations_updated)
	_create_reservation_button.pressed.connect(_on_create_reservation_button_pressed)
	_15_min_button.pressed.connect(_on_15_min_button_pressed)
	_30_min_button.pressed.connect(_on_30_min_button_pressed)
	_45_min_button.pressed.connect(_on_45_min_button_pressed)
	_1_hour_button.pressed.connect(_on_1_hour_button_pressed)

func _process(delta):
	_process_time_status_indent()
	_process_status(delta)

	var time = Time.get_time_dict_from_system()
	_process_time(time)
	_process_available_time(time)

	_process_fonts()

func _process_time_status_indent():
	var indent = get_viewport_rect().size.y/3
	if _get_time_status_indent() != indent:
		_set_time_status_indent(indent)

func _process_time(time):
	_time_label.text = "%02d:%02d" % [time.hour, time.minute]

func _process_available_time(time):
	var reservation = _reservation_repo.get_current_reservation()

	if _status == Status.BUSY and reservation:
		var current_time_in_minutes = time.hour*60 + time.minute
		var reservation_minutes = reservation.finish_time.hours*60 + reservation.finish_time.minutes
		var result_minutes = reservation_minutes - current_time_in_minutes
		_will_be_available_label.text = "(осталось %s мин)" % str(result_minutes)
	else:
		_will_be_available_label.text = ""

func _process_status(delta):
	if _status_check_timer >= StatusCheckInterval:
		_status_check_timer = 0.0
		_update_status()

	_status_check_timer += delta

func _update_status(reservations=null):
	var time = Time.get_time_dict_from_system()
	var current_time_in_minutes = time.hour*60 + time.minute

	if reservations == null:
		var room = get_selected_room()
		reservations = await _reservation_repo.list_reservations({
			"date": get_current_date(),
			"room_id": room.id if room else ''
		})

	for reservation in reservations:
		var start_time_in_minutes = reservation.start_time.hours*60 + reservation.start_time.minutes
		var finish_time_in_minutes = reservation.finish_time.hours*60 + reservation.finish_time.minutes

		if current_time_in_minutes >= start_time_in_minutes \
		and current_time_in_minutes < finish_time_in_minutes:
			_update_ui_status(Status.BUSY, "Занято", BgColors.busy)
			return

		elif current_time_in_minutes <= start_time_in_minutes \
		and current_time_in_minutes + MinutesForTemporarilyFree > start_time_in_minutes:
			_update_ui_status(Status.FREE, "Свободно", BgColors.temporarily_free)
			return

	if len(reservations) > 0:
		_update_ui_status(Status.FREE, "Свободно", BgColors.free)
	else:
		_update_ui_status(Status.FREE, "Свободно", BgColors.standart)

func _update_ui_status(status: Status, text: String, color: Color):
	_status = status
	_status_label.text = text
	_background.color = color

func _process_fonts():
	_process_font_size(_create_reservation_button, 35)

func _process_font_size(obj, k):
	var font_size = obj.get_theme_default_font_size()
	var new_font_size = get_viewport_rect().size.y/k
	if font_size != new_font_size:
		obj.add_theme_font_size_override("font_size", new_font_size)

func get_current_page():
	return _current_page

func get_previous_page():
	return _previous_page

func load_page(value, with_update=true):
	var previous_page = _current_page

	if _previous_page != _current_page:
		if not _current_page == Pages.TimeSetting:
			_previous_page = _current_page

	_current_page = value
	if with_update:
		_pages[_current_page].update()

	hide_keyboard()
	_change_page_with_delay(previous_page)
	_change_create_reservation_button_visibility(_current_page)
	_update_reserve_now_label_text()

	return _pages[_current_page]

func _change_page_with_delay(previous_page):
	await get_tree().create_timer(0.1, false).timeout
	_pages[previous_page].visible = false
	_pages[_current_page].visible = true

func _change_create_reservation_button_visibility(page: Pages):
	if page == Pages.Board:
		_create_reservation_button.show()
	else:
		_create_reservation_button.hide()

func go_to_previous_page(with_update=true):
	if _previous_page != null:
		load_page(_previous_page, with_update)

func get_reservation_repo() -> AbstractReservationRepo:
	return _reservation_repo

func get_room_repo() -> AbstractRoomRepo:
	return _room_repo

func get_event_handler() -> EventHandler:
	return _event_handler

func get_reservation_service() -> ReservationService:
	return _reservation_service

func _set_time_status_indent(value):
	_time_status_indent.custom_minimum_size.y = value

func _get_time_status_indent():
	return _time_status_indent.custom_minimum_size.y

func _create_default_reservation(minutes_of_reservation: int):
	if _current_page == Pages.ReservationCreation:
		var start_time = _pages[_current_page].get_start_time()
		_extend_finish_time_for(start_time, minutes_of_reservation)
		return
	elif _current_page == Pages.ReservationEdit:
		var finish_time = _pages[_current_page].get_finish_time()
		_extend_finish_time_for(finish_time, minutes_of_reservation)
		return

	if _status == Status.BUSY:
		return

	var datetime = Time.get_datetime_dict_from_system()
	var start_time_in_minutes = datetime.hour * 60 + datetime.minute
	var finish_time_in_minutes = start_time_in_minutes + minutes_of_reservation
	var finish_time_hours = floor(finish_time_in_minutes/60)
	var finish_time_minutes = finish_time_in_minutes - finish_time_hours * 60

	if await get_reservation_service().is_time_busy(start_time_in_minutes, finish_time_in_minutes):
		return

	var dto = CreateReservationDTO.new()
	dto.title = ""
	dto.date = "%02d.%02d.%04d" % [datetime.day, datetime.month, datetime.year]
	dto.start_time = {"hours": datetime.hour, "minutes": datetime.minute}
	dto.finish_time = {"hours": finish_time_hours, "minutes": finish_time_minutes}
	dto.creator = ""
	dto.room_id = _room_repo.get_selected_room().id
	dto.description = ""
	dto.color = randi_range(1, 3)

	var repo = get_reservation_repo()
	repo.create_reservation(dto)

	dto.queue_free()

	load_page(Main.Pages.Board, true)

func _extend_finish_time_for(time: Dictionary, minutes_of_reservation: int):
	var time_in_minutes = time.hours * 60 + time.minutes
	var new_time_in_minutes = time_in_minutes + minutes_of_reservation
	var new_time_hours = floor(new_time_in_minutes/60)
	var new_time_minutes = new_time_in_minutes - new_time_hours * 60
	var new_time = {"hours": new_time_hours, "minutes": new_time_minutes}
	_pages[_current_page].set_finish_time(new_time)

func get_selected_date() -> String:
	return _selected_date

func get_current_date() -> String:
	var date = Time.get_date_dict_from_system()
	return "%02d.%02d.%04d" % [date.day, date.month, date.year]

func is_current_date_selected() -> bool:
	return get_selected_date() == get_current_date()

func date_is_before_current_date(date: String) -> bool:
	var current_date = get_current_date()
	return Utils._date_to_number(date) < Utils._date_to_number(current_date)

func get_selected_room() -> RoomEntity:
	var room_repo = get_room_repo()
	return room_repo.get_selected_room()

func hide_keyboard():
	_keyboard.hide()

func start_date_selection():
	_pages[Pages.CalendarSetting].date_selected.connect(_on_date_selected)

func _on_reservations_updated(reservations):
	_update_status()

func _on_create_reservation_button_pressed():
	load_page(Pages.ReservationCreation)

func _on_15_min_button_pressed():
	_create_default_reservation(15)

func _on_30_min_button_pressed():
	_create_default_reservation(30)

func _on_45_min_button_pressed():
	_create_default_reservation(45)

func _on_1_hour_button_pressed():
	_create_default_reservation(60)

func _on_date_selected(date: Calendar.DateObj):
	_selected_date = "%02d.%02d.%04d" % [date.day, date.month, date.year]
	_pages[Pages.CalendarSetting].date_selected.disconnect(_on_date_selected)
	_pages[Pages.Board].update_date()

func _update_reserve_now_label_text():
	if _current_page == Pages.ReservationCreation:
		_reserve_now_label.text = "Забронировать на"
	elif _current_page == Pages.ReservationEdit:
		_reserve_now_label.text = "Продлить на"
	else:
		_reserve_now_label.text = "Забронировать сейчас на"