using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using System.Diagnostics;
using Microsoft.AspNet.Identity;

namespace OwinSample.BasicAuthMiddleware
{


    public class HttpBasicAuthenticationHandler : AuthenticationHandler<HttpBasicAuthenticationOptions>
    {

        private static string DecodeBase64(string header)
        {
            header = Encoding.UTF8.GetString(Convert.FromBase64String(header));
            return header;
        }

        private static string RemovePrefix(string str, string prefix)
        {
            if (str.StartsWith(prefix))
            {
                str = str.Substring(prefix.Length, str.Length - prefix.Length);
            }
            return str;
        }

        protected override Task InitializeCoreAsync()
        {
            return base.InitializeCoreAsync();
        }

        protected override Task TeardownCoreAsync()
        {
            return base.TeardownCoreAsync();
        }

        public override Task<bool> InvokeAsync()
        {
            // Standard: false --> Weitermachen ...
            return base.InvokeAsync();
        }


        protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
        {

            var authResult = await Context.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ApplicationCookie);

            if (authResult != null)
            {
                var claimsIdentity = new ClaimsIdentity(authResult.Identity.Claims, this.Options.AuthenticationType);
                return new AuthenticationTicket(claimsIdentity, authResult.Properties);
            }

            var emptyTicket = new AuthenticationTicket(null, new AuthenticationProperties());


            var header = this.Request.Headers["Authorization"];

            if (string.IsNullOrEmpty(header) ||
                    !header.Trim().ToLower().StartsWith("basic"))
            {
                return emptyTicket;
            }

            header = header.Trim();
            header = header.Substring(5); // Basic wegschneiden ...
            header = header.Trim();
            header = DecodeBase64(header);

            var index = header.IndexOf(':');
            if (index == -1)
            {
                return emptyTicket;
            }

            var user = header.Substring(0, index);
            var password = header.Substring(index + 1);

            if (Options.OnValidateCredentials != null)
            {
                if (!Options.OnValidateCredentials(user, password))
                {
                    return emptyTicket;
                }
            }

            var identity = new ClaimsIdentity(Options.AuthenticationType);
            identity.AddClaim(new Claim(ClaimTypes.Name, user));

            // Weitere Claims ermitteln und setzen ...
            identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));


            AuthenticationProperties prop = new AuthenticationProperties();
            prop.Dictionary["WasStrongPassword"] = "true";
            var ticket = new AuthenticationTicket(identity, prop);

            return ticket;
        }

        protected override async Task ApplyResponseGrantAsync()
        {

            if (Context.Authentication.User != null)
            {
                var sourceIdendity = Context.Authentication.User.Identity as ClaimsIdentity;
                if (sourceIdendity != null) {
                    var claimsIdentity = new ClaimsIdentity(sourceIdendity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
                    Context.Authentication.SignIn(claimsIdentity);
                }
            }
            
            AuthenticationResponseGrant grant = base.Helper.LookupSignIn(base.Options.AuthenticationType);
            AuthenticationResponseRevoke revoke = base.Helper.LookupSignOut(base.Options.AuthenticationType, base.Options.AuthenticationMode);

            if (grant != null)
            {
                // SignIn requested
                if (grant.Properties.Dictionary.ContainsKey("info"))
                {
                    var info = grant.Properties.Dictionary["info"];
                    Debug.WriteLine(info);
                }
                var identity = grant.Identity;
                var principal = grant.Principal;
            }

            if (revoke != null)
            {
                // SignOut requested
                var authTypes = revoke.AuthenticationTypes;
            }

        }



        protected override async Task ApplyResponseChallengeAsync()
        {

            AuthenticationResponseChallenge challange = base.Helper.LookupChallenge(base.Options.AuthenticationType, base.Options.AuthenticationMode);

            if (challange != null && challange.AuthenticationTypes != null)
            {
                // Challange requested
                if (challange.Properties != null && challange.Properties.Dictionary.ContainsKey("info"))
                {
                    var info = challange.Properties.Dictionary["info"];
                    Response.Write(info);
                }
                var authTypes = challange.AuthenticationTypes;
                
            }

            if (this.Response.StatusCode == 401)
            {
                Response.Headers.Add("WWW-Authenticate", new [] { "Basic" });
            }
        }
    }
}
