using log4net;
using System;
using System.Collections.ObjectModel;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Input;
using TSManagementApp.Models;
using TSManagementApp.Properties;
using TSManagementApp.Utils;
using BcAsn1 = Org.BouncyCastle.Asn1;
using BcX509 = Org.BouncyCastle.X509;

namespace TSManagementApp.ViewModels
{
    public class SettingsViewModel : BaseViewModel
    {
        #region Logger
        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        #endregion

        private MainWindowViewModel _vmMainWin;
        public static readonly string qcStatementsOID = "1.3.6.1.5.5.7.1.3";
        public static readonly string qcComplianceOID = "0.4.0.1862.1.1";
        private static bool firstInicialization = true;
        public SettingsViewModel(MainWindowViewModel vmMainWin)
        {
            _vmMainWin = vmMainWin;
            CommandSaveSettings = new CommandGeneric(SaveSettings);
            CommandGoUcAbout = new CommandGeneric(GoUcAbout);
            CommandTsaChooseCertificate = new CommandGeneric(TsaChooseCertificate);
            CommandTsaShowCertificate = new CommandGeneric(TsaShowCertificate);
            
            IndexOfTsaSelectedTimeStampServer = 0;

            InitCollections();
            LoadSettings();
        }

        #region Properties
        
        //General settings
        private bool _ieSettingIsChecked;
        public bool IeSettingIsChecked { get => _ieSettingIsChecked; set { _ieSettingIsChecked = value; OnPropertyChanged("IeSettingIsChecked"); } }
        private bool _proxyIsChecked;
        public bool ProxyIsChecked { get => _proxyIsChecked; set { _proxyIsChecked = value; OnPropertyChanged("ProxyIsChecked"); } }
        private string _proxyServer;
        public string ProxyServer { get => _proxyServer; set { _proxyServer = value; OnPropertyChanged("ProxyServer"); } }
        private string _userName;
        public string UserName { get => _userName; set { _userName = value; OnPropertyChanged("UserName"); } }
        private string _password;
        public string Password { get => _password; set { _password = value; OnPropertyChanged("Password"); } }
        private bool _automaticUpdateIsChecked;
        public bool AutomaticUpdateIsChecked { get => _automaticUpdateIsChecked; set { _automaticUpdateIsChecked = value; OnPropertyChanged("AutomaticUpdateIsChecked"); } }

        //TsaAuthSettings
        private bool _noAuthIsChecked;
        public bool NoAuthIsChecked { get => _noAuthIsChecked; set { _noAuthIsChecked = value; OnPropertyChanged("NoAuthIsChecked"); } }
        private bool _tsaAuthCertIsChecked;
        public bool TsaAuthCertIsChecked { get => _tsaAuthCertIsChecked; set { _tsaAuthCertIsChecked = value; OnPropertyChanged("TsaAuthCertIsChecked"); } }
        private bool _tsaAuthIpIsChecked;
        public bool TsaAuthIpIsChecked { get => _tsaAuthIpIsChecked; set { _tsaAuthIpIsChecked = value; OnPropertyChanged("TsaAuthIpIsChecked"); } }
        private bool _tsaAuthLoginDataIsChecked;
        public bool TsaAuthLoginDataIsChecked { get => _tsaAuthLoginDataIsChecked; set { _tsaAuthLoginDataIsChecked = value; OnPropertyChanged("TsaAuthLoginDataIsChecked"); } }
        X509Certificate2 TsaCert { get; set; }
        private string _tsaCertCn;
        public string TsaCertCn { get => _tsaCertCn; set { _tsaCertCn = value; OnPropertyChanged("TsaCertCn"); } }
        private string _tsaLoginName;
        public string TsaLoginName { get => _tsaLoginName; set { _tsaLoginName = value; OnPropertyChanged("TsaLoginName"); } }
        private string _tsaLoginPassword;
        public string TsaLoginPassword { get => _tsaLoginPassword; set { _tsaLoginPassword = value; OnPropertyChanged("TsaLoginPassword"); } }
        public ObservableCollection<ShaAlgorithmType> TsaShaAlogirthms { get; set; }
        private string _tsaPolitics;
        public string TsaPolitics { get => _tsaPolitics; set { _tsaPolitics = value; OnPropertyChanged("TsaPolitics"); } }
        public ObservableCollection<TimeStampServerModel> TsaTimeStampServers { get; set; }
        private TimeStampServerModel _tsaSelectedTimeStampServer;
        public TimeStampServerModel TsaSelectedTimeStampServer
        {
            get => _tsaSelectedTimeStampServer;
            set
            {
                if (firstInicialization)
                    firstInicialization = false;
                else if (!string.IsNullOrWhiteSpace(value.Url))
                    TsaTSUrl = value.Url;
                _tsaSelectedTimeStampServer = value;
                IndexOfTsaSelectedTimeStampServer = TsaTimeStampServers.IndexOf(_tsaSelectedTimeStampServer);
            }
        }
        private string _tsaTSUrl;
        public string TsaTSUrl { get => _tsaTSUrl; set { _tsaTSUrl = value; OnPropertyChanged("TsaTSUrl"); } }
        public int IndexOfTsaSelectedTimeStampServer { get; set; }

