using CryptoPro.Security.Cryptography.X509Certificates;
using Hcs.Broker.Api;
using Hcs.Broker.Internal;
using Hcs.Broker.Logger;
using Hcs.Broker.MessageCapturer;
using System.Security;
using System.Security.Cryptography.X509Certificates;

namespace Hcs.Broker
{
    /// <inheritdoc cref="IClient"/>
    public class Client : IClient
    {
        /// <inheritdoc cref="IClient"/>
        public string OrgPPAGUID { get; set; }

        /// <inheritdoc cref="IClient"/>
        public string ExecutorGUID { get; set; }

        /// <inheritdoc cref="IClient"/>
        public bool UseTunnel { get; set; }

        /// <inheritdoc cref="IClient"/>
        public bool IsPPAK { get; set; }

        /// <inheritdoc cref="IClient"/>
        public OrganizationRole Role { get; set; }

        /// <inheritdoc cref="IClient"/>
        public ILogger Logger { get; set; }

        /// <inheritdoc cref="IClient"/>
        public IMessageCapturer MessageCapturer { get; set; }

        public IBillsApi Bills => new BillsApi(this);

        public IDeviceMeteringApi DeviceMetering => new DeviceMeteringApi(this);

        public IHouseManagementApi HouseManagement => new HouseManagementApi(this);

        public INsiApi Nsi => new NsiApi(this);

        public INsiCommonApi NsiCommon => new NsiCommonApi(this);

        public IOrgRegistryCommonApi OrgRegistryCommon => new OrgRegistryCommonApi(this);

        public IPaymentsApi Payments => new PaymentsApi(this);

        /// <summary>
        /// Сертификат клиента для применения при формировании запросов
        /// </summary>
        internal CpX509Certificate2 Certificate { get; private set; }

        internal SecureString CertificatePin { get; private set; }

        public Client()
        {
            AppContext.SetSwitch("Switch.CryptoPro.DotNet.AllowExperimental", true);
        }

        public void SetSigningCertificate(string serialNumber, string? pin = null)
        {
            using var store = new CpX509Store(StoreName.My, StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

            var cert = store.Certificates.Find(X509FindType.FindBySerialNumber, serialNumber, false)[0];
            Certificate = cert ?? throw new ArgumentNullException("Certificate not found");

            pin ??= Constants.DEFAULT_CERTIFICATE_PIN;

            CertificatePin = new SecureString();
            foreach (var character in pin)
            {
                CertificatePin.AppendChar(character);
            }
        }

        internal string ComposeEndpointUri(string endpointName)
        {
            if (UseTunnel)
            {
                return $"http://{Constants.URI_TUNNEL}/{endpointName}";
            }

            return IsPPAK
                ? $"https://{Constants.URI_PPAK}/{endpointName}"
                : $"https://{Constants.URI_SIT_02}/{endpointName}";
        }

        /// <summary>
        /// Пробует вывести сообщение в установленный приемник отладочных сообщений
        /// </summary>
        internal void TryLog(string message)
        {
            Logger?.WriteLine(message);
        }

        /// <summary>
        /// Пробует отправить тело сообщения в установленный перехватчик
        /// </summary>
        internal void TryCaptureMessage(bool sent, string messageBody)
        {
            MessageCapturer?.CaptureMessage(sent, messageBody);
        }
    }
}
