class_name ProgressionManagerClass
extends Node

## Progression system — XP, levels, unlocks.
## Each level unlocks new products, printer slots, worker slots, and features.

# Player state
var player_level: int = 1
var experience: float = 0.0

# XP required to reach each level (cumulative)
const LEVEL_XP: Array[int] = [
	0,      # Lv1 (start)
	40,     # Lv2 — reachable in ~4 orders
	100,    # Lv3
	200,    # Lv4
	350,    # Lv5
	550,    # Lv6
	800,    # Lv7
	1100,   # Lv8
	1500,   # Lv9
	2000,   # Lv10
]

# Unlock table per level
# products = NEW products unlocked at this level (cumulative with previous)
const UNLOCK_TABLE: Dictionary = {
	1:  {"max_printers": 1, "max_workers": 1, "max_shelves": 1, "products": ["phone_case", "keychain"], "features": [], "description": "Startup - one printer, big dreams"},
	2:  {"max_printers": 2, "max_workers": 1, "max_shelves": 2, "products": ["small_vase"], "features": [], "description": "Second printer + shelf slot unlocked!"},
	3:  {"max_printers": 2, "max_workers": 2, "max_shelves": 3, "products": ["gear"], "features": [], "description": "First extra employee + new shelf!"},
	4:  {"max_printers": 3, "max_workers": 2, "max_shelves": 3, "products": ["figurine"], "features": [], "description": "Third printer + figurines!"},
	5:  {"max_printers": 3, "max_workers": 3, "max_shelves": 4, "products": [], "features": ["post_processing"], "description": "Post-Processing zone + 4th shelf!"},
	6:  {"max_printers": 4, "max_workers": 3, "max_shelves": 4, "products": [], "features": [], "description": "Fourth printer slot!"},
	7:  {"max_printers": 4, "max_workers": 4, "max_shelves": 4, "products": [], "features": [], "description": "Full team assembled!"},
	8:  {"max_printers": 5, "max_workers": 4, "max_shelves": 4, "products": [], "features": [], "description": "Five printers running!"},
	9:  {"max_printers": 5, "max_workers": 5, "max_shelves": 4, "products": [], "features": [], "description": "Maximum workforce!"},
	10: {"max_printers": 6, "max_workers": 5, "max_shelves": 4, "products": [], "features": ["resin_lab"], "description": "RESIN LAB unlocked! New era."},
}

# Signals
signal xp_gained(amount: int, new_total: float)
signal level_up(new_level: int, unlocks: Dictionary)
signal product_unlocked(product_id: String)
signal feature_unlocked(feature_id: String)


var _is_verifying: bool = false


func _ready() -> void:
	# Wave 06: Old OrderManager connection removed. NewOrderManager calls directly.
	call_deferred("_verify")
	print("[ProgressionManager] initialized (level: %d, xp: %.0f)" % [player_level, experience])


# --- XP System ---

func add_xp(amount: int) -> void:
	experience += amount
	if not _is_verifying:
		xp_gained.emit(amount, experience)
		print("[Progression] +%d XP (total: %.0f, need: %d for Lv%d)" % [amount, experience, _xp_for_next_level(), player_level + 1])

	# Check for level up (can be multiple levels at once)
	while player_level < LEVEL_XP.size() and experience >= _xp_for_next_level():
		_do_level_up()


func _do_level_up() -> void:
	player_level += 1
	var unlocks = get_level_unlocks(player_level)
	if not _is_verifying:
		print("[Progression] LEVEL UP! Now level %d: %s" % [player_level, unlocks.get("description", "")])

		# Emit new product unlocks
		for product_id in unlocks.get("products", []):
			product_unlocked.emit(product_id)

		# Emit new feature unlocks
		for feature_id in unlocks.get("features", []):
			feature_unlocked.emit(feature_id)

	level_up.emit(player_level, unlocks)


func _xp_for_next_level() -> int:
	if player_level >= LEVEL_XP.size():
		return 999999  # Max level reached
	return LEVEL_XP[player_level]  # XP array is 0-indexed, level is 1-indexed, so LEVEL_XP[level] = xp for level+1


func add_xp_for_order(order_data: Dictionary) -> void:
	## Called directly by NewOrderManager when a shop order is completed.
	var difficulty: int = 1
	var product_db = get_tree().root.get_node_or_null("Main/Systems/ProductDatabase")
	if is_instance_valid(product_db):
		var product = product_db.get_product(order_data.get("product_id", ""))
		if product:
			difficulty = product.difficulty

	var base_xp: int = max(5, difficulty * 5 + 5)

	# Speed bonus
	var time_remaining: float = order_data.get("time_remaining", 0.0)
	var total_time: float = order_data.get("deadline", 120.0)
	if total_time > 0.0:
		var time_ratio: float = time_remaining / total_time
		if time_ratio > 0.5:
			base_xp = int(base_xp * 1.5)
		elif time_ratio > 0.3:
			base_xp = int(base_xp * 1.2)

	add_xp(base_xp)


