class_name UtilityPageStyle
extends RefCounted

const TuffyFont: Font = preload("res://ui/fonts/Tuffy_Bold.otf")
const PAPER: Color = Color("eee2bd")
const PAPER_ALT: Color = Color("f3ecd7")
const INK: Color = Color("28251f")
const MUTED_INK: Color = Color("5f5547")
const BORDER: Color = Color("473d2e")
# PAPER/INK remain available only for intentionally paper-like content such as
# a letter body. Technical surfaces use this shared ocean palette.
const OCEAN_PANEL_DEEP: Color = Color("0d2c3a")
const OCEAN_PANEL_MID: Color = Color("123f4e")
const OCEAN_FIELD: Color = Color("081f2b")
const OCEAN_BUTTON: Color = Color("123f4e")
const OCEAN_BUTTON_HOVER: Color = Color("196072")
const OCEAN_BUTTON_PRESSED: Color = Color("0b3341")
const OCEAN_SELECTED: Color = Color("238697")
const OCEAN_TEXT_PRIMARY: Color = Color("e6f7f7")
const OCEAN_TEXT_SECONDARY: Color = Color("9fcfd2")
const OCEAN_DISABLED: Color = Color("38535b")
const OCEAN_DANGER: Color = Color("9e4550")
const NAVY: Color = Color("092b3d")
const NAVY_HOVER: Color = Color("12465b")
const GREEN: Color = Color("31594d")
const LIGHT_TEXT: Color = Color("f5eed9")
const DISABLED_TEXT: Color = Color(0.33, 0.36, 0.35, 0.72)
const MOTION_TWEEN_META: StringName = &"utility_page_motion_tween"
const LAPTOP_RECT: Rect2 = Rect2(66.0, 132.0, 1148.0, 520.0)


static func apply_page(root: Control) -> void:
	root.add_theme_font_override("font", TuffyFont)


static func rounded_style(color: Color, radius: int) -> StyleBoxFlat:
	var style := StyleBoxFlat.new()
	style.bg_color = color
	style.set_border_width_all(0)
	style.set_corner_radius_all(radius)
	return style


static func build_laptop_screen(
	root: Control,
	laptop_rect: Rect2 = LAPTOP_RECT,
) -> MarginContainer:
	var laptop := PanelContainer.new()
	laptop.position = laptop_rect.position
	laptop.size = laptop_rect.size
	laptop.add_theme_stylebox_override(
		"panel", rounded_style(OCEAN_PANEL_MID, 24)
	)
	root.add_child(laptop)

	var shell_margin := MarginContainer.new()
	shell_margin.add_theme_constant_override("margin_left", 20)
	shell_margin.add_theme_constant_override("margin_top", 18)
	shell_margin.add_theme_constant_override("margin_right", 20)
	shell_margin.add_theme_constant_override("margin_bottom", 24)
	laptop.add_child(shell_margin)

	var screen := PanelContainer.new()
	screen.add_theme_stylebox_override(
		"panel", rounded_style(OCEAN_FIELD, 16)
	)
	shell_margin.add_child(screen)

	var content_margin := MarginContainer.new()
	content_margin.add_theme_constant_override("margin_left", 24)
	content_margin.add_theme_constant_override("margin_top", 18)
	content_margin.add_theme_constant_override("margin_right", 24)
	content_margin.add_theme_constant_override("margin_bottom", 18)
	screen.add_child(content_margin)

	var base := ColorRect.new()
	base.position = Vector2(
		laptop_rect.position.x + 82.0,
		laptop_rect.end.y - 6.0,
	)
	base.size = Vector2(laptop_rect.size.x - 164.0, 14.0)
	base.color = OCEAN_PANEL_MID
	base.mouse_filter = Control.MOUSE_FILTER_IGNORE
	root.add_child(base)
	return content_margin


static func panel_style() -> StyleBoxFlat:
	var style := StyleBoxFlat.new()
	style.bg_color = OCEAN_PANEL_DEEP
	style.set_border_width_all(0)
	style.set_corner_radius_all(16)
	style.content_margin_left = 26
	style.content_margin_right = 26
	style.content_margin_top = 20
	style.content_margin_bottom = 20
	return style


