﻿using System;
using System.Security.Cryptography;
using System.Text;

namespace RKOKO.Config.Free
{
    public static class RkokoAesUtility
    {
        private const string Prefix = "RKOKO_AES_V1";

        public static bool IsEncryptedText(string text)
        {
            return !string.IsNullOrEmpty(text) &&
                   text.StartsWith(Prefix + ":", StringComparison.Ordinal);
        }

        public static string EncryptString(string plainText, string key)
        {
            if (plainText == null)
                throw new ArgumentNullException("plainText");

            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentException("key cannot be null or empty.", "key");

            byte[] keyBytes = BuildAesKey(key);
            byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);

            using (Aes aes = Aes.Create())
            {
                aes.Key = keyBytes;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                aes.GenerateIV();

                using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
                {
                    byte[] cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);

                    string ivBase64 = Convert.ToBase64String(aes.IV);
                    string cipherBase64 = Convert.ToBase64String(cipherBytes);

                    return Prefix + ":" + ivBase64 + ":" + cipherBase64;
                }
            }
        }

        public static string DecryptString(string encryptedText, string key)
        {
            if (encryptedText == null)
                throw new ArgumentNullException("encryptedText");

            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentException("key cannot be null or empty.", "key");

            string[] parts = encryptedText.Split(':');
            if (parts.Length != 3 || !string.Equals(parts[0], Prefix, StringComparison.Ordinal))
                throw new FormatException("Invalid encrypted text format.");

            byte[] ivBytes = Convert.FromBase64String(parts[1]);
            byte[] cipherBytes = Convert.FromBase64String(parts[2]);
            byte[] keyBytes = BuildAesKey(key);

            using (Aes aes = Aes.Create())
            {
                aes.Key = keyBytes;
                aes.IV = ivBytes;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;

                using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
                {
                    byte[] plainBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
                    return Encoding.UTF8.GetString(plainBytes);
                }
            }
        }

        public static string GenerateRandomKey(int byteCount)
        {
            if (byteCount <= 0)
                throw new ArgumentOutOfRangeException("byteCount");

            byte[] bytes = new byte[byteCount];
            using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(bytes);
            }

            return Convert.ToBase64String(bytes);
        }

        public static string GenerateRandomKey()
        {
            return GenerateRandomKey(32);
        }

        private static byte[] BuildAesKey(string key)
        {
            byte[] inputBytes = Encoding.UTF8.GetBytes(key);

            using (SHA256 sha256 = SHA256.Create())
            {
                return sha256.ComputeHash(inputBytes);
            }
        }
    }
}