using System.Diagnostics;
using System.Net;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using SeleniumExtras.WaitHelpers;

namespace Berufsschule_HAM.E2ETests.Helper;

public static class AppHelper
{
    public const string ServerUrl = "http://localhost:5275";
    public static Uri ServerUri = new(ServerUrl);
    public static int DefaultTimeout = 10;
    public static async Task<Process> StartApp(string appUrl)
    {
        var startInfo = new ProcessStartInfo
        {
            FileName = "dotnet",
            Arguments = "run --project ../../../../../src/",
            WorkingDirectory = AppContext.BaseDirectory,
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
        };
        startInfo.EnvironmentVariables["ASPNETCORE_ENVIRONMENT"] = "Development";


        var process = new Process { StartInfo = startInfo };// Process process = Process.Start("/snap/bin/dotnet", "run -e Development");
        process.Start();
        using var client = new HttpClient();
        for (int i = 0; i < 60; i++)
        {
            try
            {
                var response = await client.GetAsync(appUrl);
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    return process;
                }
                else if (response.StatusCode != HttpStatusCode.RequestTimeout)
                {
                    throw new Exception($"Server did not start properly? {response.StatusCode}");
                }
            }
            catch (Exception) { }
            Thread.Sleep(1000);
        }
        throw new Exception("Server did not start within 60 seconds");
    }

    public static ChromeDriver GetChromeDriver()
    {
        var options = new ChromeOptions();
        options.AddArgument("--headless");
        options.AddArgument("--no-sandbox");
        options.AddArgument("--disable-dev-shm-usage");
        options.AddArgument("--window-size=1920,1080");
        if (File.Exists("/usr/bin/chromium-browser"))
        {
            options.BinaryLocation = "/usr/bin/chromium-browser";
        }
        return new ChromeDriver(options);

    }

    public static void Login(ChromeDriver driver)
    {
        driver.Navigate().GoToUrl(ServerUrl);
        IWebElement username = driver.FindElement(By.Id("username"));
        username.SendKeys("admin");
        IWebElement password = driver.FindElement(By.Id("password"));
        password.SendKeys("Test1234.");
        IWebElement submit = driver.FindElement(By.CssSelector("button[type=\"submit\"]"));
        submit.Click();
        Timeout(driver).Until(ExpectedConditions.UrlContains("/Home/Index"));        
    }

    public static bool TryRetryFindSuccessToast(ChromeDriver driver)
    {
        Timeout(driver).Until(ExpectedConditions.ElementIsVisible(By.CssSelector("#toastContainer div.bg-success")));
        return true;
    }

    public static bool CheckboxGetState(IWebElement webElement)
    {
        return webElement.GetAttribute("checked") == "true";
    }

    public static void ScrollIntoViewAndClick(ChromeDriver driver, IWebElement webElement)
    {
        driver.ExecuteScript("arguments[0].scrollIntoView();", webElement);
        int retryCounter = 0;
        retry:
        try
        {
            Thread.Sleep(250);
            webElement.Click();
        }
        catch (Exception)
        {
            if (retryCounter++ < 20)
            {
                goto retry;
            }
            throw;
        }
    }
    
    public static void AwaitVisible(ChromeDriver driver, By by)
    {
        Timeout(driver).Until(ExpectedConditions.ElementIsVisible(by));
    }

    public static WebDriverWait Timeout(ChromeDriver driver, int timeout)
    {
        return new(driver, TimeSpan.FromSeconds(timeout));
    }

    public static WebDriverWait Timeout(ChromeDriver driver)
    {
        return new(driver, TimeSpan.FromSeconds(DefaultTimeout));
    }

    public static string GetRandomName()
    {
        return new string([.. Enumerable.Range(0, 8).Select(_ => (char)('a' + new Random().Next(26)))]);
    }
}