using Newtonsoft.Json;
using RestEase;
using Skuld.Core.Models;
using System;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;

namespace Skuld.API.Client;

public class SkuldAPI : ISkuldAPIClient, IDisposable
{
	public static string WrapperVersion { get; } =
		typeof(SkuldAPI).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ??
		typeof(SkuldAPI).GetTypeInfo().Assembly.GetName().Version.ToString(3) ??
		"Unknown";

	private readonly ISkuldAPIClient _api;

	static string ApiBase;
	static string Token;
	private bool disposedValue;

	public SkuldAPI()
	{

	}

	public SkuldAPI(string apiBase, string token)
	{
		ApiBase = apiBase;
		Token = token;

		var httpClient = new HttpClient
		{
			BaseAddress = new Uri(ApiBase)
		};
		httpClient.DefaultRequestHeaders.Add("User-Agent", $"Skuld.API.Client.Client/v{WrapperVersion} (https://github.com/skuldbot/Skuld)");

		if (!string.IsNullOrWhiteSpace(Token))
		{
			httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {Token}");
		}

		JsonSerializerSettings settings = new()
		{
			Formatting = Formatting.Indented,
			NullValueHandling = NullValueHandling.Ignore
		};

		_api = new RestClient(httpClient)
		{
			JsonSerializerSettings = settings
		}.For<ISkuldAPIClient>();
	}

	/// <summary>
	/// Get a guild
	/// </summary>
	/// <param name="id">Guild Id</param>
	/// <returns><see cref="EventResult"/> wrapped <see cref="Guild"/></returns>
	public Task<EventResult> GetGuildAsync(ulong id)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetGuildAsync(id) : null;

	/// <summary>
	/// Get a user
	/// </summary>
	/// <param name="id">User Id</param>
	/// <returns><see cref="EventResult"/> wrapped <see cref="User"/></returns>
	public Task<EventResult> GetUserAsync(ulong id)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetUserAsync(id) : null;

	/// <summary>
	/// Get a user's profile card
	/// </summary>
	/// <param name="id">User Id</param>
	/// <returns><see cref="Stream"/> of profile card data</returns>
	public Task<Stream> GetProfileCardAsync(ulong id)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetProfileCardAsync(id) : null;

	/// <summary>
	/// Get a user's profile card with guild attributes
	/// </summary>
	/// <param name="id">User Id</param>
	/// <param name="id">Guild Id</param>
	/// <returns><see cref="Stream"/> of profile card data</returns>
	public Task<Stream> GetProfileCardAsync(ulong id, ulong guildId)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetProfileCardAsync(id, guildId) : null;

	/// <summary>
	/// Get a user's rank card
	/// </summary>
	/// <param name="id">User Id</param>
	/// <param name="guildId">Guild Id</param>
	/// <returns><see cref="Stream"/> of profile card data</returns>
	public Task<Stream> GetRankCardAsync(ulong id, ulong guildId)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetRankCardAsync(id, guildId) : null;

	/// <summary>
	/// Preview's a custom background image
	/// </summary>
	/// <param name="id">User Id</param>
	/// <param name="previewBackground">Background to preview</param>
	/// <returns><see cref="Stream"/> of profile card data</returns>
	public Task<Stream> GetExampleProfileCardAsync(ulong id, string previewBackground)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetExampleProfileCardAsync(id, previewBackground) : null;

	/// <summary>
	/// Gets the experience leaderboard
	/// </summary>
	/// <param name="guildId">Guild Id, Accepts 0 for all</param>
	/// <param name="page">%10 offset page</param>
	/// <returns><see cref="EventResult"/> wrapped <see cref="UserExperience"/></returns>
	public Task<EventResult> GetExperienceLeaderboardAsync(ulong guildId, int page = 0)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetExperienceLeaderboardAsync(guildId, page) : null;

	/// <summary>
	/// Gets the money leaderboard
	/// </summary>
	/// <param name="guildId">Guild Id, Accepts 0 for all</param>
	/// <param name="page">%10 offset page</param>
	/// <returns><see cref="EventResult"/> wrapped <see cref="User"/></returns>
	public Task<EventResult> GetMoneyLeaderboardAsync(ulong guildId, int page = 0)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetMoneyLeaderboardAsync(guildId, page) : null;

	public Task<Stream> GetLiquidRescaledAsync(string image)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetLiquidRescaledAsync(image) : null;

	/// <summary>
	/// Get's the join card for a guild
	/// </summary>
	/// <param name="id">User Id</param>
	/// <param name="guildId">Guild Id</param>
	/// <returns><see cref="Stream"/> of join card</returns>
	public Task<Stream> GetJoinCardAsync(ulong id, ulong guildId)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetJoinCardAsync(id, guildId) : null;

	/// <summary>
	/// Get's the leave card for a guild
	/// </summary>
	/// <param name="id">User Id</param>
	/// <param name="guildId">Guild Id</param>
	/// <returns><see cref="Stream"/> of leave card</returns>
	public Task<Stream> GetLeaveCardAsync(ulong id, ulong guildId)
		=> !string.IsNullOrWhiteSpace(Token) ? _api.GetLeaveCardAsync(id, guildId) : null;

	protected virtual void Dispose(bool disposing)
	{
		if (!disposedValue)
		{
			if (disposing)
			{
				// TODO: dispose managed state (managed objects)
			}

			// TODO: free unmanaged resources (unmanaged objects) and override finalizer
			// TODO: set large fields to null
			disposedValue = true;
		}
	}

	// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
	// ~SkuldAPI()
	// {
	//     // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
	//     Dispose(disposing: false);
	// }
	public void Dispose()
	{
		// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
		Dispose(disposing: true);
		GC.SuppressFinalize(this);
	}
}