extends Control

@onready var currency_label: Label = %CurrencyLabel
@onready var wood_label: Label = %WoodLabel
@onready var stock_label: Label = %StockLabel

@onready var modifiers_label: Label = %ModifiersLabel
@onready var timer_label : Label = %Timer

@onready var game_complete_screen : Panel = %GameCompleted
@onready var completion_time_label : Label = %CompletionTimeLabel
@onready var continue_button : TextureButton = %ContinueButton
@onready var config_button : Button = %ConfigButton
@onready var config_panel : Panel = %ConfigPanel
@onready var player_name_input : TextEdit = %TextEdit
@onready var submit_score_button : TextureButton = %SubmitScoreButton
@onready var submission_status_label : Label = %SubmissionStatusLabel

var game_timer : Timer
var elapsed_time := 0.0
var current_nonce : String = ""
var bridge = null
var score_submitted := false

func _ready():
	populate_modifiers_display()
	populate_unlock_buttons()
	update_currency_label()
	update_wood_label()
	update_stock_label()
	
	game_timer = Timer.new()
	game_timer.wait_time = 1.0
	game_timer.one_shot = false
	game_timer.autostart = true
	add_child(game_timer)

	game_timer.timeout.connect(_on_timer_tick)

	currency_label.add_theme_color_override("font_color", Global.money_color)
	wood_label.add_theme_color_override("font_color", Global.wood_color)
	stock_label.add_theme_color_override("font_color", Global.stock_color)

	Inventory.currency_changed.connect(_on_currency_changed)
	Inventory.currency_added.connect(spawn_currency_increase)
	Inventory.currency_added.connect(_on_currency_added)
	Inventory.wood_changed.connect(_on_currency_changed)
	Inventory.wood_added.connect(spawn_wood_increase)
	Inventory.stock_added.connect(spawn_stock_increase)
	Inventory.stock_changed.connect(_on_currency_changed)
	Unlocks.item_unlocked.connect(populate_unlock_buttons)
	GameManager.currency_goal_met.connect(_on_currency_goal_met)

	if config_button:
		config_button.pressed.connect(_on_config_button_pressed)

	if submit_score_button:
		submit_score_button.pressed.connect(_on_submit_score_button_pressed)

	# Initialize JavaScript bridge for web builds
	if OS.has_feature("web"):
		bridge = JavaScriptBridge.get_interface("godotBridge")

	# get_tree().paused = true
	

func update_currency_label():
	currency_label.text = Global.currency_symbol + Global.format_number(Inventory.get_currency())

func update_wood_label():
	wood_label.text = Global.format_number(Inventory.get_wood())

func update_stock_label():
	stock_label.text = Global.format_number(Inventory.get_stock())

func spawn_currency_increase(value, _total):
	spawn_inventory_change_value(value, _total, "+", Global.currency_symbol, Global.money_color)

func spawn_wood_increase(value, _total):
	spawn_inventory_change_value(value, _total, "+", "", Global.wood_color)

func spawn_stock_increase(value, _total):
	spawn_inventory_change_value(value, _total, "+", "", Global.stock_color)

func spawn_inventory_change_value(value, _total, display_sign: String = "+", symbol: String = "", label_color: Color = Color.WHITE):
	var float_label = Label.new()
	float_label.text = display_sign + symbol + Global.format_number(abs(value))
	float_label.add_theme_font_size_override("font_size", 16)
	float_label.modulate = label_color
	
	# Add random offset around center
	var random_x = randf_range(-60, 30)
	var random_y = randf_range(-40, 20)
	float_label.position = Vector2(random_x, random_y)
	add_child(float_label)
	
	# Animate the label
	var tween = create_tween()
	tween.set_parallel(true) # Run both animations simultaneously
	# Move up
	tween.tween_property(float_label, "position:y", float_label.position.y - 50, 1.0)
	# Fade out
	tween.tween_property(float_label, "modulate:a", 0.0, 1.0)
	# Remove from scene when done
	tween.chain().tween_callback(float_label.queue_free)


func populate_unlock_buttons():
	var unlocks_container = $UnlockContainer
	for child in unlocks_container.get_children():
		child.free()

	for unlock_data in Unlocks.unlocks.unlocks:
		var unlock_button_scene = load("res://scenes/button.tscn")
		var unlock_button = unlock_button_scene.instantiate()
		unlocks_container.add_child(unlock_button)
		unlock_button.setup(unlock_data)

