#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;

using IGP.UnitySDK.Models;
using Newtonsoft.Json;

namespace IGP.UnitySDK
{
    public sealed partial class IGPDesktopSessionClient
    {

        public async Task<IGPDesktopSessionCommandResult> UnlockAchievementAsync(
            string achievementKey,
            string? eventId = null,
            long? occurredAtUnixMs = null,
            int? appId = null,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(achievementKey))
            {
                throw new ArgumentException("Achievement key is required", nameof(achievementKey));
            }

            var payload = JsonConvert.SerializeObject(new
            {
                eventId = ResolveAchievementEventId(eventId),
                occurredAt = occurredAtUnixMs,
                appId,
            });

            return await SendCommandAsync(
                IGPDesktopSessionCommandType.UnlockAchievement,
                cancellationToken,
                stringValue: achievementKey,
                contentJson: payload);
        }

        public async Task<IGPDesktopSessionCommandResult> ReportAchievementProgressAsync(
            string achievementKey,
            double progressValue,
            string? progressSourceKey = null,
            string? eventId = null,
            long? occurredAtUnixMs = null,
            int? appId = null,
            CancellationToken cancellationToken = default)
        {
            return await ReportAchievementProgressCoreAsync(
                achievementKey,
                progressValue,
                progressSourceKey,
                progressValueMode: null,
                eventId,
                occurredAtUnixMs,
                appId,
                cancellationToken);
        }

        public async Task<IGPDesktopSessionCommandResult> ReportAchievementProgressAsync(
            string achievementKey,
            double progressValue,
            string? progressSourceKey,
            ProgressValueMode progressValueMode,
            string? eventId = null,
            long? occurredAtUnixMs = null,
            int? appId = null,
            CancellationToken cancellationToken = default)
        {
            return await ReportAchievementProgressCoreAsync(
                achievementKey,
                progressValue,
                progressSourceKey,
                progressValueMode,
                eventId,
                occurredAtUnixMs,
                appId,
                cancellationToken);
        }

        private async Task<IGPDesktopSessionCommandResult> ReportAchievementProgressCoreAsync(
            string achievementKey,
            double progressValue,
            string? progressSourceKey,
            ProgressValueMode? progressValueMode,
            string? eventId,
            long? occurredAtUnixMs,
            int? appId,
            CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(achievementKey))
            {
                throw new ArgumentException("Achievement key is required", nameof(achievementKey));
            }

            var payloadFields = new Dictionary<string, object?>
            {
                ["progressValue"] = progressValue,
                ["progressSourceKey"] = progressSourceKey,
                ["eventId"] = ResolveAchievementEventId(eventId),
                ["occurredAt"] = occurredAtUnixMs,
                ["appId"] = appId,
            };

            if (progressValueMode.HasValue)
            {
                payloadFields["progressValueMode"] = SerializeProgressValueMode(progressValueMode.Value);
            }

            var payload = JsonConvert.SerializeObject(payloadFields);

            return await SendCommandAsync(
                IGPDesktopSessionCommandType.ReportAchievementProgress,
                cancellationToken,
                stringValue: achievementKey,
                contentJson: payload);
        }

        public async Task<IGPDesktopSessionCommandResult> ClearAchievementsAsync(
            int? appId = null,
            CancellationToken cancellationToken = default)
        {
            var payload = appId.HasValue && appId.Value > 0
                ? JsonConvert.SerializeObject(new
                {
                    appId,
                })
                : null;

            return await SendCommandAsync(
                IGPDesktopSessionCommandType.ClearAchievements,
                cancellationToken,
                contentJson: payload);
        }

        private static string SerializeProgressValueMode(ProgressValueMode progressValueMode)
        {
            switch (progressValueMode)
            {
                case ProgressValueMode.Set:
                    return "SET";
                case ProgressValueMode.Increment:
                    return "INCREMENT";
                default:
                    throw new ArgumentOutOfRangeException(
                        nameof(progressValueMode),
                        progressValueMode,
                        "Unsupported achievement progress value mode");
            }
        }

        private static string ResolveAchievementEventId(string? eventId)
        {
            return string.IsNullOrWhiteSpace(eventId)
                ? Guid.NewGuid().ToString("N")
                : eventId;
        }
    }
}
