using ClassSelect.OpenIDConnect;
using Newtonsoft.Json;

namespace ClassSelect.Implementations
{
    public class KeyCloak
    {
        private bool isDebug;
        private bool isOK;
        private bool isTeacher;
        private string? accessToken;
        private string? classlessId;
        private string? teachersId;
        private string? developersId;
        private string? studentsId;

        /// <summary>
        /// This method uses the OAuth Resource Owners Credentials Flow to get an Access Token to provide
        /// Authorization to the APIs.
        /// </summary>
        /// <returns></returns>
        private string GetAccessToken()
        {
            var client = new HttpClient();
            // https://auth.c.ucnit.eu/realms/UCNit/protocol/openid-connect/token
            string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/realms/" + MyConfiguration.Get()["API_REALM"] + "/protocol/openid-connect/token";
            var request = new HttpRequestMessage(HttpMethod.Post, theURL);
            var collection = new List<KeyValuePair<string, string>>();
            collection.Add(new("client_id", MyConfiguration.Get()["API_CLIENTID"]));
            collection.Add(new("client_secret", MyConfiguration.Get()["API_SECRET"]));
            collection.Add(new("grant_type", "client_credentials"));
            var content = new FormUrlEncodedContent(collection);
            request.Content = content;
            if (isDebug)
            {
                Console.WriteLine("GetAccessToken");
                Console.WriteLine("(POST) " + theURL);
                Console.WriteLine("client_id: " + MyConfiguration.Get()["API_CLIENTID"]);
                Console.WriteLine("client_secret: " + MyConfiguration.Get()["API_SECRET"]);
                Console.WriteLine("grant_type: client_credentials");
            }
            var response = client.SendAsync(request).Result;
            try
            {
                response.EnsureSuccessStatusCode();
                string jsonString = response.Content.ReadAsStringAsync().Result;
                object responseData = JsonConvert.DeserializeObject(jsonString);
                // return the Access Token.
                accessToken = ((dynamic)responseData).access_token;
            }
            catch (Exception ex)
            {
                Console.WriteLine(request.RequestUri);
                Console.WriteLine(ex.Message);
                accessToken = null;
            }
            // return the Access Token.
            return accessToken;
        }

        public KeyCloak()
        {
            isDebug = MyConfiguration.Get()["DEBUG"] == "Y";
            try
            {
                accessToken = GetAccessToken();
                this.isOK = true;
            }
            catch
            {
                this.isOK = false;
            }
        }

        public bool KeyCloakIsOK() { return isOK; }

        public List<KCGroups> KeyCloakGetGroups()
        {
            var client = new HttpClient();
            // https://{{Server}}/admin/realms/{{Realm}}/groups
            string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/admin/realms/" + MyConfiguration.Get()["API_REALM"] + "/groups";
            var request = new HttpRequestMessage(HttpMethod.Get, theURL);
            request.Headers.Add("Authorization", "Bearer " + accessToken);
            if (isDebug)
            {
                Console.WriteLine("KeyCloakGetGroups");
                Console.WriteLine("(GET) " + theURL);
                Console.WriteLine("Authorization Bearer " + accessToken);
            }
            var response = client.SendAsync(request).Result;
            try
            {
                response.EnsureSuccessStatusCode();
            }
            catch (HttpRequestException ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("KeyCloakGetGroupsAsync");
            }
            string jsonString = response.Content.ReadAsStringAsync().Result;
            List<KCGroups> groups = JsonConvert.DeserializeObject<List<KCGroups>>(jsonString);
            foreach (KCGroups group in groups)
            {
                if (group.name == "ClassLess") classlessId  = group.id;
                if (group.name == "developer") developersId = group.id;
                if (group.name == "teacher")   teachersId   = group.id;
                if (group.name == "student")   studentsId   = group.id;
            }
            return groups;
        }

        public string? KeyCloakClassLess()
        {
            if (classlessId == null) _ = KeyCloakGetGroups();
            return classlessId;
        }

        public string? KeyCloakTeacher()
        {
            if (teachersId == null) _ = KeyCloakGetGroups();
            return teachersId;
        }

        public string? KeyCloakStudent()
        {
            if (studentsId == null) _ = KeyCloakGetGroups();
            return studentsId;
        }

