using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Npgsql;
using NpgsqlTypes;
using System.Data;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Configuration;
using System.Xml;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using LAPS_WATCHER.App_Data;
using RequestService.ServiceController;
using LAPS_WATCHER.Configure;
using Dapper;
using LAPS_WATCHER.Models;
using SimpleImpersonation;
using LAPS_IOService.Models;

namespace LAPS_WATCHER
{
    public class ServerInfo
    {
        private string connstring = string.Empty;
        private NpgsqlConnection conn = new NpgsqlConnection();
        protected string query { get; set; }

        public ServerInfo()
        {
            this.connstring = GetConfigValue();
            //this.connstring = String.Format("Server={0}; User Id={1}; Database={2}; Port={3}; Password={4}; SSL Mode=Prefer; Trust Server Certificate=true", "172.16.1.99", "postgres", "livewms", "5432", "ssg@1234");
            this.conn = new NpgsqlConnection(connstring);
        }
        public static string connStrings { get; set; }
        public static string username { get; set; }
        public static string password { get; set; }
        public static string domain { get; set; }
        public static string ipaddress { get; set; }
        private string GetConfigValue()
        {
            string convalue = string.Empty;
            try
            {
                // convalue = System.Configuration.ConfigurationSettings.AppSettings["postprovide"].ToString();
                convalue = CustomConfiguration.AppSettings.GetValue<string>(Global.Enviroinment);

                // convalue = Program.Enviroinment;
                /*var executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
                var location = executingAssembly.Location;
                string configfile = System.Text.RegularExpressions.Regex.Replace(location, ".([a-z]+)$", ".config", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                XmlDocument doc = new XmlDocument();
                doc.Load(configfile);
                XmlNode addnode = doc.SelectSingleNode("//appSettings/add");
                convalue = addnode.Attributes["value"].Value;
                doc = null;*/
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
            return convalue;
        }

         
        /// To insert the newly added role information
        public int addlog(object data, string mastername)
        {
            using (IDbConnection dbConnection = ConnectionBase.Connection)
            {
                dbConnection.Open();
                string input = JsonConvert.SerializeObject(data);
                int result = 0;
                string query = @"public.sp" + mastername;
                var param = new DynamicParameters();
                param.Add("inputjsonstr", dbType: DbType.String, value: input, direction: ParameterDirection.Input);
                param.Add("mode_p", dbType: DbType.String, value: "insert", direction: ParameterDirection.Input);
                result = dbConnection.Query<int>(query, param, commandType: CommandType.StoredProcedure).First();
                return result;
            }
        }
       
        public DataTable GetDataTable(string funname, List<NpgsqlParameter> paramet)
        {
            NpgsqlConnection postgrescon = new NpgsqlConnection(CustomConfiguration.AppSettings["DBInfo:" + eGlob.Environment]);
            DataTable dtable = new DataTable();
            try
            {
                NpgsqlCommand cmd = new NpgsqlCommand(funname, postgrescon);
                if (paramet != null)
                {
                    foreach (NpgsqlParameter sqlpara in paramet)
                        cmd.Parameters.Add(sqlpara);
                    cmd.CommandType = CommandType.StoredProcedure;
                }
                else
                {
                    cmd.CommandType = CommandType.Text;
                }
                NpgsqlDataAdapter adp = new NpgsqlDataAdapter(cmd);
                adp.Fill(dtable);
                postgrescon.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("ServerInfo:GetDataTable:funname"+ funname);
                Console.WriteLine(ex.StackTrace);
                postgrescon.Close();
            }
            return dtable;
        }
        private List<NpgsqlParameter> GetNpgsqlParameter(string transid, int lotid, string process)
        {
            List<NpgsqlParameter> parametr = new List<NpgsqlParameter>();
            parametr.Add(new NpgsqlParameter { ParameterName = "p_tranid", NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Integer, Value = transid });
            parametr.Add(new NpgsqlParameter { ParameterName = "p_lotid", NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Integer, Value = lotid });
            parametr.Add(new NpgsqlParameter { ParameterName = "p_option", NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Varchar, Value = process });
            return parametr;
        }
        private List<NpgsqlParameter> GetNpgsqlParameter(int transid, int lotid, string process, string ostype)
        {
            List<NpgsqlParameter> parametr = new List<NpgsqlParameter>();
            parametr.Add(new NpgsqlParameter { ParameterName = "p_tranid", NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Integer, Value = transid });
            parametr.Add(new NpgsqlParameter { ParameterName = "p_lotid", NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Integer, Value = lotid });
            parametr.Add(new NpgsqlParameter { ParameterName = "p_option", NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Varchar, Value = process });
            parametr.Add(new NpgsqlParameter { ParameterName = "p_ostype", NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Varchar, Value = ostype });
            return parametr;
        }
        private string GetPath(string sqlquery)
        {
            string serverpath = string.Empty;

            try
            {
                DataSet ds = GetDataSet(sqlquery);
                if (ds.Tables.Count > 0)
                {
                    return FormatPath(ds.Tables[0].Rows[0]["serverpath"].ToString());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
            return serverpath;
        }

        public DataSet GetDataSet(string query)
        {
            DataSet ds = new DataSet();

            try
            {
                NpgsqlCommand cmd = conn.CreateCommand();
                NpgsqlDataAdapter da = new NpgsqlDataAdapter();
                cmd.CommandText = query;
                da.SelectCommand = cmd;
                conn.Open();
                da.Fill(ds);
                conn.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
            return ds;
        }

        public string GetServerPath(string transactionid, string mode, bool createdir = false)
        {
            string serverpath = string.Empty;
            try
            {
                using (IDbConnection dbConnection = ConnectionBase.Connection)
                {
                    bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                    if (isWindows)
                    {
                        dbConnection.Open();
                        var param = new DynamicParameters();
                        const string query = @"public.spusrserverpathinfo";
                        param.Add("p_tranid", dbType: DbType.Int32, value: Convert.ToInt32(transactionid), direction: ParameterDirection.Input);
                        param.Add("p_lotid", dbType: DbType.Int32, value: null, direction: ParameterDirection.Input);
                        param.Add("p_option", dbType: DbType.String, value: mode, direction: ParameterDirection.Input);
                        param.Add("p_ostype", dbType: DbType.String, value: "Windows", direction: ParameterDirection.Input);
                        IEnumerable<servermasterModel> sm = dbConnection.Query<servermasterModel>(query, param, commandType: CommandType.StoredProcedure);
                        if (createdir)
                        {
                            serverpath = FormatPath(sm.First().serverpath.ToString());
                            Directory.CreateDirectory(Path.Combine(serverpath, "IN"));
                            Directory.CreateDirectory(Path.Combine(serverpath, "OUT"));
                        }
                        else
                        {
                            serverpath = FormatPath(sm.First().serverpath.ToString());
                        }
                    }
                    else
                    {
                        dbConnection.Open();
                        var param = new DynamicParameters();
                        const string query = @"public.spusrserverpathinfo";
                        param.Add("p_tranid", dbType: DbType.Int32, value: Convert.ToInt32(transactionid), direction: ParameterDirection.Input);
                        param.Add("p_lotid", dbType: DbType.Int32, value: null, direction: ParameterDirection.Input);
                        param.Add("p_option", dbType: DbType.String, value: mode, direction: ParameterDirection.Input);
                        param.Add("p_ostype", dbType: DbType.String, value: "Linux", direction: ParameterDirection.Input);
                        IEnumerable<servermasterModel> sm = dbConnection.Query<servermasterModel>(query, param, commandType: CommandType.StoredProcedure);
                        if (createdir)
                        {
                            serverpath = sm.First().serverpath.ToString();
                            Directory.CreateDirectory(Path.Combine(serverpath, "IN"));
                            Directory.CreateDirectory(Path.Combine(serverpath, "OUT"));
                        }
                        else
                        {
                            serverpath = sm.First().serverpath.ToString();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
                return serverpath;
            }
            return serverpath;
        }

       
        //public string GetServerPath(int transactionid, bool createdir = false, string serverinfo = "")
        //{
        //    string serverpath = string.Empty; string ostype = "Windows";
        //    try
        //    {
        //        bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
        //        if (isWindows)
        //        {
        //            ostype = "Windows";
        //        }
        //        else
        //        {
        //            ostype = "Linux";
        //        }
        //        DataTable ds = new DataTable();
        //        //if (serverinfo.Equals("serverinfo_cum"))
        //        //    ds = GetDataTable("usr_server_path_info", GetNpgsqlParameter(transactionid, serverinfo));
        //        //else
        //        ds = GetDataTable("spusrserverpathinfo", GetNpgsqlParameter(transactionid, 0, serverinfo, ostype));
        //        serverpath = FormatPath(ds.Rows[0]["serverpath"].ToString());
        //        if (createdir)
        //        {
        //            if (ds.Rows.Count > 0)
        //            {
        //                username = ds.Rows[0]["username"].ToString();
        //                password = ds.Rows[0]["password"].ToString();
        //                domain = ds.Rows[0]["domain"].ToString();
        //                ipaddress = ds.Rows[0]["ipaddress"].ToString();
        //                serverpath = FormatPath(ds.Rows[0]["serverpath"].ToString());
        //                string server_inpath = Path.Combine(serverpath, "IN");
        //                string server_outpath = Path.Combine(serverpath, "OUT");
        //                if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(domain) && !string.IsNullOrEmpty(ipaddress))
        //                {
        //                    var credentials = new UserCredentials(domain, username, password);
        //                    var logonType = LogonType.NewCredentials;
        //                    Impersonation.RunAsUser(credentials, logonType, () =>
        //                    {
        //                        Directory.CreateDirectory(server_inpath);
        //                        Directory.CreateDirectory(server_outpath);
        //                    });
        //                }
        //                else
        //                {
        //                    string retinfo = GrantFolderPermissions(transactionid.ToString(), null);
        //                    var credentials = new UserCredentials(retinfo.Split(',')[0], retinfo.Split(',')[1], retinfo.Split(',')[2]);
        //                    var logonType = LogonType.NewCredentials;
        //                    Impersonation.RunAsUser(credentials, logonType, () =>
        //                    {
        //                        Directory.CreateDirectory(server_inpath);
        //                        Directory.CreateDirectory(server_outpath);
        //                    });
        //                }
        //            }
        //        }
        //        else
        //        {
        //            serverpath = FormatPath(ds.Rows[0]["serverpath"].ToString());
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        Console.WriteLine(ex.StackTrace);
        //        return serverpath;
        //    }
        //    return serverpath;
        //}
        //public string GetServerPath_V2(int transactionid, bool createdir = false, string serverinfo = "")
        //{
        //    string serverpath = string.Empty; string ostype = "Windows";
        //    try
        //    {
        //        bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
        //        if (isWindows)
        //        {
        //            ostype = "Windows";
        //        }
        //        else
        //        {
        //            ostype = "Linux";
        //        }
        //        DataTable ds = new DataTable();
        //        //if (serverinfo.Equals("serverinfo_cum"))
        //        //    ds = GetDataTable("spusrserverpathinfo", GetNpgsqlParameter(transactionid, serverinfo));
        //        //else
        //        //    ds = GetDataTable("spusrserverpathinfo", GetNpgsqlParameter(transactionid, 0, serverinfo));
        //        ds = GetDataTable("spusrserverpathinfo", GetNpgsqlParameter(transactionid, 0, serverinfo, ostype));
        //        serverpath = FormatPath(ds.Rows[0]["serverpath"].ToString());
        //        if (createdir)
        //        {
        //            if (ds.Rows.Count > 0)
        //            {
        //                username = ds.Rows[0]["username"].ToString();
        //                password = ds.Rows[0]["password"].ToString();
        //                domain = ds.Rows[0]["domain"].ToString();
        //                ipaddress = ds.Rows[0]["ipaddress"].ToString();
        //                serverpath = FormatPath(ds.Rows[0]["serverpath"].ToString());
        //                string server_inpath = Path.Combine(serverpath, "IN");
        //                string server_outpath = Path.Combine(serverpath, "OUT");
        //                if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(domain) && !string.IsNullOrEmpty(ipaddress))
        //                {
        //                    var credentials = new UserCredentials(domain, username, password);
        //                    var logonType = LogonType.NewCredentials;
        //                    Impersonation.RunAsUser(credentials, logonType, () =>
        //                    {
        //                        Directory.CreateDirectory(server_inpath);
        //                        Directory.CreateDirectory(server_outpath);
        //                    });
        //                }
        //                else
        //                {
        //                    string retinfo = GrantFolderPermissions(transactionid.ToString(), null);
        //                    var credentials = new UserCredentials(retinfo.Split(',')[0], retinfo.Split(',')[1], retinfo.Split(',')[2]);
        //                    var logonType = LogonType.NewCredentials;
        //                    Impersonation.RunAsUser(credentials, logonType, () =>
        //                    {
        //                        Directory.CreateDirectory(server_inpath);
        //                        Directory.CreateDirectory(server_outpath);
        //                    });
        //                }
        //            }
        //        }
        //        else
        //        {
        //            serverpath = FormatPath(ds.Rows[0]["serverpath"].ToString());
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        Console.WriteLine(ex.StackTrace);
        //        return serverpath;
        //    }
        //    return serverpath;
        //}
        public string GrantFolderPermissions(string transactionid, string lotid = null)
        {
            string ostype = "Windows";
            bool isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
            if (isWindows)
            {
                ostype = "Windows";
            }
            else
            {
                ostype = "Linux";
            }
            if (string.IsNullOrEmpty(transactionid))
            {
                username = CustomConfiguration.AppSettings["username"];
                password = CustomConfiguration.AppSettings["password"];
                domain = CustomConfiguration.AppSettings["domain"];
                return string.Concat(domain, ",", username, ",", password);
            }
            else
            {
                DataTable ds = null;
                if (!string.IsNullOrEmpty(transactionid))
                    ds = GetDataTable("spusrserverpathinfo", GetNpgsqlParameter(Convert.ToInt32(transactionid), 0, "logininfo", ostype));
                else if (!string.IsNullOrEmpty(lotid))
                    ds = GetDataTable("spusrserverpathinfo", GetNpgsqlParameter(0, Convert.ToInt32(lotid), "loginlotinfo", ostype));
                if (ds.Rows.Count > 0)
                {
                    return string.Concat(ds.Rows[0]["domain"].ToString(), ",", ds.Rows[0]["username"].ToString(), ",", ds.Rows[0]["password"].ToString());
                }
                else
                {
                    username = CustomConfiguration.AppSettings["username"];
                    password = CustomConfiguration.AppSettings["password"];
                    domain = CustomConfiguration.AppSettings["domain"];
                    return string.Concat(domain, ",", username, ",", password);
                }
            }
        }
        private static string FormatPath(string inputpath)
        {
            try
            {
                inputpath = inputpath.Replace("/", "\\");
                inputpath = inputpath.Replace("\\\\", "");
                inputpath = System.Text.RegularExpressions.Regex.Replace(inputpath, @"\\\\", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase);

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
            return string.Concat("\\\\", inputpath);
        }

        public class GrantFolderPermission : IDisposable
        {
            ServerInfo info = new ServerInfo();
            private bool id;
            Impartunate impartunate = null;

            public GrantFolderPermission(string transactionid)
            {

                var data = new
                {
                    transactionid = transactionid,
                    lotid = 0,
                    option = "logininfo"
                };

                string inputstr = JsonConvert.SerializeObject(data);
                var ds = CommonRepository.getfilesavelocation("spusrserverpathinfo", inputstr);
                // var ds = CommonRepository.ExecuteSP_ReturnListForLot("spusrserverpathinfo", inputstr, "logininfo");

                // DataSet ds = info.GetDataTable("usr_server_path_info", info.GetNpgsqlParameter(transactionid, 0, "logininfo"));

                /*string query = @"select  lt.transactionid, sm.ipaddress, sm.username, sm.password, sm.domain  from lot_transaction as lt 
                                Left join lot_master lm on lt.lotid=lm.lotid 
                                left join job_master jm on lm.jobid = jm.jobid
                                left join project_definition pd on jm.projectdefinitionid = pd.projectdefinitionid
                                left join server_master sm on pd.fileserver = sm.serverid where lt.transactionid = '" + transid + "'";*/

                //using (DataSet ds = info.GetDataSet(query))
                //{
                if (ds != null)
                {
                    string username = ds.username;
                    string password = ds.password;
                    string domain = ds.domain;
                    impartunate = new Impartunate(username, password, domain);
                    impartunate.AllowAccesstoServer();
                }
                //}
            }

            public void Dispose()
            {
                if (id == true)
                    return;
                impartunate.RemoveServerAccess();
                impartunate = null;
                id = true;
                GC.SuppressFinalize(this);
            }
        }

        class Impartunate
        {
            #region Impersonating User

            #region Impersonation
            static IntPtr tokenHandle;
            // static WindowsImpersonationContext impersonatedUser;
            private string impersUsername { get; set; }
            private string impersPwd { get; set; }
            private string impersDomain { get; set; }
            static WindowsIdentity newId;
            #endregion

            public Impartunate(string username, string password, string domain)
            {
                impersUsername = username;
                impersPwd = password;
                impersDomain = domain;
            }


            //   public static WindowsImpersonationContext oImpersonatedUser;
            [DllImport("advapi32.dll", SetLastError = true)]
            private static extern bool LogonUser(string sUsername, string sDomain, string sPassword, int iLogonType, int iLogonProvider, ref IntPtr oToken);

            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool CloseHandle(IntPtr oHandle);

            public bool AllowAccesstoServer()
            {
                try
                {
                    tokenHandle = IntPtr.Zero;
                    bool Result = LogonUser(impersUsername, impersDomain, impersPwd, 2, 0, ref tokenHandle);
                    if (Result)
                    {
                        newId = new WindowsIdentity(tokenHandle);
                        //  impersonatedUser = newId.Impersonate();
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                catch (Exception ex) { Console.WriteLine(ex.Message.ToString()); return false; }
            }

            public void RemoveServerAccess()
            {
                try
                {
                    //if (impersonatedUser != null)
                    //{
                    //    impersonatedUser.Undo();
                    //}
                    if (tokenHandle != IntPtr.Zero)
                    {
                        CloseHandle(tokenHandle);
                    }
                }
                catch (Exception ex) { Console.WriteLine(ex.Message.ToString()); }
            }

            private void ImpersonateUser()
            {
                //System.IO.FileInfo localFileLastModified;
                //System.IO.FileInfo serverFileLastModified;
                if (AllowAccesstoServer())
                {
                    RemoveServerAccess();
                }
            }

            #endregion
        }
    }
}
