using e_suite.API.Common.models;
using e_suite.Database.Core.Models;
using eSuite.Core.Miscellaneous;
using eSuite.Core.Sequences;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http.Headers;
using System.Text;

namespace ESuite.UI.E2E.Helpers
{
    public class APIHelper
    {
        private readonly HttpClient httpClient;
        private readonly ConfigHelper configHelper;
        private readonly ScenarioContext _scenarioContext;

        public APIHelper(ScenarioContext scenarioContext)
        {
            this.httpClient = new HttpClient();
            configHelper = new ConfigHelper();
            _scenarioContext = scenarioContext;
        }

        public async Task<string> SendGetRequest(string url)
        {
            try
            {
                HttpResponseMessage response = await httpClient.GetAsync(url);

                return await response.Content.ReadAsStringAsync();
            }
            catch (Exception ex)
            {
                throw new Exception($"Error sending GET request: {ex.Message}");
            }
        }

        public async Task<HttpResponseMessage> SendPostRequest(string url, string requestBody)
        {
            try
            {
                StringContent content = new(requestBody, Encoding.UTF8, "application/json");

                return await httpClient.PostAsync(url, content);
            }
            catch (Exception ex)
            {
                throw new Exception($"Error sending POST request: {ex.Message}");
            }
        }

        private string _authToken { get; set; } = string.Empty;

        public void ClearAuthToken()
        {
            _authToken = string.Empty;
        }

