using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace PlanTempus.Core.MultiKeyEncryption
{
    public class SecureConnectionString
    {
        const string _masterKey = "5AFD74B1C26E87FE6656099E850DC67A";

        public class EncryptedData
        {
            public string EncryptedConnectionString { get; set; }
            public Dictionary<string, string> UserMasterKeys { get; set; } = new();
        }

        public EncryptedData EncryptConnectionString(string connectionString)
        {
            var encryptedConnString = EncryptWithKey(connectionString, _masterKey);
            var userKeys = new Dictionary<string, string>();



            return new EncryptedData
            {
                EncryptedConnectionString = encryptedConnString,
                UserMasterKeys = userKeys
            };
        }

        public string AddNewUser(string username, string password)
        {
            var userKey = DeriveKeyFromPassword(password);
            var encryptedMasterKey = EncryptWithKey(_masterKey, userKey);
            return encryptedMasterKey;
        }

        public string Decrypt(string encryptedConnString, string encryptedMasterKey, string password)
        {
            var userKey = DeriveKeyFromPassword(password);
            var masterKey = DecryptWithKey(encryptedMasterKey, userKey);
            return DecryptWithKey(encryptedConnString, masterKey);
        }

        private string DeriveKeyFromPassword(string password)
        {
            using var deriveBytes = new Rfc2898DeriveBytes(
                password,
                new byte[16], // Fast salt for simpelhed - i produktion bør dette være unikt per bruger
                10000,
                HashAlgorithmName.SHA256);

            return Convert.ToBase64String(deriveBytes.GetBytes(32));
        }

        private string EncryptWithKey(string value, string key)
        {
            using var aes = Aes.Create();
            var keyBytes = Convert.FromBase64String(key);
            aes.Key = keyBytes;
            aes.GenerateIV();

            using var encryptor = aes.CreateEncryptor();
            var valueBytes = Encoding.UTF8.GetBytes(value);
            var encrypted = encryptor.TransformFinalBlock(valueBytes, 0, valueBytes.Length);

            var result = new byte[aes.IV.Length + encrypted.Length];
            Array.Copy(aes.IV, 0, result, 0, aes.IV.Length);
            Array.Copy(encrypted, 0, result, aes.IV.Length, encrypted.Length);

            return Convert.ToBase64String(result);
        }

        private string DecryptWithKey(string encryptedValue, string key)
        {
            var encryptedBytes = Convert.FromBase64String(encryptedValue);
            using var aes = Aes.Create();

            var keyBytes = Convert.FromBase64String(key);
            aes.Key = keyBytes;

            var iv = new byte[16];
            Array.Copy(encryptedBytes, 0, iv, 0, iv.Length);
            aes.IV = iv;

            using var decryptor = aes.CreateDecryptor();
            var decrypted = decryptor.TransformFinalBlock(
                encryptedBytes,
                iv.Length,
                encryptedBytes.Length - iv.Length);

            return Encoding.UTF8.GetString(decrypted);
        }
    }
}
