#nullable enable
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using IGP.UnitySDK.Models;
using Newtonsoft.Json;

namespace IGP.UnitySDK.GameKit
{
    public sealed class IGPPlayersException : Exception
    {
        public IGPPlayersException(
            string code,
            string message,
            string? upstreamJson = null)
            : base(message)
        {
            Code = code ?? string.Empty;
            UpstreamJson = upstreamJson;
        }

        public string Code { get; }
        public string? UpstreamJson { get; }
    }

    public static class IGPPlayers
    {
        public const int MaxUserIds = 50;
        public const string InvalidPlayerIdsCode = "INVALID_PLAYER_IDS";
        public const string InvalidResponseCode = "PLAYER_PROFILES_INVALID_RESPONSE";

        /// <summary>
        /// Fetches simple public profiles for 1 to 50 platform user ids.
        /// </summary>
        public static async Task<IGPPlayerProfile[]> GetProfilesAsync(
            IGPRuntimeManager runtimeManager,
            string[] userIds)
        {
            if (runtimeManager == null)
            {
                throw new ArgumentNullException(nameof(runtimeManager));
            }

            var normalizedUserIds = NormalizeUserIds(userIds);
            var contentJson = JsonConvert.SerializeObject(new { userIds = normalizedUserIds });

            IGPDesktopSessionCommandResult result;
            try
            {
                result = await runtimeManager.GetDesktopPlayerProfilesAsync(contentJson);
            }
            catch (IGPSDKException ex)
            {
                throw new IGPPlayersException(
                    string.IsNullOrWhiteSpace(ex.ErrorCode)
                        ? IGPErrorCodes.ERR_DESKTOP_SESSION_REQUIRED
                        : ex.ErrorCode!,
                    string.IsNullOrWhiteSpace(ex.Message)
                        ? "Player profiles command failed"
                        : ex.Message);
            }

            if (result == null)
            {
                throw new IGPPlayersException(
                    IGPErrorCodes.ERR_DESKTOP_SESSION_REQUIRED,
                    "Desktop session returned no player profiles command result");
            }

            if (!result.Success)
            {
                throw new IGPPlayersException(
                    string.IsNullOrWhiteSpace(result.Code)
                        ? IGPErrorCodes.ERR_DESKTOP_SESSION_REQUIRED
                        : result.Code,
                    string.IsNullOrWhiteSpace(result.Message)
                        ? "Player profiles command failed"
                        : result.Message,
                    result.ContentJson);
            }

            if (string.IsNullOrWhiteSpace(result.ContentJson))
            {
                throw new IGPPlayersException(
                    InvalidResponseCode,
                    "Player profiles response contentJson is empty");
            }

            try
            {
                var profiles = JsonConvert.DeserializeObject<IGPPlayerProfile[]>(result.ContentJson);
                if (profiles == null)
                {
                    throw new IGPPlayersException(
                        InvalidResponseCode,
                        "Player profiles response contentJson could not be parsed",
                        result.ContentJson);
                }

                foreach (var profile in profiles)
                {
                    if (profile == null || string.IsNullOrWhiteSpace(profile.id))
                    {
                        throw new IGPPlayersException(
                            InvalidResponseCode,
                            "Player profiles response contains an invalid profile",
                            result.ContentJson);
                    }
                }

                return profiles;
            }
            catch (IGPPlayersException)
            {
                throw;
            }
            catch (JsonException ex)
            {
                throw new IGPPlayersException(
                    InvalidResponseCode,
                    $"Player profiles response contentJson is invalid JSON: {ex.Message}",
                    result.ContentJson);
            }
        }

        private static string[] NormalizeUserIds(string[] userIds)
        {
            if (userIds == null || userIds.Length < 1 || userIds.Length > MaxUserIds)
            {
                throw new IGPPlayersException(
                    InvalidPlayerIdsCode,
                    $"userIds must contain 1 to {MaxUserIds} ids");
            }

            var uniqueUserIds = new List<string>(userIds.Length);
            var seen = new HashSet<string>(StringComparer.Ordinal);
            foreach (var userId in userIds)
            {
                var normalized = userId?.Trim() ?? string.Empty;
                if (string.IsNullOrWhiteSpace(normalized) || normalized.Length > 128)
                {
                    throw new IGPPlayersException(
                        InvalidPlayerIdsCode,
                        "userIds must not contain empty or oversized ids");
                }

                if (seen.Add(normalized))
                {
                    uniqueUserIds.Add(normalized);
                }
            }

            return uniqueUserIds.ToArray();
        }
    }
}
