extends RefCounted

## Local mirror for GET [code]/game/players/{id}/cooldown-snapshot[/code] (NEO-32).
## Uses [code]serverTimeUtc[/code] + receive tick to approximate server "now" between polls.

const SLOT_COUNT: int = 8
## Reject bogus [method Time.get_unix_time_from_datetime_string] results (failed parse → 0).
const MIN_VALID_UNIX_ANCHOR: float = 1_000_000_000.0

var _slot_end_unix: PackedFloat64Array = PackedFloat64Array()
var _server_unix_at_receive: float = 0.0
var _ticks_msec_at_receive: int = 0


func _init() -> void:
	_slot_end_unix.resize(SLOT_COUNT)
	for i in range(SLOT_COUNT):
		_slot_end_unix[i] = 0.0


func apply_snapshot(snapshot: Dictionary) -> void:
	for i in range(SLOT_COUNT):
		_slot_end_unix[i] = 0.0
	var st: Variant = snapshot.get("serverTimeUtc", null)
	var anchor: float = 0.0
	if st is String:
		var su: String = (st as String).strip_edges()
		if not su.is_empty():
			anchor = Time.get_unix_time_from_datetime_string(su)
	elif st is float:
		anchor = st as float
	elif st is int:
		anchor = float(st as int)
	if anchor < MIN_VALID_UNIX_ANCHOR:
		anchor = Time.get_unix_time_from_system()
	_server_unix_at_receive = anchor
	_ticks_msec_at_receive = Time.get_ticks_msec()
	var slots: Variant = snapshot.get("slots", [])
	if slots is Array:
		for item in slots as Array:
			if not item is Dictionary:
				continue
			var d: Dictionary = item
			var idx: int = int(d.get("slotIndex", -1))
			if idx < 0 or idx >= SLOT_COUNT:
				continue
			var end_v: Variant = d.get("cooldownEndsAtUtc", null)
			if end_v is String and not (end_v as String).is_empty():
				var end_s: String = (end_v as String).strip_edges()
				var end_unix: float = Time.get_unix_time_from_datetime_string(end_s)
				if end_unix >= MIN_VALID_UNIX_ANCHOR:
					_slot_end_unix[idx] = end_unix


func _effective_server_unix() -> float:
	return _server_unix_at_receive + (Time.get_ticks_msec() - _ticks_msec_at_receive) * 0.001


func remaining_for_slot(slot_index: int) -> float:
	if slot_index < 0 or slot_index >= _slot_end_unix.size():
		return 0.0
	var end_u: float = _slot_end_unix[slot_index]
	if end_u <= 0.0:
		return 0.0
	return maxf(0.0, end_u - _effective_server_unix())


func is_slot_cooling(slot_index: int) -> bool:
	return remaining_for_slot(slot_index) > 0.0


func any_slot_cooling() -> bool:
	for i in range(_slot_end_unix.size()):
		if remaining_for_slot(i) > 0.0:
			return true
	return false


func build_hud_line() -> String:
	var parts: PackedStringArray = PackedStringArray()
	for i in range(_slot_end_unix.size()):
		var rem: float = remaining_for_slot(i)
		if rem > 0.0:
			parts.append("slot %d: %.1fs" % [i, rem])
	if parts.is_empty():
		return "Cooldowns: (ready)"
	return "Cooldowns: " + ", ".join(parts)
