using e_suite.Database.Core.Models;
using eSuite.Core.Sequences;
using ESuite.UI.E2E.Pages;
using OpenQA.Selenium;


namespace ESuite.UI.E2E.Helpers
{
    public class AutomationTestManagerHelper
    {
        private readonly IWebDriver driver;
        private readonly ScenarioContext _scenarioContext;
        private readonly APIHelper apiHelper;
        private readonly ConfigHelper configHelper;

        public AutomationTestManagerHelper(ScenarioContext scenarioContext)
        {
            driver = WebDriverHelper.GetWebDriver();
            _scenarioContext = scenarioContext;
            apiHelper = new(_scenarioContext);
            configHelper = new ConfigHelper();
        }

        private static readonly Dictionary<string, string> auditEntityDisplayName = new()
        {
            { "Forms", "Forms" },
            { "Form Template", "Form Template" },
            { "Form Field Instance", "Form Field Instance" },
            { "Form Instance", "Form Instance" },
            { "Sequence", "Sequence" },
            { "Glossaries", "Glossary" },
            { "Glossary Item", "Glossary" },
            { "Glossary Custom Field Value", "Glossary Custom Field Value" },
            { "Custom Field", "Custom Field" },
            { "Client Domains", "Domain" },
            { "Users", "User" },
            { "Sso Manager", "Sso Provider" },
            { "Organisation", "Organisation" },
            { "Site", "Site" },
            { "Role", "Role" },
            { "Role Access", "RoleAccess" },
            { "UserRoles", "UserRoles" },
            { "Mail Template", "Mail Template" },
            { "Custom Field Glossary", "Custom Field Glossary" },
            { "Custom Field Sequence", "Custom Field Sequence" },
            { "Custom Field Number", "Custom Field Number" },
            { "Custom Field Text", "Custom Field Text" },
            { "Custom Field Form Template", "Custom Field" },
            { "Custom Field Domain", "Custom Field" },
            { "Specification", "Specification" }
        };

        public static Dictionary<string, string> AuditEntityDisplayName { get => auditEntityDisplayName; }

        public void CreateSsoProvider()
        {
            _scenarioContext["SSOProviderName"] = "TestSsoProvider" + _scenarioContext["GUID"];
            string clientId = "778899937320-phjl4hpacmeele7k92650u5q73n66cqe.apps.googleusercontent.com";
            string clientSecret = "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";
            string validIssuer = "https://accounts.google.com";
            string authorisationEndpoint = "https://accounts.google.com/o/oauth2/auth";
            string tokenEndpoint = "https://oauth2.googleapis.com/token";
            Guid guid = new(_scenarioContext["GUID"].ToString()!);
            string clientIdHidden = "<Redacted>", clientSecretHidden = "<Redacted>";
            bool isPublic = true;
            _scenarioContext["SSOProviderCreated"] = $"{authorisationEndpoint}, {clientIdHidden}, {clientSecretHidden}, {false.ToString().ToLower()}, {guid}, {isPublic.ToString().ToLower()}, {_scenarioContext["SSOProviderName"]}, {tokenEndpoint}, {validIssuer}";
            Task.Run(async () =>
            {
                await apiHelper.CreateNewSSOProvider(
                    configHelper.APIUrl,
                    _scenarioContext["SSOProviderName"].ToString()!,
                    clientId,
                    clientSecret,
                    validIssuer,
                    authorisationEndpoint,
                    tokenEndpoint,
                    isPublic,
                    guid
                    );
            });
        }

        public void DeleteSsoProvider()
        {
            DeleteEntity("Sso Manager", _scenarioContext["SSOProviderName"].ToString()!, _scenarioContext);
        }

        public async Task CreateUser()
        {
            var firstName = "Wolfgang" + _scenarioContext["GUID"];
            var middleName = "Amadeus";
            var lastName = "Mozart";
            var email = "tww44@inbox.testmail.app" + _scenarioContext["GUID"];
            _scenarioContext["UserName"] = $"{firstName} {middleName} {lastName}";
            _scenarioContext["UserEmail"] = $"{email}";
            await Task.Run(async () =>
            {
                var domains = await apiHelper.GetDomains(configHelper.APIUrl);
                var data = domains["data"]!.ElementAt(0);
                int domainId = (int)data["id"]!;

                await apiHelper.CreateNewUser(
                    configHelper.APIUrl,
                    firstName!,
                    middleName!,
                    lastName!,
                    email,
                    domainId
                );
            });
        }

        public void DeleteUser()
        {
            DeleteEntity("Users", _scenarioContext["UserName"].ToString()!, _scenarioContext, AddUsersPage.DisplayNameSearchField);
        }

