﻿using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using UnityEngine;

public class ErrorLogger : MonoBehaviour {

    public bool logError = false;
    public bool logException = false;
    static string path;

    static Dictionary<string, float> sent;

    // Use this for initialization
    void Awake() {
        path = Path.Combine(Environment.CurrentDirectory, "log.txt");
        sent = new Dictionary<string, float>();
    }

    void OnEnable() {
        Application.logMessageReceivedThreaded += HandleLog;
    }
    void OnDisable() {
        Application.logMessageReceivedThreaded -= HandleLog;
    }

    void OnApplicationQuit() {
        // since this isn't shared we can add a little appendage to the end to break it up a bit between plays
#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN
        LogEndOfExcution();
#endif
    }

    // Update is called once per frame
    void Update() {
        // can only be used in the editor to force a quick log for testing
        if (logError) {
            Debug.LogError("testing log error handling");
            logError = false;
        }
        if (logException) {
            Debug.LogException(new Exception("testing exception handling"));
            logException = false;
        }
    }

    void HandleLog(string logString, string stackTrace, LogType type) {
        if (type == LogType.Error || type == LogType.Exception) {
            LogEverywhereICan(logString, stackTrace);
        }
    }

    // use this if we want to track something manually
    public static void WriteToLog(string message) {
        LogEverywhereICan(message, UnityEngine.StackTraceUtility.ExtractStackTrace());
        print(message); // print so you can see it in the editor console as well
    }

    static void LogEverywhereICan(string logString, string stackTrace) {
#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN
        LogToFileOnSystem(logString, stackTrace);
#endif
        //if (PersistentData.localPlayerData.playFabId == null)
        //    return;

        //// send it to server through cloudscript
        //string completeMessage = "ID: " + PersistentData.localPlayerData.playFabId + "\n"
        //    + "UTC: " + DateTime.UtcNow + "\n"
        //    + logString + "\n"
        //    + stackTrace + "\n";

        //if (CanISendToServer(stackTrace)) {
        //    PlayfabCloudScriptAPI.LogErrorToServer(completeMessage);
        //    sent.Add(stackTrace, Time.unscaledTime + 5.0f);
        //}
    }

    static bool CanISendToServer(string stackTrace) {
        bool canSend = true;
        RemoveOldSends();
        foreach (KeyValuePair<string, float> entry in sent) {
            if (entry.Key == stackTrace) {
                return canSend = false;
            }
        }
        return canSend;
    }

    static void RemoveOldSends() {
        List<string> entriesToRemove = new List<string>();
        foreach (KeyValuePair<string, float> entry in sent) {
            if (entry.Value < Time.unscaledTime) {
                entriesToRemove.Add(entry.Key);
            }
        }

        for (int i = 0; i < entriesToRemove.Count; i++) {
            sent.Remove(entriesToRemove[i]);
        }
    }

    static void LogToFileOnSystem(string message, string stackTrace) {
        // This text is added only once to the file.
        if (!File.Exists(path)) {
            // Create a file to write to.
            using (StreamWriter sw = File.CreateText(path)) {
                sw.WriteLine("Welcome to the error log!");
                sw.WriteLine("");
            }
        }

        using (StreamWriter sw = File.AppendText(path)) {
            //if (PersistentData.localPlayerData.playFabId != null) {
            //    sw.WriteLine("ID: " + PersistentData.localPlayerData.playFabId);
            //}
            sw.WriteLine("UTC: " + DateTime.UtcNow);
            sw.WriteLine(message);
            sw.WriteLine(stackTrace);
            sw.WriteLine();
        }
    }

    // should only be called in standalone and editor
    void LogEndOfExcution() {
        using (StreamWriter sw = File.AppendText(path)) {
            sw.WriteLine("////////////////");
            sw.WriteLine("END OF EXECUTION");
            sw.WriteLine("////////////////");
            sw.WriteLine("");
        }
    }
}