func _on_order_completed(order) -> void:
	## Legacy handler — no longer connected. Kept for reference.
	if not is_instance_valid(order):
		return
	var base_xp: int = 10
	if order.product:
		base_xp = max(5, order.product.difficulty * 5 + 5)

	var time_remaining = order.deadline - _get_game_time()
	var total_time = order.deadline - order.created_at
	if total_time > 0.0:
		var time_ratio = time_remaining / total_time
		if time_ratio > 0.5:
			base_xp = int(base_xp * 1.5)
		elif time_ratio > 0.3:
			base_xp = int(base_xp * 1.2)

	add_xp(base_xp)


# --- Query Functions ---

func get_level_unlocks(level: int) -> Dictionary:
	if UNLOCK_TABLE.has(level):
		return UNLOCK_TABLE[level]
	# For levels beyond table, return last known unlock
	return UNLOCK_TABLE.get(LEVEL_XP.size(), {"max_printers": 6, "max_workers": 6, "products": [], "features": [], "description": "Max level!"})


func get_max_printers() -> int:
	var result: int = 1
	for lv in range(1, player_level + 1):
		if UNLOCK_TABLE.has(lv):
			result = UNLOCK_TABLE[lv].max_printers
	return result


func get_max_workers() -> int:
	var result: int = 1
	for lv in range(1, player_level + 1):
		if UNLOCK_TABLE.has(lv):
			result = UNLOCK_TABLE[lv].max_workers
	return result


func get_unlocked_products() -> Array[String]:
	## Returns ALL product IDs unlocked up to current level (cumulative)
	var result: Array[String] = []
	for lv in range(1, player_level + 1):
		if UNLOCK_TABLE.has(lv):
			for pid in UNLOCK_TABLE[lv].products:
				if pid not in result:
					result.append(pid)
	return result


func get_unlocked_features() -> Array[String]:
	var result: Array[String] = []
	for lv in range(1, player_level + 1):
		if UNLOCK_TABLE.has(lv):
			for fid in UNLOCK_TABLE[lv].features:
				if fid not in result:
					result.append(fid)
	return result


func is_feature_unlocked(feature_id: String) -> bool:
	return feature_id in get_unlocked_features()


func get_xp_progress() -> float:
	## Returns 0.0-1.0 progress toward next level
	if player_level >= LEVEL_XP.size():
		return 1.0  # Max level
	var current_threshold = LEVEL_XP[player_level - 1] if player_level > 1 else 0
	var next_threshold = _xp_for_next_level()
	var range_size = next_threshold - current_threshold
	if range_size <= 0:
		return 1.0
	return clampf((experience - current_threshold) / float(range_size), 0.0, 1.0)


func get_xp_for_display() -> Dictionary:
	## Returns current XP and threshold for UI display
	var current_threshold = LEVEL_XP[player_level - 1] if player_level > 1 else 0
	var next_threshold = _xp_for_next_level()
	return {
		"current": experience,
		"current_in_level": experience - current_threshold,
		"needed_in_level": next_threshold - current_threshold,
		"progress": get_xp_progress(),
	}


# --- Helpers ---

func _get_game_time() -> float:
	if GameManager:
		return GameManager.game_time
	return 0.0


# --- Serialization ---

func serialize() -> Dictionary:
	return {
		"player_level": player_level,
		"experience": experience,
	}


func deserialize(data: Dictionary) -> void:
	player_level = data.get("player_level", 1)
	experience = data.get("experience", 0.0)
	print("[ProgressionManager] Deserialized: level=%d, xp=%.0f" % [player_level, experience])


# --- Runtime Verification ---

func _verify() -> void:
	_is_verifying = true
	var saved_level = player_level
	var saved_xp = experience

	# --- Test: add_xp_for_order increases XP ---
	player_level = 1
	experience = 0.0
	var test_order: Dictionary = {
		"order_id": "test_001", "product_id": "keychain",
		"deadline": 120.0, "time_remaining": 80.0,
	}
	add_xp_for_order(test_order)
	assert(experience > 0.0, "ProgressionManager._verify: order should give XP")
	print("[ProgressionManager] PASS: add_xp_for_order gives XP")

	# --- Test: level up triggers ---
	player_level = 1
	experience = 39.0  # Just under level 2 threshold (40)
	var level_up_fired: Array = [false]
	var _on_lvl = func(_l, _u): level_up_fired[0] = true
	level_up.connect(_on_lvl)
	add_xp_for_order(test_order)  # Should push over 40 XP
	level_up.disconnect(_on_lvl)
	assert(level_up_fired[0] or experience < 40.0, "ProgressionManager._verify: level_up should fire or XP insufficient")
	print("[ProgressionManager] PASS: level up check")

	# Restore
	player_level = saved_level
	experience = saved_xp
	_is_verifying = false
	print("[ProgressionManager] _verify passed")
