@icon("../assets/chat-icon.svg")
@tool
extends Twitcher

## Grants access to read and write to a chat
class_name TwitchChat

static var _log: TwitchLogger = TwitchLogger.new("TwitchChat")

static var instance: TwitchChat

@export var broadcaster_user: TwitchUser:
	set(val):
		broadcaster_user = val
		update_configuration_warnings()
## Can be null. Then the owner of the access token will be used to send message aka the current user.
@export var sender_user: TwitchUser
@export var media_loader: TwitchMediaLoader
@export var eventsub: TwitchEventsub:
	set(val):
		eventsub = val
		update_configuration_warnings()
@export var api: TwitchAPI:
	set(val):
		api = val
		update_configuration_warnings()

## Should it subscribe on ready
@export var subscribe_on_ready: bool = true


## Triggered when a chat message got received
signal message_received(message: TwitchChatMessage)


func _ready() -> void:
	_log.d("is ready")
	if media_loader == null: media_loader = TwitchMediaLoader.instance
	if api == null: api = TwitchAPI.instance
	if eventsub == null: eventsub = TwitchEventsub.instance
	eventsub.event.connect(_on_event_received)
	if not Engine.is_editor_hint() && subscribe_on_ready:
		subscribe()


func _enter_tree() -> void:
	if instance == null: instance = self


func _exit_tree() -> void:
	if instance == self: instance = null


## Subscribe to eventsub and preload data if not happend yet
func subscribe() -> void:
	if broadcaster_user == null:
		printerr("BroadcasterUser is not set. Can't subscribe to chat.")
		return

	if is_instance_valid(media_loader):
		media_loader.preload_badges(broadcaster_user.id)
		media_loader.preload_emotes(broadcaster_user.id)

	for subscription: TwitchEventsubConfig in eventsub.get_subscriptions():
		if subscription.type == TwitchEventsubDefinition.Type.CHANNEL_CHAT_MESSAGE and \
			subscription.condition.broadcaster_user_id == broadcaster_user.id:
				# it is already subscribed
				return

	if sender_user == null:
		var current_user: TwitchGetUsers.Response = await api.get_users(null)
		sender_user = current_user.data[0]

	var config: TwitchEventsubConfig = TwitchEventsubConfig.new()
	config.type = TwitchEventsubDefinition.Type.CHANNEL_CHAT_MESSAGE
	config.condition = {
		"broadcaster_user_id": broadcaster_user.id,
		"user_id": sender_user.id
	}
	eventsub.subscribe(config)
	_log.i("Listen to Chat of %s (%s)" % [broadcaster_user.display_name, broadcaster_user.id])


func _on_event_received(type: StringName, data: Dictionary) -> void:
	if type != TwitchEventsubDefinition.CHANNEL_CHAT_MESSAGE.value: return
	var message: TwitchChatMessage = TwitchChatMessage.from_json(data)
	if message.broadcaster_user_id == broadcaster_user.id:
		message_received.emit(message)


func send_message(message: String, reply_parent_message_id: String = "") -> Array[TwitchSendChatMessage.ResponseData]:
	var message_body: TwitchSendChatMessage.Body = TwitchSendChatMessage.Body.new()
	message_body.broadcaster_id = broadcaster_user.id
	message_body.sender_id = sender_user.id
	message_body.message = message
	if reply_parent_message_id:
		message_body.reply_parent_message_id = reply_parent_message_id

	var response: TwitchSendChatMessage.Response = await api.send_chat_message(message_body)
	if _log.enabled:
		for message_data: TwitchSendChatMessage.ResponseData in response.data:
			if not message_data.is_sent:
				_log.w(message_data.drop_reason)

	return response.data


func _get_configuration_warnings() -> PackedStringArray:
	var result: PackedStringArray = []
	if eventsub == null:
		result.append("TwitchEventsub not assigned")
	if api == null:
		result.append("TwitchAPI not assigned")
	if broadcaster_user == null:
		result.append("Target broadcaster not specified")
	return result
