using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;


public class Playtomic : MonoBehaviour
{
    private PAchievements _achievements;
    private PGameVars _gamevars;
    private PGeoIP _geoip;
    private PLeaderboards _leaderboards;
    private PLeaderboardsTable _leaderboardstable;
    private PNewsletter _newsletter;
    private PPlayerLevels _playerlevels;
    public bool IsInitialized { get; private set; }
    internal static Playtomic Api { get; private set; }

    public static PLeaderboards Leaderboards
    {
        get { return Api._leaderboards; }
    }

    public static PLeaderboardsTable LeaderboardsTable
    {
        get { return Api._leaderboardstable; }
    }

    public static PPlayerLevels PlayerLevels
    {
        get { return Api._playerlevels; }
    }

    public static PGeoIP GeoIp
    {
        get { return Api._geoip; }
    }

    public static PGameVars GameVars
    {
        get { return Api._gamevars; }
    }

    public static PAchievements Achievements
    {
        get { return Api._achievements; }
    }

    public static PNewsletter Newsletter
    {
        get { return Api._newsletter; }
    }

    /// <summary>
    ///     Fires when Playtomic finishes / fails initializing.
    ///     True = InitializedResult. False = Failed.
    /// </summary>
    public event Action<bool> InitializedResult;

    /// <summary>
    ///     Initializes the API. You must do this before anything else.
    ///     <see cref="Idnet" /> handles this.
    /// </summary>
    /// <param name="idnetAppId">
    ///     <see cref="Idnet.AppId" />
    /// </param>
    /// <param name="hostUrl">Server address of <see cref="Idnet" />'s Playtomic implementation.</param>
    /// <param name="hostGameObject">GameObject to host this.</param>
    public static void Initialize(string idnetAppId, string hostUrl, GameObject hostGameObject)
    {
        if (Api != null && Api.IsInitialized)
            return;

        if (string.IsNullOrEmpty(idnetAppId))
            throw new ArgumentNullException("idnetAppId");

        if (string.IsNullOrEmpty(hostUrl))
            throw new ArgumentNullException("hostUrl");

        Api = hostGameObject.AddComponent<Playtomic>();
        Api._leaderboards = new PLeaderboards();
        Api._leaderboardstable = new PLeaderboardsTable();
        Api._playerlevels = new PPlayerLevels();
        Api._geoip = new PGeoIP();
        Api._gamevars = new PGameVars();
        Api._achievements = new PAchievements();
        Api._newsletter = new PNewsletter();

        PRequest.Initialise(idnetAppId, hostUrl);
    }

    protected static void OnInitialized()
    {
        var handler = Api.InitializedResult;
        if (handler != null) handler(Api.IsInitialized);
    }

    internal static class PRequest
    {
        public static Dictionary<string, PResponse> Requests = new Dictionary<string, PResponse>();

        /// <summary>
        ///     <see cref="Idnet.AppId" />. Playtomic's key is the same.
        /// </summary>
        private static string _idnetAppId;

        /// <summary>
        ///     Location of Playtomic's server instance.
        /// </summary>
        private static string _hostUrl;

        /// <summary>
        ///     Playtomic user session token.
        /// </summary>
        private static string _playtomicSessionToken;


        public static void Initialise(string idnetAppId, string hostUrl)
        {
            _idnetAppId = idnetAppId;
            _hostUrl = hostUrl;

            Api.StartCoroutine(CR_InitializeAsync());
        }

        public static WWW Prepare(string section, string action, Dictionary<string, object> postdata = null)
        {
            //Block IDnet api calls if api count is above 150 in last 5 minutes.
            if (Idnet.ApiCallsCounter >= 150)
            {
                Idnet.I.CheckApiCount();
                Idnet.I.Gui.Interactable = true;
                Idnet.I.CloseGui();
                return null;
            }

            // Increment ApiCount
            Idnet.I.AddApiCount();

            var url = _hostUrl;

            postdata = CleanPostData(section, action, postdata);

            // Get Json data.
            var json = PJSON.JsonEncode(postdata);
            var encodedJson = Encoding.UTF8.GetBytes(json);

            // Set encrypted hash. 
            var hash = json + _playtomicSessionToken;
            hash = PEncode.SHA256(hash);
            hash = hash.Substring(0, 20);

            url += "?hash=" + hash;

#if (UNITY_EDITOR || IDNET_DEBUG) && false 
            Debug.Log("PResponse.Prepare WWW.text:\n" + url + "\n" + json + "\n" + hash);
#endif

            return new WWW(url, encodedJson, Idnet.PlaytomicHeaders);
        }