static func row_style(selected: bool = false) -> StyleBoxFlat:
	var style := StyleBoxFlat.new()
	style.bg_color = OCEAN_SELECTED if selected else OCEAN_PANEL_MID
	style.set_border_width_all(0)
	style.set_corner_radius_all(8)
	style.content_margin_left = 12
	style.content_margin_right = 12
	style.content_margin_top = 8
	style.content_margin_bottom = 8
	return style


static func button_style(color: Color) -> StyleBoxFlat:
	var style := StyleBoxFlat.new()
	style.bg_color = color
	style.border_color = Color(0.76, 0.86, 0.78, 0.72)
	style.set_border_width_all(2)
	style.set_corner_radius_all(7)
	style.content_margin_left = 14
	style.content_margin_right = 14
	style.content_margin_top = 8
	style.content_margin_bottom = 8
	return style


static func apply_button(button: BaseButton) -> void:
	button.add_theme_font_override("font", TuffyFont)
	button.add_theme_color_override("font_color", LIGHT_TEXT)
	button.add_theme_color_override("font_hover_color", Color.WHITE)
	button.add_theme_color_override("font_pressed_color", Color.WHITE)
	button.add_theme_color_override("font_focus_color", Color.WHITE)
	button.add_theme_color_override("font_disabled_color", DISABLED_TEXT)
	button.add_theme_stylebox_override("normal", button_style(NAVY))
	button.add_theme_stylebox_override("hover", button_style(NAVY_HOVER))
	button.add_theme_stylebox_override("pressed", button_style(GREEN))
	button.add_theme_stylebox_override("focus", button_style(NAVY_HOVER))
	button.add_theme_stylebox_override(
		"disabled", button_style(Color(0.37, 0.42, 0.40, 0.55))
	)
	button.custom_minimum_size.y = maxf(button.custom_minimum_size.y, 40.0)


static func ocean_button_style(color: Color) -> StyleBoxFlat:
	var style := button_style(color)
	style.set_border_width_all(0)
	return style


static func apply_ocean_button(button: BaseButton) -> void:
	button.add_theme_font_override("font", TuffyFont)
	button.add_theme_color_override("font_color", OCEAN_TEXT_PRIMARY)
	button.add_theme_color_override("font_hover_color", Color.WHITE)
	button.add_theme_color_override("font_pressed_color", Color.WHITE)
	button.add_theme_color_override("font_focus_color", Color.WHITE)
	button.add_theme_color_override(
		"font_disabled_color",
		Color(OCEAN_TEXT_SECONDARY, 0.52),
	)
	button.add_theme_stylebox_override(
		"normal", ocean_button_style(OCEAN_BUTTON)
	)
	button.add_theme_stylebox_override(
		"hover", ocean_button_style(OCEAN_BUTTON_HOVER)
	)
	button.add_theme_stylebox_override(
		"pressed", ocean_button_style(OCEAN_SELECTED)
	)
	button.add_theme_stylebox_override(
		"focus", ocean_button_style(OCEAN_SELECTED)
	)
	button.add_theme_stylebox_override(
		"disabled", ocean_button_style(OCEAN_DISABLED)
	)
	button.custom_minimum_size.y = maxf(button.custom_minimum_size.y, 40.0)


static func apply_compact_ocean_button(button: BaseButton) -> void:
	apply_ocean_button(button)
	for state: StringName in [
		&"normal", &"hover", &"pressed", &"focus", &"disabled",
	]:
		var style := button.get_theme_stylebox(state).duplicate() as StyleBoxFlat
		if style == null:
			continue
		style.content_margin_left = 10.0
		style.content_margin_right = 10.0
		style.content_margin_top = 4.0
		style.content_margin_bottom = 4.0
		button.add_theme_stylebox_override(state, style)
	button.custom_minimum_size.y = 34.0


static func apply_line_edit(edit: LineEdit) -> void:
	edit.add_theme_font_override("font", TuffyFont)
	edit.add_theme_color_override("font_color", LIGHT_TEXT)
	edit.add_theme_color_override(
		"font_placeholder_color", Color(0.82, 0.80, 0.71, 0.84)
	)
	edit.add_theme_color_override("font_selected_color", Color.WHITE)
	edit.add_theme_color_override("caret_color", Color("fff0b6"))
	edit.add_theme_color_override("selection_color", Color("2f7186"))
	edit.add_theme_color_override("font_uneditable_color", Color("c9c2ae"))
	edit.add_theme_stylebox_override("normal", button_style(NAVY))
	edit.add_theme_stylebox_override("focus", button_style(NAVY_HOVER))
	edit.add_theme_stylebox_override(
		"read_only", button_style(Color(NAVY, 0.82))
	)