        #endregion

        #region Commands

        public ICommand CommandSaveSettings { get; set; }
        public ICommand CommandGoUcAbout { get; set; }
        public ICommand CommandTsaChooseCertificate { get; set; }
        public ICommand CommandTsaShowCertificate { get; set; }
        public ICommand CommandAtsaChooseCertificate { get; set; }
        public ICommand CommandAtsaShowCertificate { get; set; }

        public void SaveSettings()
        {
            try
            {
                log.Info("Start saving application settings");
                string selectedTsaShaAlgorithm = null;
                foreach(ShaAlgorithmType sha in TsaShaAlogirthms)
                {
                    if (sha.IsChecked)
                        selectedTsaShaAlgorithm = sha.Name;
                }
                Manager.Instance.SettingsManager.SetGeneralSettings(IeSettingIsChecked, ProxyIsChecked, ProxyServer, UserName, Password, AutomaticUpdateIsChecked);
                Manager.Instance.SettingsManager.SetTsaSettings(TsaAuthCertIsChecked, TsaAuthIpIsChecked, TsaAuthLoginDataIsChecked, TsaCert, TsaLoginName, TsaLoginPassword,
                    TsaPolitics, selectedTsaShaAlgorithm, TsaTSUrl, NoAuthIsChecked);

                Manager.Instance.SettingsManager.SerializeSettings();

                Messages.MsgInfo(Resources.SettingsVM_SettingsSaved);
            }
            catch (Exception ex)
            {
                log.Error($"Error while saving settings - {ex.ToString()}");
                throw;
            }
        }

        public void GoUcAbout()
        {
            _vmMainWin.GoUcAbout();
        }

        public void TsaChooseCertificate()
        {
            try
            {
                TsaCert = GetCertifiace();
                TsaCertCn = TsaCert.Subject;
                log.Info($"Tsa auth cert set to {TsaCert.Subject}");
            }
            catch (Exception ex)
            {
                log.Error($"Failed to set certificate for Tsa authentication - {ex.ToString()}");
                Messages.MsgError($"{Resources.SettingsVm_ErrorWhilesettingTsaAuthCert} - {ex.Message}");
            }
        }

        public void TsaShowCertificate()
        {
            try
            {
                if(TsaCert != null)
                    X509Certificate2UI.DisplayCertificate(TsaCert);
            }
            catch (Exception ex)
            {
                Messages.MsgError(Resources.SettingsVM_CantShowTsaAuthCert);
                log.Error($"Error while displaying TSA auth certificate - {ex.ToString()}");
            }
        }

        #endregion

        #region Methods

