using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using TMPro;
using UnityEngine;

using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using UnityEditor;

public class exportServerPrefabs : MonoBehaviour
{
    private void Awake()
    {
        System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");

    }

    //public TextMeshPro textMeshProString;

    public exportToServer ExportToServer;

    private string CreateMD5(string input)
    {
        // Use input string to calculate MD5 hash
        using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
        {
            byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
            byte[] hashBytes = md5.ComputeHash(inputBytes);

            // Convert the byte array to hexadecimal string
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            for (int i = 0; i < hashBytes.Length; i++)
            {
                sb.Append(hashBytes[i].ToString("X2"));
            }
            return sb.ToString();
        }
    }


    private Dictionary<string, string> SpritesDictionary = new Dictionary<string, string>();
    private Dictionary<string, int> SpritesPPUDictionary = new Dictionary<string, int>();

    private Dictionary<string, string> AnimationsDictionary = new Dictionary<string, string>();


    // Start is called before the first frame update
    void Start()
    {


        int currentPrefabID = 1;

        string json = "{\"prefabs\":[";

        //going through each prefab
        foreach (Transform child in transform)
        {
            //taking all basic info:

            Vector3 position = child.localPosition;
            Vector3 scale = child.localScale;
            Vector3 rotation = new Vector3(child.localEulerAngles.x, child.localEulerAngles.y, child.localEulerAngles.z);

            //now going through the children of this gameobject

            int activeSelf = 1;
            if (child.gameObject.activeSelf == false)
            {
                activeSelf = 0;
            }

            string childJson = "{\"name\":\""+child.gameObject.name+"\",";
            childJson += "\"position\":[" + position.x + "," + position.y + "," + position.z + "],";
            childJson += "\"scale\":[" + scale.x + "," + scale.y + "," + scale.z + "],";
            childJson += "\"rotation\":[" + rotation.x + "," + rotation.y + "," + rotation.z + "],";
            childJson += "\"active\":" + activeSelf + ",";
            childJson += "\"id\":" + currentPrefabID + ",";

            childJson += "\"children\":" + TraverseAllChildren(child) + ",";

            childJson += "},";

            json += childJson;

            currentPrefabID += 1;

        }

        json += "],\"images\":[";

        foreach (KeyValuePair<string, string> keyValue in SpritesDictionary)
        {
            json += "{\"hash\":\""+ keyValue.Key + "\",\"base64\":\""+keyValue.Value+"\",\"ppu\":"+ SpritesPPUDictionary[keyValue.Key] + "},";
        }

        json += "]";

        json += ",\"animations\":[";

        foreach (KeyValuePair<string, string> keyValue in AnimationsDictionary)
        {
            json += "{\"hash\":\"" + keyValue.Key + "\",\"data\":" + keyValue.Value + "},";
        }

        json += "]}";

        //textMeshProString.text = json;

        JObject jsonParse = JObject.Parse(json);
        string jsonString = JsonConvert.SerializeObject(jsonParse);

        byte[] compressedString = CompressString(jsonString);

        string brotliProject = Convert.ToBase64String(compressedString);

        //textMeshProString.text = brotliProject;

        ExportToServer.StartUpload("prefabsBrotli", brotliProject);

        //Debug.Log(jsonString);

    }

    private byte[] CompressString(string str)
    {
        byte[] inputBytes = Encoding.UTF8.GetBytes(str);
        using (var outputStream = new MemoryStream())
        {
            using (var brotliStream = new BrotliStream(outputStream, System.IO.Compression.CompressionLevel.Optimal))
            {
                brotliStream.Write(inputBytes, 0, inputBytes.Length);
            }
            return outputStream.ToArray();
        }
    }