        public async Task CreateOrganisation()
        {
            var name = "TestOrganisation" + _scenarioContext["GUID"];
            var address = "TestAddress";
            OrganisationStatus status = OrganisationStatus.Active;
            Guid guid = new(_scenarioContext["GUID"].ToString()!);

            _scenarioContext!["OrganisationName"] = $"{name}";
            _scenarioContext["OrganisationCreated"] = $"{address}, {"false"}, {guid}, {name}, {status}";

            await apiHelper.CreateNewOrganisation(
                 configHelper.APIUrl,
                 guid!,
                 name!,
                 address!,
                 status!
             );
        }

        public void DeleteOrganisation()
        {
            I.Click(BasicPage.DropdownTab("e-print"));
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!);
            I.Click(BasicPage.DeleteOrganisationButton(_scenarioContext!["OrganisationName"].ToString()!));
            I.WaitTillInvisible(BasicPage.DeleteOrganisationButton(_scenarioContext!["OrganisationName"].ToString()!));
            I.Click(BasicPage.ConfirmDeletionButton);
            SaveTimingForAction(_scenarioContext);
            I.WaitTillInvisible(BasicPage.ConfirmDeletionButton);
        }

        public void CreateSite()
        {
            var name = "TestOrganisationSite" + _scenarioContext["GUID"];
            var address = "TestAddress";
            OrganisationStatus status = OrganisationStatus.Active;
            Guid guid = new(_scenarioContext["GUID"].ToString()!);

            _scenarioContext!["SiteName"] = $"{name}";
            _scenarioContext["SiteCreated"] = $"{address}, {"false"}, {guid}, {name}, {_scenarioContext["OrganisationName"]}, {""}, {status}";

            Task.Run(async () =>
            {
                var organisations = await apiHelper.GetOrganisations(configHelper.APIUrl);
                var data = organisations["data"]!.ElementAt(0);
                int organisationId = (int)data["id"]!;
                await apiHelper.CreateNewSite(
                    configHelper.APIUrl,
                    guid!,
                    name!,
                    address!,
                    status!,
                    organisationId
                );
            });
        }

