//============= Copyright (c) Ludic GmbH, All rights reserved. ==============
//
// Purpose: Part of the My Behaviour Tree Code
//
//=============================================================================

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

namespace MyBT {
    [System.Serializable]
    public class FileHash {
        [SerializeField]
        private List<string> hashCache;

        public bool debugLog = false;

        public void UpdateHashCache (FileHash compareFileHash) {
            hashCache = compareFileHash.GetCurrentHashCache();
        }

        public void UpdateHashCache (List<string> newHashCache) {
            if (debugLog) Debug.Log("UpdateHashCache");
            hashCache = newHashCache;
        }

        public void UpdateHashCacheFromTextAsset (List<UnityEngine.TextAsset> textAssets) {
            UpdateHashCache(TextAssetHash(textAssets));
            // Debug.LogError("FileHash.UpdateHashCacheFromTextAsset: " + this);
        }

        public void ClearHashCache () {
            if (debugLog) Debug.Log("ClearHashCache");
            hashCache = null;
        }

        public List<string> GetCurrentHashCache () {
            return hashCache;
        }

        public bool HashChanged (FileHash compareFileHash, bool allowNull = true) {
            bool changed = HashChanged(compareFileHash.GetCurrentHashCache(), allowNull);
            if (debugLog) Debug.Log("CheckGenerationOutdated:\tThis Hash:\t" + this + " \n"+
                                            "\t\t\tCompared Hash:\t" + compareFileHash);
            return changed;
        }

        // public bool HashChangedAndNotNull (FileHash compareFileHash) {
        //     bool changed = HashChanged(compareFileHash.GetCurrentHashCache(), false);
        //     if (debugLog) Debug.Log("CheckGenerationOutdated:\tThis Hash:\t" + this + " \n"+
        //                                     "\t\t\tCompared Hash:\t" + compareFileHash);
        //     return changed;
        // }

        public bool HashChanged (List<string> compareHashes, bool allowNull = true) {
            if (!allowNull && ((compareHashes == null) || (hashCache == null))) {
                return true;
            }

            if (compareHashes == hashCache) {
                return false;
            }

            if ((compareHashes != null) && (hashCache != null) && (compareHashes.Count == hashCache.Count)) {
                bool anyChanged = false;
                for (int i=0; i<compareHashes.Count; i++) {
                    if ((i < compareHashes.Count) && (i < hashCache.Count)) {
                        bool differ = (compareHashes[i] != hashCache[i]);
                        // if (debugLog) Debug.Log("BtFileHashChanged: bt script "+i+" changed "+differ);
                        anyChanged |= differ;
                    }
                }
                if (debugLog)
                    Debug.Log("BtFileHashChanged: some hash differ: " + this + " " + ((compareHashes!=null)?string.Join(", ", compareHashes.Select(g=>g)):"null"));
                return anyChanged;
            }
            else {
                if (debugLog)
                    Debug.Log("BtFileHashChanged: hash length changed, or null: compareHashes=" + 
                        (compareHashes!=null?compareHashes.Count.ToString():"null") + " btFileHashCache=" + 
                        (hashCache!=null?hashCache.Count.ToString():"null"));
            }
            return true;
        }

        public bool HashChangedFromTextAsset (List<UnityEngine.TextAsset> textAssets) {
            return HashChanged(TextAssetHash(textAssets));
        }

        /// <summary>
        /// return list of hashes generated from textassets
        /// </summary>
        public List<string> TextAssetHash (List<UnityEngine.TextAsset> textAssets) {
            List<string> fileHashes = new List<string>(); //[taskScripts.Count];
            for (int i=0; i<textAssets.Count; i++) {
                TextAsset txt = textAssets[i];
                if (txt!= null) {
                    fileHashes.Add(GetHash(txt.text));
                }
                else {
                    fileHashes.Add(null);
                }
                // Resources.UnloadAsset(txt);
            }
            if (debugLog) Debug.Log("TextAssetHash: generated hashes "+string.Join(", ", fileHashes.Select(f=>f)));
            return fileHashes;
        }

        /// <summary>
        /// create a hash from a string
        /// </summary>
        private string GetHash(string usedString) {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            //byte[] bytes = Encoding.ASCII.GetBytes(usedString+secretKey);     // this wrong because can't receive korean character
            byte[] bytes = Encoding.UTF8.GetBytes(usedString); //  + secretKey
            byte[] hash = md5.ComputeHash(bytes);

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hash.Length; i++) {
                sb.Append(hash[i].ToString("x2"));
            }
            return sb.ToString();
        }

        public override string ToString() {
            return ((hashCache!=null)?string.Join(", ", hashCache.Select(g=>g)):"null");
        }
    }
}