    // Recursively traverse all children, including nested children
    public string TraverseAllChildren(Transform parent)
    {
        // Loop through each child of the current parent

        string list = "[";

        foreach (Transform child in parent)
        {
            // Do something with the child, for example, log its name
            //Debug.Log("Found child: " + child.name);


            Vector3 position = child.localPosition;
            Vector3 scale = child.localScale;
            Vector3 rotation = new Vector3(child.localEulerAngles.x, child.localEulerAngles.y, child.localEulerAngles.z);

            string childComponentsJson = "[";

            SpriteRenderer _SpriteRenderer = child.GetComponent<SpriteRenderer>();
            if (_SpriteRenderer != null)
            {
                string base64String = ConvertSpriteToBase64(_SpriteRenderer.sprite);
                string md5hash = CreateMD5(base64String + (int)_SpriteRenderer.sprite.pixelsPerUnit).ToLower();
                //Debug.Log(base64String);

                if (!SpritesDictionary.ContainsKey(md5hash))
                {
                    //not yet exists
                    SpritesDictionary[md5hash] = base64String;
                }

                SpritesPPUDictionary[md5hash] = (int)_SpriteRenderer.sprite.pixelsPerUnit;

                childComponentsJson += "{\"type\":\"SpriteRenderer\",\"hash\":\""+ md5hash + "\",\"color\":["+ (int)(_SpriteRenderer.color.r*255f)+ ","+ (int)(_SpriteRenderer.color.g * 255f) + ","+ (int)(_SpriteRenderer.color.b * 255f)+","+ (int)(_SpriteRenderer.color.a * 255f)+"]},";
            }

            Animator _Animator = child.GetComponent<Animator>();

            if (_Animator != null && true)
            {

                //AnimationsDictionary

                string animatorJSON = "";
                animatorJSON += "{\"type\":\"Animator\",";

                List<Sprite> allSprites = GetAllSpritesFromAnimator(_Animator);

                animatorJSON += "\"frames\":[";

                foreach (Sprite sprite in allSprites)
                {
                    string base64String = ConvertSpriteToBase64(sprite);
                    string md5hash = CreateMD5(base64String + (int)sprite.pixelsPerUnit).ToLower();
                    //Debug.Log(base64String);

                    if (!SpritesDictionary.ContainsKey(md5hash))
                    {
                        //not yet exists
                        SpritesDictionary[md5hash] = base64String;
                    }

                    SpritesPPUDictionary[md5hash] = (int)sprite.pixelsPerUnit;
                    //Debug.Log("Sprite: " + sprite.name + " hash: " + md5hash);



                    animatorJSON += "\"" + md5hash + "\",";


                }

                animatorJSON += "],";

                AnimationClip _AnimationClip = _Animator.runtimeAnimatorController.animationClips[0];

                animatorJSON += "\"fps\":" + _AnimationClip.frameRate + ",";

                int _isLooped = 0;

                if (_AnimationClip.isLooping)
                {
                    _isLooped = 1;
                }

                animatorJSON += "\"isLooped\":" + _isLooped + ",";

                //animatorJSON += "\"hash\":\"" + animationHash + "\",";


                animatorJSON += "},";

                string animationHash = CreateMD5(animatorJSON).ToLower();

                if (!AnimationsDictionary.ContainsKey(animationHash))
                {
                    AnimationsDictionary[animationHash] = animatorJSON;
                }

                Debug.Log("Animation hash: " + animationHash);

                childComponentsJson += "{\"type\":\"CustomAnimator\",";

                childComponentsJson += "\"hash\":\"" + animationHash + "\",";

                childComponentsJson += "},";

            }


            TextMeshPro _TextMeshPro = child.GetComponent<TextMeshPro>();

            if (_TextMeshPro != null)
            {
                childComponentsJson += "{\"type\":\"TextMeshPro\",";

                childComponentsJson += "\"text\":\"" + _TextMeshPro.text + "\",";

                childComponentsJson += "\"color\":[" + (int)(_TextMeshPro.color.r * 255f) + "," + (int)(_TextMeshPro.color.g * 255f) + "," + (int)(_TextMeshPro.color.b * 255f) + "," + (int)(_TextMeshPro.color.a * 255f) + "],";


                FontStyles currentStyles = _TextMeshPro.fontStyle;


                string styles = "[";

                // Iterate through each style in the FontStyles enum
                foreach (FontStyles style in System.Enum.GetValues(typeof(FontStyles)))
                {
                    // Check if the style is enabled using a bitwise AND
                    if ((currentStyles & style) == style)
                    {
                        styles += "\"" + style + "\",";
                    }
                }

                styles += "]";


                if (styles != "[]")
                {
                    //Debug.Log(styles);
                    childComponentsJson += "\"fontStyles\":" + styles + ",";

                }

                childComponentsJson += "\"fontIndex\":" + Convert.ToInt32(_TextMeshPro.font.name) + ",";

                childComponentsJson += "\"fontSize\":" + _TextMeshPro.fontSize + ",";

                if (_TextMeshPro.enableAutoSizing == true)
                {

                    childComponentsJson += "\"autoSizing\":1,";
                    childComponentsJson += "\"fontSizeMin\":" + _TextMeshPro.fontSizeMin + ",";
                    childComponentsJson += "\"fontSizeMax\":" + _TextMeshPro.fontSizeMax + ",";

                }


                if (_TextMeshPro.horizontalAlignment == HorizontalAlignmentOptions.Center)
                {
                    childComponentsJson += "\"horizontalAlignment\":\"" + "center" + "\",";
                }
                else if (_TextMeshPro.horizontalAlignment == HorizontalAlignmentOptions.Left)
                {
                    childComponentsJson += "\"horizontalAlignment\":\"" + "left" + "\",";
                }
                else if (_TextMeshPro.horizontalAlignment == HorizontalAlignmentOptions.Right)
                {
                    childComponentsJson += "\"horizontalAlignment\":\"" + "right" + "\",";
                }
                else if (_TextMeshPro.horizontalAlignment == HorizontalAlignmentOptions.Flush)
                {
                    childComponentsJson += "\"horizontalAlignment\":\"" + "flush" + "\",";
                }
                else if (_TextMeshPro.horizontalAlignment == HorizontalAlignmentOptions.Justified)
                {
                    childComponentsJson += "\"horizontalAlignment\":\"" + "justified" + "\",";
                }
                else if (_TextMeshPro.horizontalAlignment == HorizontalAlignmentOptions.Geometry)
                {
                    childComponentsJson += "\"horizontalAlignment\":\"" + "geometry" + "\",";
                }

                if (_TextMeshPro.verticalAlignment == VerticalAlignmentOptions.Top)
                {
                    childComponentsJson += "\"verticalAlignment\":\"" + "top" + "\",";
                }
                else if (_TextMeshPro.verticalAlignment == VerticalAlignmentOptions.Middle)
                {
                    childComponentsJson += "\"verticalAlignment\":\"" + "middle" + "\",";
                }
                else if (_TextMeshPro.verticalAlignment == VerticalAlignmentOptions.Bottom)
                {
                    childComponentsJson += "\"verticalAlignment\":\"" + "bottom" + "\",";
                }
                else if (_TextMeshPro.verticalAlignment == VerticalAlignmentOptions.Baseline)
                {
                    childComponentsJson += "\"verticalAlignment\":\"" + "baseline" + "\",";
                }
                else if (_TextMeshPro.verticalAlignment == VerticalAlignmentOptions.Capline)
                {
                    childComponentsJson += "\"verticalAlignment\":\"" + "capline" + "\",";
                }
                else if (_TextMeshPro.verticalAlignment == VerticalAlignmentOptions.Geometry)
                {
                    childComponentsJson += "\"verticalAlignment\":\"" + "geometry" + "\",";
                }

                if (_TextMeshPro.enableWordWrapping == true)
                {
                    childComponentsJson += "\"enableWordWrapping\":1,";
                }

                if (_TextMeshPro.overflowMode == TextOverflowModes.Overflow)
                {
                    childComponentsJson += "\"overflowMode\":\"overflow\",";
                }
                else if (_TextMeshPro.overflowMode == TextOverflowModes.Truncate)
                {
                    childComponentsJson += "\"overflowMode\":\"truncate\",";
                }


                RectTransform _RectTransform = child.GetComponent<RectTransform>();


                childComponentsJson += "\"sizeDelta\":[" + _RectTransform.sizeDelta.x + ","+ _RectTransform.sizeDelta.y + "],";


                childComponentsJson += "},";
            }


            BoxCollider2D _BoxCollider2D = child.GetComponent<BoxCollider2D>();

            if (_BoxCollider2D != null)
            {
                childComponentsJson += "{\"type\":\"BoxCollider2D\",";

                childComponentsJson += "\"offset\":[" + _BoxCollider2D.offset.x + "," + _BoxCollider2D.offset.y + "],";
                childComponentsJson += "\"size\":[" + _BoxCollider2D.size.x + "," + _BoxCollider2D.size.y + "],";
                childComponentsJson += "\"edgeRadius\":" + _BoxCollider2D.edgeRadius + ",";

                childComponentsJson += "},";
            }

            CapsuleCollider2D _CapsuleCollider2D = child.GetComponent<CapsuleCollider2D>();

            if (_CapsuleCollider2D != null)
            {
                childComponentsJson += "{\"type\":\"CapsuleCollider2D\",";

                childComponentsJson += "\"offset\":[" + _CapsuleCollider2D.offset.x + "," + _CapsuleCollider2D.offset.y + "],";
                childComponentsJson += "\"size\":[" + _CapsuleCollider2D.size.x + "," + _CapsuleCollider2D.size.y + "],";

                string _direction = "Vertical";
                if (_CapsuleCollider2D.direction == CapsuleDirection2D.Horizontal)
                {
                    _direction = "Horizontal";
                }

                childComponentsJson += "\"direction\":\"" + _direction + "\",";

                childComponentsJson += "},";
            }

            CircleCollider2D _CircleCollider2D = child.GetComponent<CircleCollider2D>();

            if (_CircleCollider2D != null)
            {
                childComponentsJson += "{\"type\":\"CircleCollider2D\",";

                childComponentsJson += "\"offset\":[" + _CircleCollider2D.offset.x + "," + _CircleCollider2D.offset.y + "],";

                childComponentsJson += "\"radius\":" + _CircleCollider2D.radius + ",";

                childComponentsJson += "},";
            }

            PolygonCollider2D _PolygonCollider2D = child.GetComponent<PolygonCollider2D>();

            if (_PolygonCollider2D != null)
            {
                childComponentsJson += "{\"type\":\"PolygonCollider2D\",";
                childComponentsJson += "\"offset\":[" + _PolygonCollider2D.offset.x + "," + _PolygonCollider2D.offset.y + "],";

                childComponentsJson += "\"points\":[";

                for (int i = 0; i < _PolygonCollider2D.points.Length; i++)
                {
                    childComponentsJson += "[" + _PolygonCollider2D.points[i].x + "," + _PolygonCollider2D.points[i].y + "],";
                }

                childComponentsJson += "],";

                childComponentsJson += "},";
            }


            childComponentsJson += "]";

            int activeSelf = 1;
            if (child.gameObject.activeSelf == false)
            {
                activeSelf = 0;
            }

            string childJson = "{";
            childJson += "\"position\":[" + position.x + "," + position.y + "," + position.z + "],";
            childJson += "\"scale\":[" + scale.x + "," + scale.y + "," + scale.z + "],";
            childJson += "\"rotation\":[" + rotation.x + "," + rotation.y + "," + rotation.z + "],";
            childJson += "\"active\":" + activeSelf + ",";

            childJson += "\"components\":" +childComponentsJson+",";

            // Call the function recursively to traverse its children

            //now going deeper
            string childrenListJson = TraverseAllChildren(child);

            childJson += "\"children\":" + childrenListJson + "}";

            //Debug.Log(childJson);

            list += childJson + ",";

        }

        list += "]";

        return list;
    }