        public void DeleteSite()
        {
            I.Click(BasicPage.DropdownTab("e-print"));
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!);
            I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!));
            I.Click(BasicPage.DeleteOrganisationButton(_scenarioContext!["SiteName"].ToString()!));
            I.WaitTillInvisible(BasicPage.DeleteOrganisationButton(_scenarioContext!["SiteName"].ToString()!));
            I.Click(BasicPage.ConfirmDeletionButton);
            SaveTimingForAction(_scenarioContext);
            I.WaitTillInvisible(BasicPage.ConfirmDeletionButton);
        }

        public void SaveDataFromCreatedUser()
        {
            Task.Run(async () =>
            {
                var users = await apiHelper.GetUsers(configHelper.APIUrl);
                var data = users["data"]!.ElementAt(0);
                int userId = (int)data["id"]!;
                string userGuid = (string)data["guid"]!;
                string userFirstName = (string)data["firstName"]!;
                string userLastName = (string)data["lastName"]!;
                string userMiddleName = (string)data["middleNames"]!;
                string userDomainName = (string)data["domainName"]!;
                string userEmail = (string)data["email"]!;
                string userCreatedDate = (string)data["created"]!;
                var userEmailConfirmed = (string)data["emailConfirmed"]!;
                _scenarioContext["UserCreated"] = $"{"true"}, {userCreatedDate}, {userDomainName}, {userEmail}, {userEmailConfirmed.ToLower()}, {userFirstName}, {userGuid}," +
                $" {userLastName}, {userMiddleName}, {"<Redacted>"}, {""}, {"<Redacted>"}, {"<Redacted>"}, {"false"}";
            });
        }

        public async Task CreateDomain(string name)
        {

            if (string.IsNullOrEmpty(name))
            {
                name = "TestDomain" + _scenarioContext["GUID"];
            }

            var sunriseHostName = "";
            var sunriseAppId = "";
            var sunriseCategoryId = "";
            int? sigmaId = null;
            Guid guid = Guid.NewGuid();

            _scenarioContext!["DomainName"] = $"{name}";
            _scenarioContext["DomainCreated"] = $"{"false"}, {guid}, {name}, {""}, {""}, {""}, {""}, {""}";

            await apiHelper.CreateNewDomain(
                configHelper.APIUrl,
                guid!,
                name!,
                sunriseHostName,
                sunriseAppId,
                sunriseCategoryId,
                sigmaId
            );
        }

        public void CreateRole()
        {
            _scenarioContext["DomainRoleName"] = "Role" + _scenarioContext["GUID"];
            var name = _scenarioContext["DomainRoleName"].ToString()!;
            Guid guid = new(_scenarioContext["GUID"].ToString()!);
            var isSuperUser = false;
            var isAdministrator = false;
            var canDelete = true;
            _scenarioContext["RoleCreated"] = $"{canDelete.ToString().ToLower()}, {false.ToString().ToLower()}, {_scenarioContext["DomainName"]}, {guid}, {isAdministrator.ToString().ToLower()}, {isSuperUser.ToString().ToLower()}, {name}";

            Task.Run(async () =>
            {
                var domains = await apiHelper.GetDomains(configHelper.APIUrl);
                var data = domains["data"]!.ElementAt(0);
                int domainId = (int)data["id"]!;

                await apiHelper.CreateNewRole(
                    configHelper.APIUrl,
                    name!,
                    guid!,
                    isSuperUser!,
                    isAdministrator,
                    domainId
                );
            });
        }

        public async Task CreateSequence(string? newName = null)
        {
            _scenarioContext["SequenceName"] = (newName ?? "Sequence") + _scenarioContext["GUID"];
            var name = _scenarioContext["SequenceName"].ToString()!;
            Guid guid = new(_scenarioContext["GUID"].ToString()!);
            Rollover rollOver = Rollover.Day;
            int seed = 1;
            int increment = 1;
            var pattern = "ID:[000000] Date:{DD}";

            await Task.Run(async () =>
            {
                await apiHelper.CreateNewSequence(
                   configHelper.APIUrl,
                   name!,
                   seed!,
                   increment!,
                   pattern,
                   rollOver,
                   guid!
                 );
            });
        }

        public async Task AssignAdminRole(int userId, Guid userGuid)
        {
            var roles = await apiHelper.GetRoles(configHelper.APIUrl);
            var data = roles["data"]!.ElementAt(0);
            int roleId = (int)data["id"]!;
            Guid roleGuid = Guid.Parse((string)data["guid"]!);
            await apiHelper.CreateAdminRoleToLatestDomain(
                configHelper.APIUrl,
                roleGuid!,
                roleId!,
                userGuid!,
                userId!
            );
        }

        public async Task DeleteUserAPI()
        {
            var userId = int.Parse(_scenarioContext["UserId"].ToString()!);
            Guid userGuid = new(_scenarioContext["UserGUID"].ToString()!);

            await apiHelper.DeleteUserAPI(
                configHelper.APIUrl,
                userGuid!,
                userId!
            );
        }

        public async Task DeleteDomainAPI()
        {
            var domainId = int.Parse(_scenarioContext["DomainId"].ToString()!);
            Guid domainGuid = new(_scenarioContext["DomainGUID"].ToString()!);

            await apiHelper.DeleteDomainAPI(
                configHelper.APIUrl,
                domainGuid!,
                domainId!
            );
        }

        public void DeleteDomain()
        {
            DeleteEntity("Client Domains", _scenarioContext["DomainName"].ToString()!, _scenarioContext);
        }

        public void DeleteFormTemplate()
        {
            DeleteEntity("Forms", _scenarioContext["FormName"].ToString()!, _scenarioContext);
        }

        public static void DeleteEntity(string menuName, string entityName, ScenarioContext scenarioContext, By? locator = null)
        {
            try
            {
                NavigateToMenu(menuName);
                BasicPage.SearchObjectNameInTableViaSearchInputField(entityName, locator);
                I.Click(BasicPage.DeleteObjectButton(entityName));
                I.WaitTillInvisible(BasicPage.DeleteObjectButton(entityName));
                I.Click(BasicPage.ConfirmDeletionButton);
                SaveTimingForAction(scenarioContext);
                I.WaitTillInvisible(BasicPage.ConfirmDeletionButton);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to delete entity '{entityName}' in menu '{menuName}': {ex.Message}");
                throw;
            }
        }

        public static void SaveTimingForAction(ScenarioContext scenarioContext)
        {
            DateTimeOffset currentDateAndTime = DateTimeOffset.Now;
            string formattedDate = currentDateAndTime.ToString("MMM d, yy, hh:mm tt");
            scenarioContext["Timing"] = formattedDate;
        }

        public static void NavigateToMenu(string menuName)
        {
            try
            {
                BasicPage.ClickOnDropdownMenuItem(menuName);
                //I.WaitForElementVisibleAndClickable(BasicPage.SearchInput);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to navigate to menu '{menuName}': {ex.Message}");
                throw;
            }
        }
    }
}