using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using Grpc.Core;
using Rpcscanning;
using RpcScannerServer;
using System.Runtime.InteropServices;
using System.Configuration;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;

namespace ScanningRpcService
{
    static class Program
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        private const int SW_HIDE = 0;
        private const int SW_SHOW = 5;

        private static readonly NativeWindowsActivateFocusHelper _nativeWindowsActivateFocusHelper = new NativeWindowsActivateFocusHelper();
        
        
        
        static void Main(string[] args)
        {
            Console.WriteLine("Starting rpc service");
            bool.TryParse(ConfigurationManager.AppSettings.Get("ShowConsole"), out var showConsole);
            if (!showConsole)
            {
                HideConsoleWindow();
            }

            _nativeWindowsActivateFocusHelper.StartListening();
            var _rpcServer = new Server
            {
                Services = { RpcScanner.BindService(new RpcScannerServerImplementation()) },
                Ports = { new ServerPort("localhost", 50051, GetWindowsCertificateStoreCredentials()) }
            };
            _rpcServer.Start();
            Console.ReadKey();
            _rpcServer.ShutdownAsync().Wait();
        }

        private static ServerCredentials GetWindowsCertificateStoreCredentials()
        {
            X509Store store = new X509Store(StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2 cert = null;
            foreach (var certificate in store.Certificates)
            {
                if (certificate.HasPrivateKey && certificate.FriendlyName.Equals("EVA Skanning RPC Server", StringComparison.InvariantCultureIgnoreCase))
                {
                    cert = certificate;
                    break;
                }
            }

            var privateKey = ExportPrivateKeyToPem(cert);
            var publicKey = ExportPublicKeyToPem(cert);
            var certificates = new List<KeyCertificatePair>();
            certificates.Add(new KeyCertificatePair(publicKey, privateKey));
            return new SslServerCredentials(certificates,GetRootCertificates(), true);
        }


        private static string ExportPublicKeyToPem(X509Certificate2 cert)
        {
            StringBuilder builder = new StringBuilder();

            builder.AppendLine("-----BEGIN CERTIFICATE-----");
            builder.AppendLine(Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
            builder.AppendLine("-----END CERTIFICATE-----");

            return builder.ToString();
        }

        private static string ExportPrivateKeyToPem(X509Certificate2 cert)
        {
            var pkey = (RSACryptoServiceProvider)cert.PrivateKey;
            var keyPair = DotNetUtilities.GetRsaKeyPair(pkey);
            StringBuilder builder = new StringBuilder();

            var memoryStream = new MemoryStream();
            using (TextWriter tw = new StreamWriter(memoryStream))
            {
                PemWriter pw = new PemWriter(tw);
                pw.WriteObject(keyPair.Private);
                tw.Flush();
            }

            return Encoding.ASCII.GetString(memoryStream.ToArray());
        }


        public static string GetRootCertificates()
        {
            StringBuilder builder = new StringBuilder();
            X509Store store = new X509Store(StoreName.Root);
            store.Open(OpenFlags.ReadOnly);
            foreach (X509Certificate2 mCert in store.Certificates)
            {
                builder.AppendLine(
                    "# Issuer: " + mCert.Issuer.ToString() + "\n" +
                    "# Subject: " + mCert.Subject.ToString() + "\n" +
                    "# Label: " + mCert.FriendlyName.ToString() + "\n" +
                    "# Serial: " + mCert.SerialNumber.ToString() + "\n" +
                    "# SHA1 Fingerprint: " + mCert.GetCertHashString().ToString() + "\n" +
                    ExportPublicKeyToPem(mCert) + "\n");
            }
            return builder.ToString();
        }

        private static void HideConsoleWindow()
        {
            var handle = GetConsoleWindow();
            ShowWindow(handle, SW_HIDE);
        }
    }
}

