# naughty.games SDK for Godot 4 web exports (SDK v1): lifecycle and ad breaks.
# Guide: https://naughty.games/guides/in-game-ads-sdk
#
# Setup:
#   1. Add this script as an autoload named NaughtyGamesSdk
#      (Project > Project Settings > Globals > Autoload).
#   2. In Project > Export > Web, paste this into HTML > Head Include:
#        <script src="https://naughty.games/sdk/v1.js"></script>
#
# Use:
#   NaughtyGamesSdk.game_loading_finished()
#   await NaughtyGamesSdk.commercial_break()
#   if await NaughtyGamesSdk.rewarded_break():
#       give_coins(50)
#
# Rules: grant a reward only when rewarded_break() returns true. A break can
# finish at once (no ad available, or too soon after the last one), so always
# carry on with the game after the await.
extends Node

signal initialized(env: String)
signal paused
signal resumed
signal muted
signal unmuted

signal _commercial_done
signal _rewarded_done(granted: bool)

## Pause the scene tree while an ad plays.
@export var pause_tree_during_ads := true
## Mute the Master bus while an ad plays.
@export var mute_audio_during_ads := true

## "naughty" on naughty.games, "local" on localhost (test ads), "inert" anywhere else.
var env := "inert"

var _sdk: JavaScriptObject = null
# JavaScriptBridge callbacks are freed when nothing holds them: keep them here.
var _callbacks: Array[JavaScriptObject] = []
var _commercial_busy := false
var _rewarded_busy := false


func _ready() -> void:
	# Keep receiving resume/unmute while the tree is paused.
	process_mode = Node.PROCESS_MODE_ALWAYS
	if not OS.has_feature("web"):
		_on_init.call_deferred([])
		return
	_sdk = JavaScriptBridge.get_interface("NgSdk")
	if _sdk == null:
		push_warning("naughty.games SDK not found. Add the script tag to HTML > Head Include.")
		_on_init.call_deferred([])
		return
	for event_name in ["pause", "resume", "mute", "unmute"]:
		var cb := JavaScriptBridge.create_callback(_on_sdk_event.bind(event_name))
		_callbacks.append(cb)
		_sdk.on(event_name, cb)
	var on_init := JavaScriptBridge.create_callback(_on_init)
	_callbacks.append(on_init)
	_sdk.init().then(on_init)


func game_loading_finished() -> void:
	if _sdk != null:
		_sdk.gameLoadingFinished()


func gameplay_start() -> void:
	if _sdk != null:
		_sdk.gameplayStart()


func gameplay_stop() -> void:
	if _sdk != null:
		_sdk.gameplayStop()


## Shows an ad between levels if one is due. Often returns at once.
func commercial_break() -> void:
	if _sdk == null or _commercial_busy:
		return
	_commercial_busy = true
	var cb := JavaScriptBridge.create_callback(func(_args: Array) -> void: _commercial_done.emit())
	_callbacks.append(cb)
	_sdk.commercialBreak().then(cb, cb)
	await _commercial_done
	_callbacks.erase(cb)
	_commercial_busy = false


## Offers a rewarded ad. True only when the player watched it to the end.
func rewarded_break() -> bool:
	if _sdk == null or _rewarded_busy:
		return false
	_rewarded_busy = true
	var on_result := JavaScriptBridge.create_callback(
		func(args: Array) -> void: _rewarded_done.emit(args.size() > 0 and args[0] == true)
	)
	var on_error := JavaScriptBridge.create_callback(
		func(_args: Array) -> void: _rewarded_done.emit(false)
	)
	_callbacks.append(on_result)
	_callbacks.append(on_error)
	_sdk.rewardedBreak().then(on_result, on_error)
	var granted: bool = await _rewarded_done
	_callbacks.erase(on_result)
	_callbacks.erase(on_error)
	_rewarded_busy = false
	return granted


func _on_init(args: Array) -> void:
	if args.size() > 0 and args[0] != null:
		env = str(args[0].env)
	initialized.emit(env)


func _on_sdk_event(_args: Array, event_name: String) -> void:
	match event_name:
		"pause":
			if pause_tree_during_ads:
				get_tree().paused = true
			paused.emit()
		"resume":
			if pause_tree_during_ads:
				get_tree().paused = false
			resumed.emit()
		"mute":
			if mute_audio_during_ads:
				AudioServer.set_bus_mute(AudioServer.get_bus_index("Master"), true)
			muted.emit()
		"unmute":
			if mute_audio_during_ads:
				AudioServer.set_bus_mute(AudioServer.get_bus_index("Master"), false)
			unmuted.emit()
