#if !UNITY_WSA || UNITY_EDITOR
using System.Security.Cryptography;
#else
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
#endif
using System;

namespace XLua
{
    public class SignatureLoader
    {
        private LuaEnv.CustomLoader userLoader;
#if !UNITY_WSA || UNITY_EDITOR
        RSACryptoServiceProvider rsa;
        SHA1 sha;
#else
        AsymmetricKeyAlgorithmProvider rsa;
        CryptographicKey key;
#endif

        public SignatureLoader(string publicKey, LuaEnv.CustomLoader loader)
        {
#if !UNITY_WSA || UNITY_EDITOR
            rsa = new RSACryptoServiceProvider();
            rsa.ImportCspBlob(Convert.FromBase64String(publicKey));
            sha = new SHA1CryptoServiceProvider();
#else
            rsa = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaSignPkcs1Sha1);
            key = rsa.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(publicKey), CryptographicPublicKeyBlobType.Capi1PublicKey);
#endif
            userLoader = loader;
        }


        byte[] load_and_verify(ref string filepath)
        {
            byte[] data = userLoader(ref filepath);
            if (data == null)
            {
                return null;
            }
            if (data.Length < 128)
            {
                throw new InvalidProgramException(filepath + " length less than 128!");
            }

            byte[] sig = new byte[128];
            byte[] filecontent = new byte[data.Length - 128];
            Array.Copy(data, sig, 128);
            Array.Copy(data, 128, filecontent, 0, filecontent.Length);

#if !UNITY_WSA || UNITY_EDITOR
            if (!rsa.VerifyData(filecontent, sha, sig))
            {
                throw new InvalidProgramException(filepath + " has invalid signature!");
            }
#else
            if (!CryptographicEngine.VerifySignature(key, CryptographicBuffer.CreateFromByteArray(filecontent), CryptographicBuffer.CreateFromByteArray(sig)))
            {
                throw new InvalidProgramException(filepath + " has invalid signature!");
            }
#endif
            return filecontent;
        }


        public static implicit operator LuaEnv.CustomLoader(SignatureLoader signatureLoader)
        {
            return signatureLoader.load_and_verify;
        }
    }
}