#include "pch.h"
#include "Internal.h"
#include "ChatImpl.h"
#include "ChannelImpl.h"

using namespace TwitchInGames;

namespace {
	ttv::ChannelId AsUserId(tstring const& clientId, tstring const& name) {
		ttv::ChannelId userId = _ttoi(name.c_str());
		if(userId == 0) {
			auto user = User::FetchOtherByLogin(clientId, name).get();
			userId = _ttoi(user.Id.c_str());
		}
		return userId;
	}
}

Chat::Channel::Channel(Chat& chat, tstring const& name, ReceiveCallback receiveCallback) :
	chat(chat),
	name(name),
	receiveCallback(receiveCallback),
	channelImpl(std::make_shared<ChannelImpl>(*this, *chat.chatImpl, AsUserId(chat.clientId, name), receiveCallback)),
	state(Opened) {}

Chat::Channel::~Channel() {
	if(state == Opened) {
		try {
			DebugWriteLine(_T("[Chat::Channel::~Channel] not closed; current state is %d"), state);
			Depart().get();
		} catch(TwitchException const& ex) {
			UNREFERENCED_PARAMETER(ex);
			DebugWriteLine(_T("[Chat::Channel::~Channel] failure; error %d"), ex.ErrorCode);
		} catch(std::exception const& ex) {
			UNREFERENCED_PARAMETER(ex);
			DebugWriteLine(_T("[Chat::Channel::~Channel] failure; error \"%s\""), ToTstring(ex.what()).c_str());
		}
	}
}

std::future<void> TwitchInGames::Chat::Channel::Depart() {
	if(state != Opened) {
		throw TwitchException(FromPlatformError(ERROR_INVALID_OPERATION));
	}
	state= Closing;
	auto fn= [this] {
		// Perform the depart hand-shake.
		try {
			channelImpl.reset();
			LockedOperation(chat.channelsAccess, [this] { chat.channels.erase(name); });
			SendUserScienceEvent(chat.clientId, chat.login, _T("sdk_chat_leave_channel"), { { _T("chat_channel_name"), name } });
			state= Closed;
		} catch(TwitchException const& ex) {
			UNREFERENCED_PARAMETER(ex);
			DebugWriteLine(_T("[Chat::Channel::Depart] failure; error %d"), ex.ErrorCode);
		} catch(std::exception const& ex) {
			UNREFERENCED_PARAMETER(ex);
			DebugWriteLine(_T("[Chat::Channel::Depart] failure; error \"%s\""), ToTstring(ex.what()).c_str());
		}
	};
	return std::async(std::launch::deferred, fn);
}

std::future<void> Chat::Channel::SendLine(string_t message) {
	if(state != Opened) {
		throw TwitchException(FromPlatformError(ERROR_INVALID_OPERATION));
	}
	return channelImpl->Send(message);
}
