#if DEBUG
#define kleinLogin // Über VPN geht Active Directory scheinbar nicht, daher manuelles einloggen
#endif
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Runtime.Versioning;
using System.Security.Claims;
using System.Threading.Tasks;
using WK5.Core;
using WK5.Core.PageModels.Account;

namespace WK5_Blazor.Pages.Account
{
    [AllowAnonymous]
    public class LoginModel : PageModel
    {


        [BindProperty]
        public LoginInput Input { get; set; } = new LoginInput();

        public string? ReturnUrl { get; set; }


        public async Task OnGetAsync(string? returnUrl = null)
        {
            ReturnUrl = returnUrl ?? Url.Content("~/");

            try
            {
                // Clear the existing external cookie
                await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            }
            catch { }

        }
        [SupportedOSPlatform("windows")]
        public async Task<IActionResult> OnPostAsync(string? returnUrl = null)
        {
            returnUrl = returnUrl ?? Url.Content("~/");

            if (ModelState.IsValid)
            {

#if kleinLogin
                // Hier Login simuliereren fürs Homeoffice.
                var claims = new List<Claim>
                {
                        new Claim(ClaimTypes.Name, Input.Username),
                        new Claim("EmployeeId",  30.ToString()),
                        new Claim("displayName", "Marvin Klein" ),
                        new Claim("password", Input.Password)
                };

                claims.Add(new Claim(ClaimTypes.Role, "VPNUser"));
                claims.Add(new Claim(ClaimTypes.Role, "KarleyEntwickler"));
                claims.Add(new Claim(ClaimTypes.Role, "GitAdmin"));
                claims.Add(new Claim(ClaimTypes.Role, "GitUser"));
                claims.Add(new Claim(ClaimTypes.Role, "DVG-SRV01"));
                claims.Add(new Claim(ClaimTypes.Role, "LokaleAdmins"));
                claims.Add(new Claim(ClaimTypes.Role, "Programmierer"));
                claims.Add(new Claim(ClaimTypes.Role, "Archivare"));
                claims.Add(new Claim(ClaimTypes.Role, "Remotedesktopbenutzer"));
                claims.Add(new Claim(ClaimTypes.Role, "Administratoren"));

                var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

                var authProperties = new AuthenticationProperties
                {
                    IsPersistent = Input.RememberMe,
                    RedirectUri = returnUrl
                };

                await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);


                return LocalRedirect(returnUrl);
#else
                var eintrag = new DirectoryEntry(GlobalConfig.Configuration.LDAP, Input.Username, Input.Password);

                try
                {
                    var _object = eintrag.NativeObject;
                    DirectorySearcher searcher = new DirectorySearcher(eintrag);
                    searcher.Filter = $"(SAMAccountName={Input.Username})";
                    searcher.PropertiesToLoad.Add("cn");
                    searcher.PropertiesToLoad.Add("memberOf");
                    searcher.PropertiesToLoad.Add("employeeid");
                    searcher.PropertiesToLoad.Add("telephonenumber");
                    searcher.PropertiesToLoad.Add("displayName");
                    searcher.PropertiesToLoad.Add("mail");

                    SearchResult result = searcher.FindOne();

                    if (result != null)
                    {
                        // Er kann bei employeeId rausfliegen, wenn diese nicht gesetzt ist
                        var claims = new List<Claim>
                        {
                             new Claim(ClaimTypes.Name, Input.Username),
                             new Claim("EmployeeId", result.Properties["employeeid"][0].ToString()!),
                             new Claim("displayName", result.Properties["displayName"][0].ToString()!),
                             new Claim("password", Input.Password)     
                        };

                        // Telefonnummer ist nicht zwingend angegeben
                        try
                        {
                            claims.Add(new Claim(ClaimTypes.HomePhone, result.Properties["telephonenumber"][0]?.ToString() ?? String.Empty));
                            claims.Add(new Claim(ClaimTypes.Email, result.Properties["mail"][0]?.ToString() ?? String.Empty));
                        }
                        catch (Exception)
                        {

                        }


                        int propertyCount = result.Properties["memberOf"].Count;
                        String dn;
                        int equalsIndex, commaIndex;

                        for (int propertyCounter = 0; propertyCounter < propertyCount;
                            propertyCounter++)
                        {
                            dn = (String)result.Properties["memberOf"][propertyCounter];

                            equalsIndex = dn.IndexOf("=", 1);
                            commaIndex = dn.IndexOf(",", 1);
                            if (-1 == equalsIndex)
                            {
                                break;
                            }

                            claims.Add(new Claim(ClaimTypes.Role, dn.Substring(equalsIndex + 1, commaIndex - equalsIndex - 1)));


                        }

                        var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

                        var authProperties = new AuthenticationProperties
                        {
                            IsPersistent = Input.RememberMe,
                            RedirectUri = returnUrl
                        };

                        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);


                        return LocalRedirect(returnUrl);
                    }
                    else
                    {
                        // Wenn man das LDAP kürzel vor dem Loginnanmen verwendet gibt es zwar keinen Fehler, der User wird aber dennoch nicht gefunden. Login nur mit reinen Anmeldenamen möglich
                        ModelState.AddModelError("login-error", "Username oder Passwort ist falsch.");
                    }
                }
                catch (Exception ex)
                {
                    if (ex.HResult == -2147023570)
                    {
                        ModelState.AddModelError("login-error", "Username oder Passwort ist falsch.");
                    }
                    else if (ex.HResult == -2147016672)
                    {
                        ModelState.AddModelError("login-error", "Es muss ein Username und Passwort angegeben werden.");
                    }
                    else if (ex.HResult == -2146233086)
                    {
                        ModelState.AddModelError("login-error", "Sie verfügen über keine Personalnummer. Bitte wenden Sie sich an die Programmierung.");
                    }
                    else
                    {
                        throw;
                    }
                }
#endif
            }
            return Page();
        }
    }
}