using System;
using System.Threading.Tasks;
using UnityEngine;

namespace CoolGameX
{
    /// <summary>A single achievement definition for the current game.</summary>
    [Serializable]
    public class AchievementInfo
    {
        public string slug;
        public string name;
        public string description;
        public int points;
        public bool is_hidden;
        public string icon_url;
    }

    /// <summary>Result of an achievement unlock call.</summary>
    public struct UnlockResult
    {
        /// <summary>The request succeeded.</summary>
        public bool Success;
        /// <summary>True only the first time it's unlocked (false if already had it).</summary>
        public bool NewlyUnlocked;
        /// <summary>Error message, if any.</summary>
        public string Error;
    }

    /// <summary>Unlock and query achievements for the current game.</summary>
    public class Achievements
    {
        /// <summary>
        /// Fires when an achievement is unlocked for the FIRST time (not on
        /// repeat calls). Subscribe to show your own in-game toast, play a sound,
        /// etc. The argument is the achievement slug.
        /// </summary>
        public event Action<string> OnAchievementUnlocked;

        [Serializable]
        private class UnlockResponse
        {
            public bool success;
            public bool newlyUnlocked;
        }

        /// <summary>
        /// Unlocks an achievement by its slug for the logged-in player.
        /// Safe to call repeatedly — the backend ignores duplicates.
        /// </summary>
        /// <returns>True if the request succeeded.</returns>
        public async Task<bool> Unlock(string achievementSlug)
        {
            var result = await UnlockDetailed(achievementSlug);
            return result.Success;
        }

        /// <summary>
        /// Like <see cref="Unlock"/>, but returns a detailed result including
        /// whether this was the first time the achievement was unlocked.
        /// </summary>
        public async Task<UnlockResult> UnlockDetailed(string achievementSlug)
        {
            if (string.IsNullOrEmpty(achievementSlug))
            {
                Debug.LogWarning("[CoolAPI] Unlock called with empty slug.");
                return new UnlockResult { Success = false, Error = "Empty slug" };
            }

            var json =
                $"{{\"gameSlug\":\"{Escape(CoolAPI.GameSlug)}\"," +
                $"\"achievementSlug\":\"{Escape(achievementSlug)}\"}}";

            var res = await Net.PostJson("/api/achievements/unlock", json);
            if (!res.Success)
                return new UnlockResult { Success = false, Error = res.Error };

            bool newly = true;
            try
            {
                var parsed = JsonUtility.FromJson<UnlockResponse>(res.Body);
                if (parsed != null) newly = parsed.newlyUnlocked;
            }
            catch { /* tolerate parse issues; assume newly unlocked */ }

            if (newly)
            {
                Debug.Log($"[CoolAPI] Achievement '{achievementSlug}' unlocked!");
                try { OnAchievementUnlocked?.Invoke(achievementSlug); }
                catch (Exception e) { Debug.LogException(e); }
            }

            return new UnlockResult { Success = true, NewlyUnlocked = newly };
        }

        [Serializable] private class GameDetailResponse { public AchievementInfo[] achievements; }

        /// <summary>
        /// Returns this game's achievement definitions (slug, name, description,
        /// points, hidden flag, icon URL) as a typed array.
        /// </summary>
        public async Task<AchievementInfo[]> GetDefinitions()
        {
            var res = await Net.Get($"/api/games/{Uri.EscapeDataString(CoolAPI.GameSlug)}");
            if (!res.Success) return Array.Empty<AchievementInfo>();
            try
            {
                var parsed = JsonUtility.FromJson<GameDetailResponse>(res.Body);
                return parsed?.achievements ?? Array.Empty<AchievementInfo>();
            }
            catch { return Array.Empty<AchievementInfo>(); }
        }

        /// <summary>
        /// Returns the raw JSON for this game's detail payload (from
        /// GET /api/games/:slug). Prefer <see cref="GetDefinitions"/> for typed data.
        /// </summary>
        public async Task<string> List()
        {
            var res = await Net.Get($"/api/games/{Uri.EscapeDataString(CoolAPI.GameSlug)}");
            return res.Success ? res.Body : null;
        }

        private static string Escape(string s) =>
            s?.Replace("\\", "\\\\").Replace("\"", "\\\"") ?? "";
    }
}