    public string ConvertSpriteToBase64(Sprite sprite)
    {
        if (sprite == null) return null;

        // Get the texture from the sprite
        Texture2D texture = sprite.texture;

        // Create a readable Texture2D in a compatible format (RGBA32)
        Texture2D readableTexture = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height, TextureFormat.RGBA32, false);

        // Copy the pixels from the original texture to the new readable texture
        Color[] pixels = texture.GetPixels((int)sprite.rect.x, (int)sprite.rect.y, (int)sprite.rect.width, (int)sprite.rect.height);
        readableTexture.SetPixels(pixels);
        readableTexture.Apply();

        // Convert the texture to PNG format (or JPG if preferred)
        byte[] imageData = readableTexture.EncodeToPNG(); // Or EncodeToJPG for JPG format

        // Convert byte array to base64 string
        string base64String = System.Convert.ToBase64String(imageData);

        return base64String;
    }


    List<Sprite> GetAllSpritesFromAnimator(Animator animator)
    {
        List<Sprite> sprites = new List<Sprite>();

        // Get all animation clips from the animator
        AnimationClip[] clips = animator.runtimeAnimatorController.animationClips;

        foreach (AnimationClip clip in clips)
        {
            ObjectReferenceKeyframe[] keyframes = GetSpriteKeyFrames(clip);

            foreach (var keyframe in keyframes)
            {
                Sprite sprite = keyframe.value as Sprite;
                if (sprite != null && !sprites.Contains(sprite))
                {
                    sprites.Add(sprite);
                }
            }
        }

        return sprites;
    }

    ObjectReferenceKeyframe[] GetSpriteKeyFrames(AnimationClip clip)
    {
        // Retrieve all keyframes for each property with Sprite data
        var bindings = AnimationUtility.GetObjectReferenceCurveBindings(clip);
        List<ObjectReferenceKeyframe> keyframes = new List<ObjectReferenceKeyframe>();

        foreach (var binding in bindings)
        {
            if (binding.type == typeof(SpriteRenderer) && binding.propertyName == "m_Sprite")
            {
                var spriteKeyFrames = AnimationUtility.GetObjectReferenceCurve(clip, binding);
                keyframes.AddRange(spriteKeyFrames);
            }
        }

        return keyframes.ToArray();
    }

}