        private X509Certificate2Collection ReturnValidCertificates(X509Certificate2Collection collection)
        {
            X509Certificate2Collection validCerts = new X509Certificate2Collection();
            foreach (X509Certificate2 cert in collection)
            {
                int pom = DateTime.Compare(cert.NotAfter, DateTime.Now);
                if (pom >= 0)
                    validCerts.Add(cert);
            }

            X509Certificate2Collection withoutQualifiedCerts = new X509Certificate2Collection();
            foreach(X509Certificate2 cert in validCerts)
            {
                bool isQualified = false;
                BcX509.X509Certificate bcCert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(new X509Certificate(cert.RawData));
                
                X509ExtensionCollection extensions = cert.Extensions;
              
                if(extensions != null)
                {
                    foreach(X509Extension ext in extensions)
                    {
                        System.Security.Cryptography.Oid oid = ext.Oid;
                        if(oid.Value == qcStatementsOID)
                        {
                            BcAsn1.DerObjectIdentifier derObject = new BcAsn1.DerObjectIdentifier(oid.Value);
                            var octetString = bcCert.GetExtensionValue(derObject);
                            BcAsn1.X509.X509Extension bcext = new BcAsn1.X509.X509Extension(BcAsn1.DerBoolean.GetInstance(ext.Critical) ,octetString);
                            
                            
                            BcAsn1.X509.Qualified.QCStatement qCStatement = new BcAsn1.X509.Qualified.QCStatement(derObject, bcext.GetParsedValue());
                            string qcStatetmentInfo = qCStatement.StatementInfo.ToString();
                            if (qcStatetmentInfo.Contains(qcComplianceOID))
                                isQualified = true;
                        }
                    }
                }

                if (!isQualified)
                    withoutQualifiedCerts.Add(cert);
            }

            return withoutQualifiedCerts;
        }

        private X509Certificate2 GetCertifiace()
        {
            using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
            {
                store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
                if (store.Certificates != null)
                {
                    X509Certificate2Collection collection = ReturnValidCertificates(store.Certificates);
                    X509Certificate2Collection selectedCert = X509Certificate2UI.SelectFromCollection(collection, Resources.SettingsVM_ChooseCert,
                        Resources.SettingsVM_ChooseAuthCert, X509SelectionFlag.SingleSelection);
                    if (selectedCert.Count == 1)
                        return selectedCert[0];
                    else
                        throw new Exception(Resources.SettingsVM_NoCertChoosed);
                }
                else
                    throw new Exception(Resources.SettingsVM_NoCertsFound);
            }
        }

        private void InitCollections()
        {
            TsaShaAlogirthms = Manager.Instance.SettingsManager.TsaShaAlogirthms;
            TsaTimeStampServers = Manager.Instance.SettingsManager.TsaTimeStampServers;
        }

        private void LoadSettings()
        {
            try
            {
                log.Debug($"Start loading settings in SettingsView from Manager");
                SettingsModel settings = Manager.Instance.SettingsManager.Settings;
                NoAuthIsChecked = settings.TsaSettings.NoAuthIsChecked;
                IeSettingIsChecked = settings.GeneralSettings.IeSettingsIsChecked;
                ProxyIsChecked = settings.GeneralSettings.ProxyIsChecked;
                ProxyServer = settings.GeneralSettings.ProxyServer;
                UserName = settings.GeneralSettings.UserName;
                Password = settings.GeneralSettings.Password;
                AutomaticUpdateIsChecked = settings.GeneralSettings.AutomaticUpdateIsChecked;

                TsaPolitics = settings.TsaSettings.Politics;
                TsaTSUrl = settings.TsaSettings.SelectedTimeStampServer;
                TsaAuthCertIsChecked = settings.TsaSettings.AuthCertIsChecked;
                TsaAuthIpIsChecked = settings.TsaSettings.AuthIpIsChecked;
                TsaAuthLoginDataIsChecked = settings.TsaSettings.AuthLoginDataIsChecked;
                TsaCert = settings.TsaSettings.AuthCert;
                if (TsaCert != null)
                    TsaCertCn = settings.TsaSettings.AuthCert.Subject;
                TsaLoginName = settings.TsaSettings.LoginName;
                TsaLoginPassword = settings.TsaSettings.LoginPassword;
                foreach (ShaAlgorithmType sha in TsaShaAlogirthms)
                {
                    if (sha.Name == settings.TsaSettings.MessageImprintType)
                        sha.IsChecked = true;
                }
            }
            catch (Exception ex)
            {
                log.Error($"Error while loading settings data from Manager - {ex.ToString()}");
                Messages.MsgError($"{Resources.SettingsVM_ErrorWhileLoadingSettings} - {ex.Message}");
            }
        }

        #endregion

    }
}