static func apply_ocean_line_edit(edit: LineEdit) -> void:
	edit.add_theme_font_override("font", TuffyFont)
	edit.add_theme_color_override("font_color", OCEAN_TEXT_PRIMARY)
	edit.add_theme_color_override(
		"font_placeholder_color", Color(OCEAN_TEXT_SECONDARY, 0.78)
	)
	edit.add_theme_color_override("font_selected_color", Color.WHITE)
	edit.add_theme_color_override("caret_color", OCEAN_TEXT_PRIMARY)
	edit.add_theme_color_override("selection_color", OCEAN_SELECTED)
	edit.add_theme_color_override("font_uneditable_color", OCEAN_TEXT_SECONDARY)
	edit.add_theme_stylebox_override(
		"normal", ocean_button_style(OCEAN_FIELD)
	)
	edit.add_theme_stylebox_override(
		"focus", ocean_button_style(OCEAN_SELECTED)
	)
	edit.add_theme_stylebox_override(
		"read_only", ocean_button_style(Color(OCEAN_FIELD, 0.82))
	)


static func apply_text_edit(edit: TextEdit) -> void:
	edit.add_theme_font_override("font", TuffyFont)
	edit.add_theme_color_override("font_color", OCEAN_TEXT_PRIMARY)
	edit.add_theme_color_override(
		"font_placeholder_color", Color(OCEAN_TEXT_SECONDARY, 0.78)
	)
	edit.add_theme_color_override("font_selected_color", Color.WHITE)
	edit.add_theme_color_override("caret_color", OCEAN_TEXT_PRIMARY)
	edit.add_theme_color_override("selection_color", OCEAN_SELECTED)
	edit.add_theme_stylebox_override("normal", ocean_button_style(OCEAN_FIELD))
	edit.add_theme_stylebox_override("focus", ocean_button_style(OCEAN_SELECTED))


static func animate_in(control: Control) -> void:
	_cancel_motion(control)
	control.pivot_offset = control.size * 0.5
	control.scale = Vector2.ONE * UIMotion.UTILITY_ENTER_SCALE
	control.modulate.a = 0.0
	control.mouse_filter = Control.MOUSE_FILTER_IGNORE
	var tween := control.create_tween()
	control.set_meta(MOTION_TWEEN_META, tween)
	tween.set_parallel(true)
	tween.tween_property(
		control, "scale", Vector2.ONE, UIMotion.UTILITY_ENTER_DURATION
	).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
	tween.tween_property(
		control, "modulate:a", 1.0, UIMotion.UTILITY_ENTER_DURATION
	)
	tween.finished.connect(func() -> void:
		if is_instance_valid(control):
			control.mouse_filter = Control.MOUSE_FILTER_PASS
			control.remove_meta(MOTION_TWEEN_META)
	)


static func animate_out(control: Control, completed: Callable) -> void:
	_cancel_motion(control)
	control.mouse_filter = Control.MOUSE_FILTER_IGNORE
	control.pivot_offset = control.size * 0.5
	var tween := control.create_tween()
	control.set_meta(MOTION_TWEEN_META, tween)
	tween.set_parallel(true)
	tween.tween_property(
		control,
		"scale",
		Vector2.ONE * UIMotion.UTILITY_ENTER_SCALE,
		UIMotion.UTILITY_EXIT_DURATION
	).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
	tween.tween_property(
		control, "modulate:a", 0.0, UIMotion.UTILITY_EXIT_DURATION
	)
	if completed.is_valid():
		tween.finished.connect(completed, CONNECT_ONE_SHOT)
	tween.finished.connect(func() -> void:
		if is_instance_valid(control):
			control.remove_meta(MOTION_TWEEN_META)
	)


static func _cancel_motion(control: Control) -> void:
	if not control.has_meta(MOTION_TWEEN_META):
		return
	var existing := control.get_meta(MOTION_TWEEN_META) as Tween
	if existing != null and existing.is_valid():
		existing.kill()
	control.remove_meta(MOTION_TWEEN_META)
