using ESuite.UI.E2E.Helpers;
using ESuite.UI.E2E.Models;
using ESuite.UI.E2E.Pages;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using System.Text.RegularExpressions;

namespace ESuite.UI.E2E.StepDefinitions
{
    [Binding]
    public class SpecificationManagerStepDefinitions
    {
        private readonly IWebDriver driver;
        private readonly ScenarioContext _scenarioContext;
        private readonly ConfigHelper configHelper;


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

        [When(@"I added a Form Template into the Print Specifications")]
        public void ThenIAddedAFormIntoPrintSpecifications(Table dataTable)
        {
            BasicPage.ClickOnDropdownMenuItem("Glossaries");
            var specifications = dataTable.CreateSet<SpecificationsData>();
            foreach (var specification in specifications)
            {
                _scenarioContext["PrintSpecificationName"] = specification.Name + _scenarioContext["GUIDPostfix"];
                I.Click(By.LinkText("Print Specifications"));
                I.Click(BasicPage.AddButton);
                I.WaitTillInvisible(BasicPage.LoadingMessage);
                I.FillField(BasicPage.NameField, _scenarioContext["PrintSpecificationName"].ToString()!);
                I.SelectOption(AddGlossariesPage.PrintSpecificationFormTemplateFieldSelector, _scenarioContext["FormName"]!);
                I.Click(BasicPage.SaveAndCloseButton);
                AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext);
                I.WaitForVisible(BasicPage.ToastWithMessage("New Glossary Item added"));
                I.WaitTillInvisible(BasicPage.SaveAndCloseButton);
            }
        }