        public static PResponse Process(WWW www)
        {
            if (www == null)
                return PResponse.GeneralError(1);

            if (!string.IsNullOrEmpty(www.error))
                return PResponse.GeneralError(www.error);

            if (string.IsNullOrEmpty(www.text))
                return PResponse.Error(1);

#if IDNET_DEBUG
            Debug.Log("PResponse.Process Success WWW.text:\n" + www.text);
#endif

            var results = (Dictionary<string, object>)PJSON.JsonDecode(www.text);

            if (!(results.ContainsKey("success") || results.ContainsKey("errorcode")))
                return PResponse.GeneralError(1);

            PResponse response;
            int errorcode;
            if (int.TryParse(results["errorcode"].ToString(), out errorcode))
            {
                if (errorcode != 0)
                {
                    if (!string.IsNullOrEmpty(results["errormessage"].ToString()))
                    {
                        response = new PResponse
                        {
                            success = false,
                            errorcode = (int)(double)results["errorcode"],
                            errormessage = (string)results["errormessage"],
                            json = results
                        };
                        return response;
                    }
                }
            }

            response = new PResponse
            {
                success = (bool)results["success"],
                errorcode = (int)(double)results["errorcode"],
                json = results
            };

            return response;
        }

        private static WWW CreateWww(string url, string json)
        {
            var post = new WWWForm();


#if UNITY_EDITOR || IDNET_DEBUG
            Debug.Log("Playtomic: publickey:\n" +
                      _idnetAppId +
                      "\nFinal Url:\n" +
                      url +
                      "\nJson:\n" +
                      json);
#endif

            return new WWW(_hostUrl, post);
        }

        private static Dictionary<string, object> CleanPostData(string section, string action,
            Dictionary<string, object> postdata)
        {
            if (postdata == null)
            {
                postdata = new Dictionary<string, object>();
            }
            else
            {
                postdata.Remove("appid");
                postdata.Remove("section");
                postdata.Remove("action");
            }

            postdata.Add("appid", _idnetAppId);
            postdata.Add("section", section);
            postdata.Add("action", action);

            return postdata;
        }

        private static IEnumerator CR_InitializeAsync()
        {
            var url = _hostUrl + "?hash=1";
            var jsonData = CleanPostData("init", "start", new Dictionary<string, object> { { "appid", Idnet.AppId } });

            var json = PJSON.JsonEncode(jsonData);
            var encodedJson = Encoding.UTF8.GetBytes(json);
            PResponse response;
            WWW www = new WWW(url, encodedJson, Idnet.PlaytomicHeaders);

            yield return www;

            response = Process(www);

            if (response.success)
            {
                _playtomicSessionToken = response.json["appsession"] as string;
                Idnet.I.GameName = response.json["appname"] as string;

                if (string.IsNullOrEmpty(_playtomicSessionToken))
                {
                    Debug.LogError(Api + " failed to return appsession!", Api);
                }
                else
                {
                    Debug.Log(Api + " IsInitialized."
#if UNITY_EDITOR || IDNET_DEBUG
                              + " : " + _playtomicSessionToken
#endif
                        , Api);
                    Api.IsInitialized = true;
                    OnInitialized();
                }
            }
            else
            {
                Debug.LogError(
                    Api + " failed to initialize! " + response.errorcode + " | " + response.errormessage,
                    Api);
            }
            /*
            // Calling Tracker API when login gets sucessfull "play"
#if UNITY_WEBGL && !UNITY_EDITOR        
            Idnet.I.StartCoroutine (IdnetTracker.CR_SendTrackerStats ("play"));
#endif
            */
        }
    }
}