        public List<KCGroups> KeyCloakGetUsersGroups(string theUser)
        {
            var client = new HttpClient();
            // https://{{Server}}/admin/realms/{{Realm}}/users/{{kajeID}}/groups
            string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/admin/realms/" + MyConfiguration.Get()["API_REALM"] + "/users/" + theUser + "/groups";
            var request = new HttpRequestMessage(HttpMethod.Get, theURL);
            request.Headers.Add("Authorization", "Bearer " + accessToken);
            if (isDebug)
            {
                Console.WriteLine("KeyCloakGetUsersGroups");
                Console.WriteLine("(GET) " + theURL);
                Console.WriteLine("Authorization Bearer " + accessToken);
            }
            var response = client.SendAsync(request).Result;
            try
            {
                response.EnsureSuccessStatusCode();
            }
            catch (HttpRequestException ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("KeyCloakGetUsersGroupsAsync for user: [" + theUser + "]");
            }
            string jsonString = response.Content.ReadAsStringAsync().Result;
            List<KCGroups> groups = JsonConvert.DeserializeObject<List<KCGroups>>(jsonString);
            isTeacher = false;
            foreach (KCGroups group in groups)
            {
                if (group.name == "teacher" || group.name == "developer")   isTeacher = true;
                if (isDebug)
                {
                    Console.WriteLine("in group: " + group.name);
                }
            }
            return groups;
        }

        public bool KeyCloakLeaveGroup(string theUser, string theGroup)
        {
            var client = new HttpClient();
            string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/admin/realms/" + MyConfiguration.Get()["API_REALM"] + "/users/" + theUser + "/groups/" + theGroup;
            var request = new HttpRequestMessage(HttpMethod.Delete, theURL);
            request.Headers.Add("Authorization", "Bearer " + accessToken);
            if (isDebug)
            {
                Console.WriteLine("KeyCloakLeaveGroup");
                Console.WriteLine("(DELETE) " + theURL);
                Console.WriteLine("Authorization Bearer " + accessToken);
            }
            var response = client.SendAsync(request).Result;
            try
            {
                response.EnsureSuccessStatusCode();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public bool KeyCloakJoinGroup(string theUser, string theGroup)
        {
            var client = new HttpClient();
            string theURL = "https://" + MyConfiguration.Get()["API_SERVER"] + "/admin/realms/" + MyConfiguration.Get()["API_REALM"] + "/users/" + theUser + "/groups/" + theGroup;
            var request = new HttpRequestMessage(HttpMethod.Put, theURL);
            request.Headers.Add("Authorization", "Bearer " + accessToken);
            if (isDebug)
            {
                Console.WriteLine("KeyCloakJoinGroup");
                Console.WriteLine("(PUT) " + theURL);
                Console.WriteLine("Authorization Bearer " + accessToken);
            }
            var response = client.SendAsync(request).Result;
            try
            {
                response.EnsureSuccessStatusCode();
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("KeyCloakJoinGroup: [" + theGroup + "] for user: [" + theUser + "]");
                return false;
            }
        }

        public void KeyCloakToggleMembership(string theUser, string theGroup)
        {
            List<KCGroups> myGroups = KeyCloakGetUsersGroups(theUser);
            if (isDebug)
            {
                foreach (KCGroups group in myGroups)
                {
                    Console.WriteLine("{0} member of {1}", theUser, group.name);
                }
            }
            foreach (KCGroups group in myGroups)
            {
                if (group.id == theGroup)
                {
                    KeyCloakLeaveGroup(theUser, theGroup);
                    if (isDebug) Console.WriteLine("{0} left {1}", theUser, theGroup);
                    return;
                }

            }
            // if we get here, then create membership
            KeyCloakJoinGroup(theUser, theGroup);
            if (isDebug) Console.WriteLine("{0} joined {1}", theUser, theGroup);
        }

        public bool KeyCloakIsTeacher() { return isTeacher; }
    }

    public class KCUserGroups
    {
        public string? id { get; set; }
        public string? name { get; set; }
        public string? path { get; set; }

    }

    public class KCGroups : KCUserGroups
    {
        public List<object> subGroups { get; set; }
    }

}