func populate_modifiers_display():
	var modifiers_text = ""

	modifiers_text = modifiers_text + "Sale Price: " + Global.currency_symbol + Global.format_number(Unlocks.get_sale_price_per_item()) + "\n"
	modifiers_text = modifiers_text + "Items Produced Per Tick: " + Global.format_number(Unlocks.get_items_produced_per_tick()) + "\n"
	modifiers_text = modifiers_text + "Wood per Click: " + Global.format_number(Unlocks.get_wood_per_click()) + "\n\n"
	modifiers_text = modifiers_text + "Demand: " + Global.format_number(Unlocks.get_sale_demand()) + "\n\n"

	modifiers_text = modifiers_text + "Current Modifiers:\n"
	for key in Unlocks.current_modifiers.keys():
		var display_name = key.replace("_modifier", "").replace("_", " ").capitalize()
		var percentage = int((Unlocks.current_modifiers[key] - 1.0) * 100)
		modifiers_text += "%s: %s%%\n" % [display_name, str(percentage)]

	modifiers_label.text = modifiers_text
	

func _on_currency_changed(_value):
	populate_modifiers_display()
	update_currency_label()
	update_wood_label()
	update_stock_label()
	
	if Inventory.get_currency() >= Global.target_currency:
		game_timer.stop()
	
func _on_timer_tick():
	elapsed_time += 1
	timer_label.text = format_time(elapsed_time)

func _on_currency_goal_met():
	Log.pr("Currency goal met!")
	get_tree().paused = true
	completion_time_label.text = format_time(elapsed_time)
	game_complete_screen.visible = true
	score_submitted = false

	# Request nonce from API when game is completed
	if bridge != null:
		# Disable submit button until nonce is received
		submit_score_button.disabled = true
		submission_status_label.visible = false
		_request_nonce()
	else:
		# No web bridge available, hide the submit button entirely
		submit_score_button.visible = false
		submission_status_label.visible = false
	
func format_time(seconds: float) -> String:
	var total_seconds := int(seconds)

	var hours := total_seconds / 3600
	var minutes := (total_seconds % 3600) / 60
	var secs := total_seconds % 60

	return "%02d:%02d:%02d" % [hours, minutes, secs]


func _on_continue_button_pressed() -> void:
	Global.game_continue_pressed = true
	game_complete_screen.visible = false
	get_tree().paused = false

func _on_config_button_pressed() -> void:
	if config_panel:
		config_panel.toggle_visibility()

func _on_currency_added(_value, _total):
	var audio_manager = get_node("/root/Audio")
	if audio_manager:
		audio_manager.play_money_sound()

# HIGH SCORE SUBMISSION FUNCTIONS

func _request_nonce():
	if bridge == null:
		return

	# Call JavaScript bridge to request nonce
	var result = bridge.requestNonce()

	# Set up polling to check if nonce was received
	# (since JS callbacks are async)
	var nonce_check_timer = Timer.new()
	nonce_check_timer.wait_time = 0.5
	nonce_check_timer.one_shot = false
	nonce_check_timer.process_mode = Node.PROCESS_MODE_ALWAYS  # Run even when paused
	add_child(nonce_check_timer)

	var attempts = 0
	var max_attempts = 20  # 10 seconds total

	nonce_check_timer.timeout.connect(func():
		attempts += 1
		var nonce = _get_nonce_from_js()

		if nonce != null and nonce != "" and nonce != "null":
			current_nonce = nonce
			# Enable submit button when nonce is ready
			submit_score_button.disabled = false
			nonce_check_timer.stop()
			nonce_check_timer.queue_free()
		elif attempts >= max_attempts:
			# Failed to get nonce - show error and keep button disabled
			submission_status_label.text = "Failed to connect to server"
			submission_status_label.modulate = Color(1.0, 0.3, 0.3)  # Red
			submission_status_label.visible = true
			nonce_check_timer.stop()
			nonce_check_timer.queue_free()
	)

	nonce_check_timer.start()

func _get_nonce_from_js() -> String:
	if bridge == null:
		return ""

	# Try to get the nonce that JavaScript stored
	var result = JavaScriptBridge.eval("""
		(function() {
			if (window.godotNonce) {
				return window.godotNonce;
			}
			return '';
		})();
	""", true)

	return str(result) if result != null else ""

