extends VBoxContainer

enum Types {
	Creation,
	Edit,
	Info
}

@export var type : Types:
	set(new_type):
		type = new_type

@onready var _main: Main = get_tree().get_current_scene()
@onready var _title := $TopBar/Label
@onready var _back_button := $BottomBar/Left/BackButton
@onready var _apply_button := $BottomBar/Right/ApplyButton
@onready var _delete_button := $BottomBar/Left/DeleteButton
@onready var _error_box := $ErrorBox

@onready var _title_field := $TitleField
@onready var _date_field := $DateField
@onready var _start_time_field := $StartTimeField
@onready var _finish_time_field := $FinishTimeField
@onready var _creator_field := $CreatorField
@onready var _room_field := $RoomField
@onready var _description_field := $DescriptionField

var _reservation : ReservationEntity = null

func _process(delta):
	_process_fonts()
	_process_separation()

func _process_fonts():
	_process_font_size(_title, 35)
	_process_font_size(_back_button, 35)
	_process_font_size(_apply_button, 35)
	_process_font_size(_delete_button, 35)
	_process_font_size(_error_box, 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 _process_separation():
	var separation = get_theme_constant("separation")
	var new_separation = get_viewport_rect().size.y*(1.0/19.0) - 715.0/19.0
	if separation != new_separation:
		add_theme_constant_override("separation", new_separation)

func _ready():
	initialize_signals()
	_error_box.set_message(String())

func initialize_signals():
	_back_button.pressed.connect(_on_back_button_pressed)
	_apply_button.pressed.connect(_on_apply_button_pressed)

	if type == Types.Edit:
		_delete_button.pressed.connect(_on_delete_button_pressed)

func _on_back_button_pressed():
	_main.load_page(Main.Pages.Board)

func _on_apply_button_pressed():
	match type:
		Types.Creation:
			_create_reservation()
		Types.Edit:
			_update_reservation()

func _on_delete_button_pressed():
	_delete_reservation()

func _load_info():
	var reservation_repo = _main.get_reservation_repo()
	var reservation_id = reservation_repo.get_selected_reservation_id()
	_reservation = await reservation_repo.get_reservation(reservation_id)

	var room_repo = _main.get_room_repo()
	var room = await room_repo.get_room(_reservation.room_id)
	var room_title = room.title if room != null else ""

	_title_field.set_value(_reservation.title)
	_start_time_field.set_value(_reservation.start_time)
	_finish_time_field.set_value(_reservation.finish_time)
	_date_field.set_value(_reservation.date)
	_room_field.set_value({"title": room_title, "id": _reservation.room_id})

func _load_room():
	if _room_field.get_value().title == "":
		var room = _main.get_selected_room()
		_room_field.set_value({"title": room.title, "id": room.id})

func _load_date():
	if _date_field.get_value() == "":
		_date_field.set_value(_main.get_selected_date())

func _create_reservation():
	if not await _fields_are_correct():
		return

	var dto = CreateReservationDTO.new()
	dto.title = _title_field.get_value()
	dto.date = _date_field.get_value()
	dto.start_time = _start_time_field.get_value()
	dto.finish_time = _finish_time_field.get_value()
	dto.creator = _creator_field.get_value()
	dto.room_id = _room_field.get_value().id
	dto.description = _description_field.get_value()
	dto.color = randi_range(1, 3)

	var reservation_repo = _main.get_reservation_repo()
	reservation_repo.create_reservation(dto)

	dto.queue_free()

	_main.load_page(Main.Pages.Board, true)
	clean()

func _update_reservation():
	if not await _fields_are_correct():
		return

	var dto = UpdateReservationDTO.new()
	dto.title = _title_field.get_value()
	dto.date = _date_field.get_value()
	dto.start_time = _start_time_field.get_value()
	dto.finish_time = _finish_time_field.get_value()
	dto.creator = _creator_field.get_value()
	dto.room_id = _room_field.get_value().id
	dto.description = _description_field.get_value()
	dto.color = randi_range(1, 3)

	var reservation_repo = _main.get_reservation_repo()
	var reservation_id = reservation_repo.get_selected_reservation_id()
	reservation_repo.change_reservation(reservation_id, dto)
	reservation_repo.set_selected_reservation_id(null)

	dto.queue_free()

	_main.load_page(Main.Pages.Board, true)
	clean()

func _delete_reservation():
	var repo = _main.get_reservation_repo()
	var reservation_id = repo.get_selected_reservation_id()
	repo.cancel_reservation(reservation_id)

	_main.load_page(Main.Pages.Board, true)
	clean()

func _fields_are_correct():
	var successful := true

	#if not _title_is_correct():
	#	successful = false

	if not await _time_is_correct():
		successful = false

	return successful

func _title_is_correct():
	if len(_title_field.get_value()) < 1:
		print("The title is not entered.")
		_error_box.set_message("Не введено название встречи")
		return false

	return true

func _time_is_correct():
	var start_time = _start_time_field.get_value()
	var finish_time = _finish_time_field.get_value()

	if _time_is_not_entered(start_time, finish_time):
		return false

	if _time_or_date_is_before_now(start_time):
		return false

	if _start_time_is_after_finish_time(start_time, finish_time):
		return false

	if await _selected_time_is_busy(start_time, finish_time):
		return false

	return true

func _time_is_not_entered(start_time: Dictionary, finish_time: Dictionary):
	var time_is_not_entered = \
		start_time["hours"] == 0 and start_time["minutes"] == 0 or \
		finish_time["hours"] == 0 and finish_time["minutes"] == 0

	if time_is_not_entered:
		_error_box.set_message("Введите время начала и окончания встречи")
		return true
	
	return false

func _time_or_date_is_before_now(start_time: Dictionary):
	var time_is_before_now = _time_is_before_current_time(start_time)
	var date_is_before_now = _date_is_before_current_date(_date_field.get_value())

	if time_is_before_now or date_is_before_now:
		_error_box.set_message("Нельзя зарезервировать на прошедшее время")
		return true

	return false

func _time_is_before_current_time(time) -> bool:
	if _main.get_current_page() == Main.Pages.ReservationEdit and _reservation:
		var selected_start_time = get_start_time()
		if selected_start_time.hours == _reservation.start_time.hours and \
		selected_start_time.minutes == _reservation.start_time.minutes:
			return false

	var current_time = Time.get_time_dict_from_system()
	var time_in_minutes = time.hours*60 + time.minutes
	var current_time_in_minutes = current_time.hour*60 + current_time.minute

	return time_in_minutes < current_time_in_minutes

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

func _date_to_number(date_str: String) -> int:
	var parts = date_str.split(".")
	assert(parts.size() == 3, "Некорректная дата: " + date_str)
	
	return int(parts[2] + parts[1].lpad(2, "0") + parts[0].lpad(2, "0"))

func _start_time_is_after_finish_time(start_time: Dictionary, finish_time: Dictionary):
	var start_time_is_after_finish_time = \
		start_time["hours"] > finish_time["hours"] or \
		(start_time["hours"] == finish_time["hours"] and \
		start_time["minutes"] >= finish_time["minutes"])

	if start_time_is_after_finish_time:
		print("Start time should not be more than or equal to finish time.")
		_error_box.set_message("Время начала не может быть больше времени окончания")
		return true

	return false

func _selected_time_is_busy(start_time: Dictionary, finish_time: Dictionary):
	var start_time_in_minutes = start_time.hours*60 + start_time.minutes
	var finish_time_in_minutes = finish_time.hours*60 + finish_time.minutes
	var service = _main.get_reservation_service()
	var selected_room_id = _room_field.get_value().id
	var selected_date = _date_field.get_value()
	var is_busy = await service.is_time_busy(start_time_in_minutes, finish_time_in_minutes, \
		selected_room_id, selected_date)

	if is_busy:
		print("The selected time slot is busy.")
		_error_box.set_message("Выбранный временной интервал занят")
		return true

	return false

func get_start_time() -> Dictionary:
	return _start_time_field.get_value()

func get_finish_time() -> Dictionary:
	return _finish_time_field.get_value()

func set_start_time(value) -> void:
	_start_time_field.set_value(value)

func set_finish_time(value) -> void:
	_finish_time_field.set_value(value)

func update():
	_ready()

	if type == Types.Edit and _main.get_previous_page() == Main.Pages.Board:
		_load_info()
	else:
		_load_room()
		_load_date()

func clean():
	_title_field.clean()
	_start_time_field.clean()
	_finish_time_field.clean()
	_date_field.clean()
	_room_field.clean()