using System;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using SdaWSCryptoClient.Keys;

namespace MOH_CRA_XCRMS_Service.Common
{
    public class KeyExchange
    {
        ECKey ecKey;

        internal ECPublicKey GeneratedPublicKey { get; private set; }

        internal ECPublicKey ReceivedPublicKey { get; private set; }

        internal long KeyId { get; set; }

        /// <summary>
        /// Generates new private-public keypair. Public key will be sent to provider during key exchange. Private key will be used to calculate symetric encryption key
        /// </summary>
        internal void GenerateKeyPair()
        {
            ecKey = new ECKey();

            GeneratedPublicKey = new ECPublicKey()
            {
                X = ecKey.X,
                Y = ecKey.Y,
                CurveOId = ecKey.CurveOId
            };
        }

        /// <summary>
        /// Calculates symetric encryption key with generate keypair's private key and public key received by key exchange. Key should be stored in order to use it for encryption and decryption until next key exchange (persumably once per day)
        /// </summary>
        /// <returns></returns>
        internal byte[] CalculateSecureSymetricKey()
        {
            return ecKey.GenerateKeyAgreement(ReceivedPublicKey.X, ReceivedPublicKey.Y);
        }

        /// <summary>
        /// Builds key exchange request xml with generated keypair's public key and calls key exchange subcontract to receive providers public key
        /// </summary>
        /// <param name="subcontractId">Key exchange subcontractId given by service provider</param>
        /// <param name="signingCert">Signing certificate</param>
        internal void PerformExchange(string subcontractId, X509Certificate2 signingCert)
        {
            if (GeneratedPublicKey == null)
                GenerateKeyPair();

            XmlDocument publicKeyXml = GeneratedPublicKey.ToXml();
            ((XmlElement)publicKeyXml.FirstChild).SignXml(signingCert, Guid.NewGuid());

            XmlElement requestNode = Helpers.ComposeRequestXmlWithParamObjects(subcontractId, publicKeyXml);

            string keyExchangeResponse = CallApi.GetResponse(requestNode.OuterXml);
            try
            {
                var resultStatus = Helpers.GetResponseStatus(keyExchangeResponse);

                if (resultStatus.Code != "14")
                    throw new Exception(resultStatus.Code + "-" + resultStatus.Message);

                ReceivedPublicKey = new ECPublicKey();
                ReceivedPublicKey.LoadXml(keyExchangeResponse);

                KeyId = ReceivedPublicKey.Id;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Get stored encryption key calculated after last key exchange. 
        /// Key will be used for request part encryption and response decryption until next key exchange (persumably once per day)
        /// </summary>
        /// <returns></returns>
        internal byte[] GetCurrentEncryptionKey()
        {
            KeyId = 0;
            return null;
        }

        public byte[] GetCurrentEncryptionKey(string keyExchangeSubcontractId)
        {
            KeyId = 0;
            return null;
        }
    }
}