func _on_submit_score_button_pressed():
	if score_submitted:
		submission_status_label.text = "Score already submitted!"
		submission_status_label.modulate = Color(1.0, 0.8, 0.3)  # Yellow
		submission_status_label.visible = true
		return

	if bridge == null or current_nonce == "":
		# This shouldn't happen as button should be disabled
		return

	# Disable button during submission and show status
	submit_score_button.disabled = true
	submission_status_label.text = "Submitting..."
	submission_status_label.modulate = Color(1.0, 1.0, 1.0)  # White
	submission_status_label.visible = true

	# Get player name from input and sanitize
	var player_name = _sanitize_player_name(player_name_input.text)
	if player_name == "":
		player_name = "Anonymous"

	# Get completion time in seconds
	var completion_time_seconds = int(elapsed_time)

	# Create and encode payload on GDScript side
	var encoded_payload = _create_encoded_payload(current_nonce, player_name, completion_time_seconds)

	# Call JavaScript to submit score with pre-encoded payload and nonce
	bridge.submitScore(encoded_payload, current_nonce)

	# Poll for submission result
	var submit_check_timer = Timer.new()
	submit_check_timer.wait_time = 0.5
	submit_check_timer.one_shot = false
	submit_check_timer.process_mode = Node.PROCESS_MODE_ALWAYS  # Run even when paused
	add_child(submit_check_timer)

	var attempts = 0
	var max_attempts = 30  # 15 seconds total

	submit_check_timer.timeout.connect(func():
		attempts += 1
		var result = _get_submission_result_from_js()

		if result.has("completed") and result["completed"]:
			submission_status_label.visible = true
			if result["success"]:
				submission_status_label.text = result.get("message", "Score submitted!")
				submission_status_label.modulate = Color(0.5, 1.0, 0.5)  # Green
				score_submitted = true

				# Show rank if available
				if result.has("rank") and result["rank"] > 0:
					submission_status_label.text += " (Rank #%d)" % result["rank"]
			else:
				submission_status_label.text = result.get("message", "Failed to submit")
				submission_status_label.modulate = Color(1.0, 0.3, 0.3)  # Red
				submit_score_button.disabled = false

			submit_check_timer.stop()
			submit_check_timer.queue_free()
		elif attempts >= max_attempts:
			submission_status_label.text = "Submission timeout"
			submission_status_label.modulate = Color(1.0, 0.3, 0.3)  # Red
			submission_status_label.visible = true
			submit_score_button.disabled = false
			submit_check_timer.stop()
			submit_check_timer.queue_free()
	)

	submit_check_timer.start()

func _get_submission_result_from_js() -> Dictionary:
	if bridge == null:
		return {}

	var result = JavaScriptBridge.eval("""
		(function() {
			if (window.godotSubmissionResult) {
				var result = window.godotSubmissionResult;
				window.godotSubmissionResult = null; // Clear after reading
				return JSON.stringify(result);
			}
			return '{}';
		})();
	""", true)

	if result != null and result != "":
		var json = JSON.new()
		var error = json.parse(str(result))
		if error == OK:
			return json.data

	return {}

func _create_encoded_payload(nonce: String, player_name: String, completion_time: int) -> String:
	# Create the payload as JSON
	var payload = {
		"nonce": nonce,
		"gameId": "whittling-clicker",  # Unique identifier for this game
		"playerName": player_name,
		"completionTime": completion_time,
		"timestamp": Time.get_unix_time_from_system() * 1000  # Convert to milliseconds
	}

	var json_string = JSON.stringify(payload)

	# XOR encode with key derived from nonce
	var key = "WHITTLING_KEY_" + nonce.substr(0, 8)
	var encoded_bytes = _xor_encode(json_string, key)

	# Base64 encode (using raw bytes)
	var base64_encoded = Marshalls.raw_to_base64(encoded_bytes)

	return base64_encoded

func _sanitize_player_name(name: String) -> String:
	# Strip leading/trailing whitespace
	name = name.strip_edges()

	# Remove control characters and most special characters, keep letters, numbers, spaces, and safe punctuation
	var safe_name = ""
	for i in range(name.length()):
		var c = name[i]
		var code = name.unicode_at(i)

		# Allow: letters, numbers, spaces, hyphens, underscores, periods
		# Block: control chars, path separators, quotes, angle brackets, etc
		if (code >= 48 and code <= 57) or \
		   (code >= 65 and code <= 90) or \
		   (code >= 97 and code <= 122) or \
		   c == " " or c == "-" or c == "_" or c == ".":
			safe_name += c

	# Limit length to 50 characters
	safe_name = safe_name.substr(0, 50)

	# Remove multiple consecutive spaces
	while safe_name.find("  ") != -1:
		safe_name = safe_name.replace("  ", " ")

	# Strip again after processing
	safe_name = safe_name.strip_edges()

	return safe_name

func _xor_encode(text: String, key: String) -> PackedByteArray:
	var text_bytes = text.to_utf8_buffer()
	var key_bytes = key.to_utf8_buffer()
	var key_length = key_bytes.size()
	var result = PackedByteArray()

	for i in range(text_bytes.size()):
		var xor_byte = text_bytes[i] ^ key_bytes[i % key_length]
		result.append(xor_byte)

	return result
