using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace LAPS_XMLQC_Service.App_Data
{
    public class Impartunate : IDisposable
    {
        private IntPtr tokenHandle;
        private WindowsIdentity newId;

        private readonly string impersUsername;
        private readonly string impersPwd;
        private readonly string impersDomain;

        [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 Impartunate(string username, string password, string domain)
        {
            impersUsername = username;
            impersPwd = password;
            impersDomain = domain;
        }

        public WindowsIdentity AllowAccesstoServer()
        {
            try
            {
                tokenHandle = IntPtr.Zero;
                bool result = LogonUser(impersUsername, impersDomain, impersPwd, 2, 0, ref tokenHandle);
                if (!result)
                {
                    int errorCode = Marshal.GetLastWin32Error();
                    throw new UnauthorizedAccessException($"LogonUser failed with error code {errorCode}");
                }

                newId = new WindowsIdentity(tokenHandle);
                return newId;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("Failed to impersonate user", ex);
            }
        }

        public void RemoveServerAccess()
        {
            if (tokenHandle != IntPtr.Zero)
            {
                CloseHandle(tokenHandle);
                tokenHandle = IntPtr.Zero;
            }
        }

        public void Dispose()
        {
            RemoveServerAccess();
            GC.SuppressFinalize(this);
        }

        ~Impartunate()
        {
            RemoveServerAccess();
        }
    }
}