        [Then(@"^I (create|edit) a Specification$")]
        [When(@"^I (create|edit) a Specification$")]
        public void ThenICreateASpecification(string action, Table dataTable)
        {
            I.Click(BasicPage.DropdownTab("e-print"));
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!);
            I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!));
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SiteName"].ToString()!);
            I.Click(By.LinkText(_scenarioContext["SiteName"].ToString()!));

            var specifications = dataTable.CreateSet<SpecificationsData>();

            if (action == "create")
            {
                I.WaitTillInvisible(BasicPage.LoadingMessage);
                I.Click(BasicPage.AddButton);
                I.WaitTillInvisible(BasicPage.AddButton);
                I.WaitForPageToLoad();

                foreach (var specification in specifications)
                {
                    FillSpecification(specification);
                }
            }
            else if (action == "edit")
            {
                BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SpecificationName"].ToString()!);
                I.Click(BasicPage.EditObjectButton(_scenarioContext!["SpecificationName"].ToString()!));
                I.WaitTillInvisible(BasicPage.EditObjectButton(_scenarioContext!["SpecificationName"].ToString()!));
                I.WaitTillInvisible(BasicPage.LoadingMessage);
                I.WaitForPageToLoad();
                I.DebounceDelay(configHelper.DebounceDelayMilliseconds);

                foreach (var specification in specifications)
                {
                    FillSpecification(specification);
                }
            }

            I.Click(BasicPage.SaveAndCloseButton);
            AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext);
            I.WaitTillInvisible(BasicPage.SaveAndCloseButton);
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SpecificationName"].ToString()!);

            _scenarioContext["Specification"] = $"{"false"}, {_scenarioContext!["SpecificationName"]}, {_scenarioContext!["SiteName"]}";
            _scenarioContext["SpecificationEdited"] = $"{_scenarioContext!["SpecificationName"]}";
        }

        [Then(@"^I can not (create|edit) a Specification with required fields and empty value$")]
        [When(@"^I can not (create|edit) a Specification with required fields and empty value$")]
        public void ThenICanNotCreateASpecification(string action, Table dataTable)
        {
            I.Click(BasicPage.DropdownTab("e-print"));
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["OrganisationName"].ToString()!);
            I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!));
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SiteName"].ToString()!);
            I.Click(By.LinkText(_scenarioContext["SiteName"].ToString()!));

            var specifications = dataTable.CreateSet<SpecificationsData>();

            if (action == "create")
            {
                I.WaitTillInvisible(BasicPage.LoadingMessage);
                I.Click(BasicPage.AddButton);
                I.WaitTillInvisible(BasicPage.AddButton);
                I.WaitForPageToLoad();

                foreach (var specification in specifications)
                {
                    FillSpecification(specification);
                }
            }
            else if (action == "edit")
            {
                BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["SpecificationName"].ToString()!);
                I.Click(BasicPage.EditObjectButton(_scenarioContext!["SpecificationName"].ToString()!));
                I.WaitTillInvisible(BasicPage.EditObjectButton(_scenarioContext!["SpecificationName"].ToString()!));
                I.WaitTillInvisible(BasicPage.LoadingMessage);
                I.WaitForPageToLoad();
                I.DebounceDelay(configHelper.DebounceDelayMilliseconds);

                foreach (var specification in specifications)
                {
                    FillSpecification(specification);
                }
            }
            I.DebounceDelay(configHelper.DebounceDelayMilliseconds);
            I.Click(BasicPage.SaveAndCloseButton);
            AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext);

            _scenarioContext["Specification"] = $"{"false"}, {_scenarioContext!["SpecificationName"]}, {_scenarioContext!["SiteName"]}";
            _scenarioContext["SpecificationEdited"] = $"{_scenarioContext!["SpecificationName"]}";
        }

        [Then(@"^new Specification is (present|not present) on the list$")]
        [When(@"^new Specification is (present|not present) on the list$")]
        public void ThenNewSpecificationIsPresentOnTheList(string presence)
        {
            I.Click(BasicPage.DropdownTab("Home"));
            I.Click(BasicPage.DropdownTab("e-print"));
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext!["OrganisationName"].ToString()!);
            I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["OrganisationName"].ToString()!));
            BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext!["SiteName"].ToString()!);
            I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["SiteName"].ToString()!));

            switch (presence)
            {
                case "present":
                    BasicPage.SearchObjectNameInTableViaSearchInputField(_scenarioContext["GUID"].ToString()!, BasicPage.SearchInput);
                    break;
                case "not present":
                    BasicPage.SearchDeletedObjectNameInTableViaSearchInputField(_scenarioContext["GUID"].ToString()!);
                    break;
            }
        }

        [When(@"I delete existing Specification")]
        [Then(@"I delete existing Specification")]
        public void WhenIDeleteExistingSSOProvider()
        {
            I.Click(BasicPage.DropdownTab("Home"));
            I.Click(BasicPage.DropdownTab("e-print"));
            I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["OrganisationName"].ToString()!));
            I.Click(BasicPage.EPrintInstanceButton(_scenarioContext!["SiteName"].ToString()!));
            I.Click(BasicPage.DeleteObjectButton(_scenarioContext["SpecificationName"].ToString()!));
            I.WaitTillInvisible(BasicPage.DeleteObjectButton(_scenarioContext["SpecificationName"].ToString()!));
            I.Click(BasicPage.ConfirmDeletionButton);
            AutomationTestManagerHelper.SaveTimingForAction(_scenarioContext);
        }

        [Then(@"I check data on Specification")]
        public void ThenICheckEditedDataOnSSOProviderPage(Table dataTable)
        {
            var specifications = dataTable.CreateSet<SpecificationsData>();
            RetryHelper.Retry(() =>
            {
                I.Click(BasicPage.DropdownTab("e-print"));

                I.Click(By.LinkText(_scenarioContext["OrganisationName"].ToString()!));
                I.Click(By.LinkText(_scenarioContext["SiteName"].ToString()!));
                I.Click(BasicPage.EditObjectButton(_scenarioContext["SpecificationName"].ToString()!));
                I.WaitTillInvisible(BasicPage.EditObjectButton(_scenarioContext["SpecificationName"].ToString()!));
                I.WaitForPageToLoad();
                I.DebounceDelay(configHelper.DebounceDelayMilliseconds);

                I.WaitForElementWithAttributeValue(BasicPage.NameField, "value", _scenarioContext["SpecificationName"].ToString()!);
                foreach (var specification in specifications)
                {
                    switch (specification.SpecificationItems)
                    {
                        case "Glossary":
                            var actualGlossary = I.ReturnSelectedOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), 1);
                            if (specification.ItemValue!.Equals("dataFromScenarioContext"))
                            {
                                var glossaryFromScenarioContext = _scenarioContext["GlossaryItemName"].ToString()!;
                                Assert.AreEqual(glossaryFromScenarioContext, actualGlossary, $"Expected Glossary is: {glossaryFromScenarioContext}, but found: {actualGlossary}");
                            }
                            else
                            {
                                string expectedGlossary = specification.ItemValue ?? "";
                                Assert.AreEqual(expectedGlossary, actualGlossary, $"Expected Glossary is: {expectedGlossary}, but found: {actualGlossary}");
                            }
                            break;
                        case "Domain":
                            var actualDomain = I.ReturnSelectedOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), 1);

                            if (specification.ItemValue!.Equals("dataFromScenarioContext"))
                            {
                                var domainFromScenarioContext = _scenarioContext!["DomainName"].ToString()!;
                                Assert.AreEqual(domainFromScenarioContext, actualDomain, $"Expected Domain is: {domainFromScenarioContext}, but found: {actualDomain}");
                            }
                            else
                            {
                                string expectedDomain = specification.ItemValue ?? "";
                                Assert.AreEqual(expectedDomain, actualDomain, $"Expected Domain is: {expectedDomain}, but found: {actualDomain}");
                            }
                            break;
                        case "Text":

                            if (specification.ItemValue!.Equals("dataFromScenarioContext"))
                            {
                                var actualText = I.GetText(AddSpecificationsPage.PrintSpecificationTextAreaItem(specification.SpecificationItems)!, 1);
                                var textFromScenarioContext = _scenarioContext!["Text"].ToString()!;
                                Assert.AreEqual(textFromScenarioContext, actualText, $"Expected Text is: {textFromScenarioContext}, but found: {actualText}");
                            }
                            else
                            {
                                var actualText = I.GetText(AddSpecificationsPage.PrintSpecificationInputItem(specification.SpecificationItems)!, 1);
                                string expectedText = specification.ItemValue ?? "";
                                Assert.AreEqual(expectedText, actualText, $"Expected Text is: {expectedText}, but found: {actualText}");
                            }
                            break;
                        case "Sequence":
                            if (specification.ItemValue!.Equals("dataFromScenarioContext"))
                            {
                                var regexMatch = @"ID:\d{6}\s+Date:\d{2}";
                                var input = I.GetValueAttribute(AddSpecificationsPage.PrintSpecificationInputItem(specification.SpecificationItems)!, 1);
                                Assert.IsTrue(Regex.IsMatch(input, regexMatch), $"Sequence {input} doesn't match the regex {regexMatch}");
                            }
                            break;
                        case "Form Template":
                            var actualFormTemplate = I.ReturnSelectedOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), 1);

                            if (specification.ItemValue!.Equals("dataFromScenarioContext"))
                            {
                                var expectedFormTemplate = _scenarioContext["ChildFormName"].ToString()!;
                                Assert.AreEqual(expectedFormTemplate, actualFormTemplate, $"Expected Form Template is: {expectedFormTemplate}, but found: {actualFormTemplate}");
                            }
                            else
                            {
                                var expectedFormTemplate = _scenarioContext["FormName"].ToString()!;
                                Assert.AreEqual(expectedFormTemplate, actualFormTemplate, $"Expected Form Template is: {expectedFormTemplate}, but found: {actualFormTemplate}");
                            }
                            break;
                        case "Number":
                            var actualNumber = AddSpecificationsPage.PrintSpecificationInputItem(specification.SpecificationItems);

                            if (specification.ItemValue!.Equals("dataFromScenarioContext"))
                            {
                                var numberFromScenarioContext = _scenarioContext!["Number"].ToString()!;
                                I.WaitForElementWithAttributeValue(actualNumber, "value", numberFromScenarioContext, 1);
                            }
                            else
                            {
                                string expectedNumber = specification.ItemValue ?? "";
                                I.WaitForElementWithAttributeValue(actualNumber, "value", expectedNumber, 1);
                            }
                            break;
                        default:
                            break;
                    }
                }
            });
        }

        private void FillSpecification(SpecificationsData specification)
        {
            I.DebounceDelay(configHelper.DebounceDelayMilliseconds);
            if (!string.IsNullOrEmpty(specification.Name)) _scenarioContext["SpecificationName"] = specification.Name + _scenarioContext["GUID"];
            if (!string.IsNullOrEmpty(specification.Name)) I.FillField(BasicPage.NameField, _scenarioContext["SpecificationName"].ToString()!);
            if (!string.IsNullOrEmpty(specification.PrintSpecification)) I.SelectOption(AddSpecificationsPage.PrintSpecificationSelector, _scenarioContext["PrintSpecificationName"]!);
            switch (specification.SpecificationItems)
            {
                case "Glossary":
                    if (specification.ItemValue!.Equals("defaultGlossary") && !specification.MultiselectField == true)
                    {
                        I.SelectOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), _scenarioContext["GlossaryItemName"]!);
                        _scenarioContext["FormFieldInstance"] = $"{_scenarioContext["GlossaryItemName"]}";
                    }
                    else if (!string.IsNullOrEmpty(specification.ItemValue) && !specification.MultiselectField == true)
                    {
                        var glossaries = _scenarioContext["GlossaryList"] as List<string>;
                        if (glossaries != null)
                        {
                            var differentGlossary = glossaries.FirstOrDefault(x => x.Contains("TestBlackGlossaryItemDifferent", StringComparison.OrdinalIgnoreCase));
                            I.SelectOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), differentGlossary!);
                            _scenarioContext["FormFieldInstance"] = $"{differentGlossary}";
                        }
                    }
                    else if (specification.ItemValue!.Equals("defaultGlossary") && specification.MultiselectField == true)
                    {
                        var glossaries = _scenarioContext["GlossaryList"] as List<string>;
                        for (int i = 0; i < specification.NumberOfItems && i < glossaries!.Count; i++)
                        {
                            string glossary = glossaries[i];
                            I.Click(AddSpecificationsPage.PrintSpecificationMultiSelectField);
                            I.Click(AddSpecificationsPage.PrintSpecificationMultiSelectItem(glossary));
                        }
                    }
                    break;
                case "Domain":
                    if (!string.IsNullOrEmpty(specification.ItemValue) && !specification.MultiselectField == true)
                    {
                        I.SelectOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), _scenarioContext!["DomainName"]!);
                    }
                    else if (specification.ItemValue!.Equals("default") && specification.MultiselectField == true)
                    {
                        if (_scenarioContext["DomainList"] is List<string> domains)
                        {
                            for (int i = 0; i < specification.NumberOfItems && i < domains!.Count; i++)
                            {
                                string domain = domains[i];
                                I.Click(AddSpecificationsPage.PrintSpecificationMultiSelectField);
                                I.Click(AddSpecificationsPage.PrintSpecificationMultiSelectItem(domain));
                            }
                        }
                    }
                    break;
                case "Text":
                    if (!string.IsNullOrEmpty(specification.ItemValue))
                        I.FillField(AddSpecificationsPage.PrintSpecificationTextAreaItem(specification.SpecificationItems), specification.ItemValue!);
                    _scenarioContext["Text"] = specification.ItemValue!;
                    break;
                case "Sequence":
                    break;
                case "Form Template":
                    if (!string.IsNullOrEmpty(specification.ItemValue))
                        I.SelectOption(AddSpecificationsPage.PrintSpecificationSelectItem(specification.SpecificationItems), _scenarioContext["ChildFormName"]!);
                    break;
                case "Number":
                    if (!string.IsNullOrEmpty(specification.ItemValue))
                        I.FillField(AddSpecificationsPage.PrintSpecificationInputItem(specification.SpecificationItems), specification.ItemValue!);
                    _scenarioContext["Number"] = specification.ItemValue!;
                    break;
                default:
                    break;
            }
        }

        [Then(@"Error toast message is present")]
        public static void ThenErrorToastMessageIsPresent(Table dataTable)
        {
            var commonData = dataTable.CreateSet<SpecificationsData>();
            foreach (var data in commonData)
            {
                I.WaitForVisible(BasicPage.ToastWithMessage(data.Message!));
            }
        }
    }
}
