using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

namespace IndieExchange
{
    // Created by the SDK, never configured by the developer. This proves continuity of an
    // installation key, not hardware authenticity. Server credit review remains necessary.
    internal static class InstallationKey
    {
        private static RSACryptoServiceProvider key;
        private static string publicKey, directory;
        internal static void Prepare(string root) { directory = root; Ensure(); }
        internal static string PublicKey { get { Ensure(); return publicKey; } }
        internal static string Id {
            get { using (var sha = SHA256.Create()) return BitConverter.ToString(sha.ComputeHash(Encoding.UTF8.GetBytes(PublicKey))).Replace("-", "").ToLowerInvariant(); }
        }
        private static void Ensure()
        {
            if (key != null) return;
            var folder = Path.Combine(directory, "IndieExchange");
            Directory.CreateDirectory(folder);
            var path = Path.Combine(folder, "installation-key.xml");
            var created = new RSACryptoServiceProvider(2048) { PersistKeyInCsp = false };
            try {
                if (File.Exists(path)) created.FromXmlString(File.ReadAllText(path));
                else File.WriteAllText(path, created.ToXmlString(true));
                if (created.KeySize != 2048) throw new CryptographicException();
                publicKey = Convert.ToBase64String(created.ExportParameters(false).Modulus);
                key = created;
            } catch { created.Dispose(); throw; }
        }
        internal static string Sign(string requestHash)
        {
            Ensure();
            var encoded = requestHash.Replace('-', '+').Replace('_', '/');
            encoded = encoded.PadRight((encoded.Length + 3) / 4 * 4, '=');
            var hash = Convert.FromBase64String(encoded);
            if (hash.Length != 32) throw new CryptographicException();
            return Convert.ToBase64String(key.SignHash(hash, CryptoConfig.MapNameToOID("SHA256")));
        }
    }
}
