using System;
using System.IO;
using UnityEditor;

namespace XGame.Editor.Build
{
    [BuildCommand((uint)BuildCommandPriority.EncryptGlobalMetadata)]
    class CmdEncryptGlobalMetadata : BaseBuildCommand, ICommandExecuter
    {
        const string EncryptKey = @"DMMDyUKYp7z3orgK/bIImLojiy6/t3PUjIe6lojNGQVFB59AzSCRz7V7uSMI6DD2+";

        const int Encryptoffset = 8;
        const int EncryptLength = 1024;
        public BuildErrorCode Execute()
        {
            BuildErrorCode rc = BuildErrorCode.CmdCompleted;
            if (Context.config.scriptImpl == ScriptingImplementation.IL2CPP)
            {
                string globalMetadata = GetMetadataPath(Context.config.target);
                try
                {
                    BuildLog.Log($"CmdEncriptGlobalMetadata Encrypt: {globalMetadata}, Exists: {File.Exists(globalMetadata)}");
                    var bytes = File.ReadAllBytes(globalMetadata);
                    Encrypt(bytes);
                    File.WriteAllBytes(globalMetadata, bytes);
                }
                catch (Exception e)
                {
                    BuildLog.Error($"CmdEncriptGlobalMetadata failed! Error: {e.Message}\nStackTrace: {e.StackTrace}");
                    rc = BuildErrorCode.EncryptGlobalMetadataError;
                }
            }
            return rc;
        }

        string GetMetadataPath(BuildTarget target)
        {
            string productName = Context.config.project.productName;
            const string relative = "Data/Managed/Metadata/global-metadata.dat";
            return target switch
            {
                BuildTarget.Android => Path.Combine(Context.appOutputPath, "unityLibrary/src/main/assets/bin", relative),
                BuildTarget.iOS => Path.Combine(Context.appOutputPath, relative),
                BuildTarget.StandaloneWindows => Path.Combine(Directory.GetParent(Context.appOutputPath).ToString(), $"{productName}_Data/il2cpp_data/Metadata/global-metadata.dat"),
                BuildTarget.StandaloneWindows64 => Path.Combine(Directory.GetParent(Context.appOutputPath).ToString(), $"{productName}_Data/il2cpp_data/Metadata/global-metadata.dat"),
                _ => throw new NotImplementedException($"GetMetadataPath fail. target: {target}")
            };
        }

        void Encrypt(byte[] bytes)
        {
            var keybuffer = System.Text.Encoding.UTF8.GetBytes(EncryptKey);
            var len = keybuffer.Length;
            for (int i = Encryptoffset; i < EncryptLength; i++)
                bytes[i] ^= keybuffer[(i - Encryptoffset) % len];
        }
    }
}
