#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
#define COMPILE
#endif

#if COMPILE
using Discord;
using System;
using Logger = Cryville.Common.Logging.Logger;
#endif
using UnityEngine;

namespace Cryville.Crtr {
	internal class DiscordController : MonoBehaviour {
#if COMPILE
		public static DiscordController Instance;

		const long CLIENT_ID = 1059021675578007622L;

		Discord.Discord dc;
		ActivityManager am;
		long launchTime;

		void Start() {
			Instance = this;
			launchTime = (long)(DateTime.UtcNow - DateTime.UnixEpoch).TotalSeconds;
			try {
				dc = new Discord.Discord(CLIENT_ID, (UInt64)CreateFlags.NoRequireDiscord);
				Logger.Log("main", 1, "Discord", "Connected to Discord");
				am = dc.GetActivityManager();
				SetIdle();
			}
			catch (ResultException) {
				if (dc != null) {
					dc.Dispose();
					dc = null;
				}
				Logger.Log("main", 3, "Discord", "Cannot connect to Discord");
			}
		}

		void Update() {
			if (dc == null) return;
			try {
				dc.RunCallbacks();
			}
			catch (ResultException ex) {
				dc.Dispose();
				dc = null;
				Logger.Log("main", 4, "Discord", "An error occurred while running callbacks: {0}", ex);
			}
		}

		void OnApplicationQuit() {
			if (dc == null) return;
			dc.Dispose();
		}

		void Callback(Result result) { }

		public void SetIdle() {
			if (dc == null) return;
			am.UpdateActivity(new Activity {
				State = "Idle",
				Instance = false,
				Timestamps = { Start = launchTime },
			}, Callback);
		}

		string _detail;
		double? _duration;
		public void SetPlaying(string detail, double? duration) {
			if (dc == null) return;
			_detail = detail;
			_duration = duration;
			long now = (long)(DateTime.UtcNow - DateTime.UnixEpoch).TotalSeconds;
			am.UpdateActivity(new Activity {
				State = "Playing a chart",
				Details = _detail,
				Instance = true,
				Timestamps = {
					Start = now,
					End = _duration == null ? 0 : now + (long)_duration,
				},
			}, Callback);
		}

		public void SetPaused() {
			if (dc == null) return;
			am.UpdateActivity(new Activity {
				State = "Playing a chart (Paused)",
				Details = _detail,
				Instance = true,
			}, Callback);
		}

		public void SetResume(double timestamp) {
			if (dc == null) return;
			long now = (long)(DateTime.UtcNow - DateTime.UnixEpoch).TotalSeconds;
			am.UpdateActivity(new Activity {
				State = "Playing a chart",
				Details = _detail,
				Instance = true,
				Timestamps = {
					Start = now - (long)timestamp,
					End = _duration == null ? 0 : now + (long)_duration - (long)timestamp,
				},
			}, Callback);
		}
#endif
	}
}