        public async Task<string> GetAuthToken()
        {
            if (!string.IsNullOrWhiteSpace(_authToken))
            {
                return _authToken;
            }

            var url = $"{configHelper.APIUrl}/api/Authentication/login";

            string requestBody = $@"
            {{
                ""email"": ""{configHelper.AdminName}"",
                ""password"": ""{configHelper.AdminPassword}"",
                ""securityCode"": """",
                ""requestTfaRemoval"": false
            }}";

            try
            {
                HttpResponseMessage response = await SendPostRequest(url, requestBody);

                if (response.IsSuccessStatusCode)
                {
                    var responseContent = await response.Content.ReadAsStringAsync();
                    _authToken = GetFieldValueFromJSONResponse("token", responseContent);
                    return _authToken;
                }
                else
                {
                    throw new Exception("GetAuthToken Response is: " + response.StatusCode);
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Error getting authentication token: {ex.Message}");
            }
        }

        public async Task<string> SendAuthenticatedRequest(string url, string token, string requestType = "GET")
        {
            try
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                HttpResponseMessage response;

                switch (requestType)
                {
                    case "GET": response = await httpClient.GetAsync(url); break;
                    case "POST":
                        response = await httpClient.PostAsync(url, null);
                        if (response.IsSuccessStatusCode)
                        {
                            Console.WriteLine("Response content: " + await response.Content.ReadAsStringAsync());
                        }
                        else
                        {
                            var body = await response.Content.ReadAsStringAsync();
                            throw new Exception("Response status code from POST request: " + response.StatusCode + body);
                        }
                        break;
                    default: throw new Exception("Unknown request type");
                }
                return await response.Content.ReadAsStringAsync();
            }
            catch (Exception ex)
            {
                throw new Exception($"Error sending authenticated POST request: {ex.Message}");
            }
            finally
            {
                httpClient.DefaultRequestHeaders.Authorization = null;
            }
        }

        public async Task<HttpResponseMessage> SendAuthenticatedRequest<T>(string url, string token, T requestBody = default!, string requestType = "GET")
        {
            try
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                HttpResponseMessage response;

                switch (requestType)
                {
                    case "GET": response = await httpClient.GetAsync(url); break;
                    case "POST":
                        var postPayload = System.Text.Json.JsonSerializer.Serialize(requestBody);
                        StringContent postContent = new(postPayload!, Encoding.UTF8, "application/json");
                        response = await httpClient.PostAsync(url, postContent);
                        AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext);
                        break;
                    case "DELETE":
                        var deletePayload = System.Text.Json.JsonSerializer.Serialize(requestBody);
                        var deleteContent = new StringContent(deletePayload, Encoding.UTF8, "application/json");

                        var request = new HttpRequestMessage
                        {
                            Method = HttpMethod.Delete,
                            RequestUri = new Uri(url),
                            Content = deleteContent
                        };

                        response = await httpClient.SendAsync(request);
                        AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext);
                        break;
                    default: throw new Exception("Unknown request type");
                }
                return response;

            }
            catch (Exception ex)
            {
                throw new Exception($"Error sending authenticated POST request: {ex.Message}");
            }
            finally
            {
                httpClient.DefaultRequestHeaders.Authorization = null;
            }
        }

        public static string GetFieldValueFromJSONResponse(string field, dynamic jsonString)
        {
            try
            {
                dynamic json = JsonConvert.DeserializeObject(jsonString);

                return json[field]; ;
            }
            catch (Exception)
            {
                throw new Exception(
                    $"Error appears in process of getting field '{field}' data from JSON string: {jsonString}"
                    );
            }
        }

        public async Task<JObject> GetDomains(string url)
        {
            string token = await GetAuthToken();
            UriBuilder domainsUriBuilder = new($"{url}/api/Domain/domains");
            var query = System.Web.HttpUtility.ParseQueryString(domainsUriBuilder.Query);
            query["SortAscending"] = "false";
            query["SortKey"] = "id";
            domainsUriBuilder.Query = query.ToString();
            string domainsUrl = domainsUriBuilder.ToString();
            string getDomainsResponse = await SendAuthenticatedRequest(domainsUrl, token);

            if (string.IsNullOrEmpty(getDomainsResponse))
            {
                throw new Exception("Could not get response for getting all domains.");
            }

            JObject getDomainsJson = JObject.Parse(getDomainsResponse);

            return getDomainsJson;
        }

        public async Task<JObject> GetUsers(string url)
        {
            string token = await GetAuthToken();

            UriBuilder usersUriBuilder = new($"{url}/api/User/users");
            var query = System.Web.HttpUtility.ParseQueryString(usersUriBuilder.Query);
            query["SortKey"] = "created";
            query["SortAscending"] = "false";

            usersUriBuilder.Query = query.ToString();

            string usersUrl = usersUriBuilder.ToString();
            string getUsersResponse = await SendAuthenticatedRequest(usersUrl, token);

            if (string.IsNullOrEmpty(getUsersResponse))
            {
                throw new Exception("Could not get response for getting all Users.");
            }
            var settings = new JsonSerializerSettings
            {
                DateParseHandling = DateParseHandling.None, // Prevent automatic DateTime parsing
                DateFormatHandling = DateFormatHandling.IsoDateFormat
            };
            JObject getUsers = JsonConvert.DeserializeObject<JObject>(getUsersResponse, settings)!;
            return getUsers;
        }
        public async Task<JObject> GetOrganisations(string url)
        {
            string token = await GetAuthToken();

            UriBuilder usersUriBuilder = new($"{url}/api/Organisations/organisations");
            var query = System.Web.HttpUtility.ParseQueryString(usersUriBuilder.Query);
            query["SortAscending"] = "false";
            query["SortKey"] = "id";
            usersUriBuilder.Query = query.ToString();

            string usersUrl = usersUriBuilder.ToString();
            string getUsersResponse = await SendAuthenticatedRequest(usersUrl, token);

            if (string.IsNullOrEmpty(getUsersResponse))
            {
                throw new Exception("Could not get response for getting all Organisations.");
            }

            JObject getUsers = JsonConvert.DeserializeObject<JObject>(getUsersResponse)!;
            return getUsers;
        }

        public async Task<JObject> GetRoles(string url)
        {

            string token = await GetAuthToken();
            UriBuilder rolesUriBuilder = new($"{url}/api/Role/roles");
            var query = System.Web.HttpUtility.ParseQueryString(rolesUriBuilder.Query);
            query["SortAscending"] = "false";
            query["SortKey"] = "id";
            rolesUriBuilder.Query = query.ToString();
            string rolesUrl = rolesUriBuilder.ToString();
            string getRolesResponse = await SendAuthenticatedRequest(rolesUrl, token);

            if (string.IsNullOrEmpty(getRolesResponse))
            {
                throw new Exception("Could not get response for getting all domains.");
            }

            JObject getDomainsJson = JObject.Parse(getRolesResponse);

            return getDomainsJson;
        }

        public async Task CreateNewUser(string url, string firstName, string middleName, string lastName, string email, int domainId)
        {
            var requestBody = new UserRegistration
            {
                FirstName = firstName,
                MiddleNames = middleName,
                LastName = lastName,
                Email = email,
                DomainId = new eSuite.Core.Miscellaneous.GeneralIdRef
                {
                    Id = domainId
                }
            };

            string token = await GetAuthToken();
            UriBuilder usersUriBuilder = new($"{url}/api/User/user");
            string usersUrl = usersUriBuilder.ToString();
            await SendAuthenticatedRequest(usersUrl, token, requestBody, "POST");
        }

        public async Task CreateNewSSOProvider(string url, string name, string clientId, string clientSecret, string validIssuer, string authorizationEndpoint, string tokenEndpoint, bool isPublic, Guid guid)
        {
            var requestBody = new CreateSsoProvider()
            {
                Name = name,
                ClientId = clientId,
                ClientSecret = clientSecret,
                ValidIssuer = validIssuer,
                AuthorizationEndpoint = authorizationEndpoint,
                TokenEndpoint = tokenEndpoint,
                IsPublic = isPublic,
                Guid = guid
            };

            string token = await GetAuthToken();
            UriBuilder ssoProviderUriBuilder = new($"{url}/api/SsoManager/ssoProvider");
            string ssoProviderUrl = ssoProviderUriBuilder.ToString();
            await SendAuthenticatedRequest(ssoProviderUrl, token, requestBody, "POST");
        }

        public async Task<HttpResponseMessage> CreateNewOrganisation(string url, Guid guid, string name, string address, OrganisationStatus status)
        {
            var requestBody = new CreateOrganisation()
            {
                Guid = guid,
                Name = name,
                Address = address,
                Status = status
            };

            string token = await GetAuthToken();
            UriBuilder organisationUriBuilder = new($"{url}/api/Organisations/organisation");
            string siteUrl = organisationUriBuilder.ToString();
            HttpResponseMessage response = await SendAuthenticatedRequest(siteUrl, token, requestBody, "POST");
            return response;
        }

        public async Task CreateNewSite(string url, Guid guid, string name, string address, OrganisationStatus status, int organisationId)
        {
            var requestBody = new CreateSite()
            {
                Name = name,
                Address = address,
                Status = status,
                OrganisationId = new eSuite.Core.Miscellaneous.GeneralIdRef
                {
                    Id = organisationId
                },
                Guid = guid
            };

            string token = await GetAuthToken();
            UriBuilder siteUriBuilder = new($"{url}/api/Site/site");
            string siteUrl = siteUriBuilder.ToString();
            await SendAuthenticatedRequest(siteUrl, token, requestBody, "POST");
        }

        public async Task<HttpResponseMessage> CreateNewDomain(string url, Guid guid, string name, string sunriseHostName, string sunriseAppId, string sunriseCategoryId, int? sigmaId)
        {
            var requestBody = new CreateDomain()
            {
                Guid = guid,
                Name = name,
                SunriseHostName = sunriseHostName,
                SunriseAppId = sunriseAppId,
                SunriseCategoryId = sunriseCategoryId,
                SigmaId = sigmaId
            };

            string token = await GetAuthToken();
            UriBuilder domainUriBuilder = new($"{url}/api/Domain/domain");
            string siteUrl = domainUriBuilder.ToString();
            HttpResponseMessage response = await SendAuthenticatedRequest(siteUrl, token, requestBody, "POST");
            return response;
        }

        public async Task CreateNewRole(string url, string name, Guid guid, bool isSuperUser, bool isAdministrator, int domainId)
        {
            var requestBody = new CreateRole
            {
                Name = name,
                Guid = guid,
                IsSuperUser = isSuperUser,
                IsAdministrator = isAdministrator,
                DomainId = new eSuite.Core.Miscellaneous.GeneralIdRef
                {
                    Id = domainId
                }
            };

            string token = await GetAuthToken();
            UriBuilder roleUriBuilder = new($"{url}/api/Role/role");
            string roleUrl = roleUriBuilder.ToString();
            await SendAuthenticatedRequest(roleUrl, token, requestBody, "POST");
        }

        public async Task CreateNewSequence(string url, string name, int seed, int increment, string pattern, Rollover rollOver, Guid guid)
        {
            var requestBody = new Sequence
            {
                Name = name,
                Seed = seed,
                Increment = increment,
                Pattern = pattern,
                RolloverType = rollOver,
                GeneralIdRef = new eSuite.Core.Miscellaneous.GeneralIdRef()
                {
                    Guid = guid
                }
            };

            string token = await GetAuthToken();
            UriBuilder sequenceUriBuilder = new($"{url}/api/Sequences/sequence");
            string sequenceUrl = sequenceUriBuilder.ToString();
            await SendAuthenticatedRequest(sequenceUrl, token, requestBody, "POST");
        }

        public async Task CreateAdminRoleToLatestDomain(string url, Guid roleGuid, int roleId, Guid userGuid, int userId)
        {
            var requestBody = new UserRoleIds
            {
                RoleId = new eSuite.Core.Miscellaneous.GeneralIdRef()
                {
                    Guid = roleGuid,
                    Id = roleId
                },
                UserId = new eSuite.Core.Miscellaneous.GeneralIdRef()
                {
                    Guid = userGuid,
                    Id = userId
                }
            };

            string token = await GetAuthToken();
            UriBuilder sequenceUriBuilder = new($"{url}/api/Role/roleUsers");
            string sequenceUrl = sequenceUriBuilder.ToString();
            await SendAuthenticatedRequest(sequenceUrl, token, requestBody, "POST");
        }

        public async Task DeleteUserAPI(string url, Guid userGuid, int userId)
        {
            var requestBody = new GeneralIdRef
            {
                Guid = userGuid,
                Id = userId
            };

            string token = await GetAuthToken();
            UriBuilder sequenceUriBuilder = new($"{url}/api/User/user");
            string sequenceUrl = sequenceUriBuilder.ToString();
            string ddd = JsonConvert.SerializeObject(requestBody);
            var response = await SendAuthenticatedRequest(sequenceUrl, token, requestBody, "DELETE");
            var r = await response.Content.ReadAsStringAsync();
            var statusCode = response.StatusCode;
        }

        public async Task DeleteDomainAPI(string url, Guid userGuid, int userId)
        {
            var requestBody = new GeneralIdRef
            {
                Guid = userGuid,
                Id = userId
            };

            string token = await GetAuthToken();
            UriBuilder sequenceUriBuilder = new($"{url}/api/Domain/domain");
            string sequenceUrl = sequenceUriBuilder.ToString();
            string ddd = JsonConvert.SerializeObject(requestBody);
            var response = await SendAuthenticatedRequest(sequenceUrl, token, requestBody, "DELETE");
            var r = await response.Content.ReadAsStringAsync();
            var statusCode = response.StatusCode;
        }

        public void Dispose()
        {
            httpClient.Dispose();
        }

        internal void AssignAdminRoleToUser(string v)
        {
            throw new NotImplementedException();
        }
    }
}
