using NUnit.Framework;
using System.Text.RegularExpressions;
using Microsoft.Playwright;
using Microsoft.Playwright.NUnit;
using NUnit.Framework.Internal;

namespace PlaywrightTests;

[Parallelizable(ParallelScope.Self)]
[TestFixture]
public partial class PokeyPageTests : PageTest
{
    private const string ScreenshotRoot = "../../../screenshots/";
    private const string HomeUrl = "http://localhost:5296";
    private const int AppInitDelay = 5000;
    private IPage? _page;
    private IBrowser? _browser;
    
    [GeneratedRegex("Home page")]
    private static partial Regex HomePageRegex();
    
    [GeneratedRegex(".*Pokey")]
    private static partial Regex PokeyUrlRegex();

    [SetUp]
    public async Task Init()
    {
        _browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions() { Headless = true, });
        _page = await _browser.NewPageAsync();
        await WaitForApp(_page);
    }

    [Test]
    public async Task PokeyOptionShouldBePresentInMenu()
    {
        // Confirm we've found the Gumby link in the header
        var pokeyPageLink = _page!.GetByRole(AriaRole.Link, new PageGetByRoleOptions { Name = "Pokey" });
        await Expect(pokeyPageLink).ToHaveAttributeAsync("href", "/Pokey");
    }

    [Test]
    public async Task NavigationToPokeyPageShouldSucceed()
    {
        await GotoPokey(_page!);
        await PageSnap(_page!, "gumby.png");
        await Expect(_page!).ToHaveURLAsync(PokeyUrlRegex());
    }
    
    [Test]
    public async Task PokeyImageShouldBePresentOnBrowser()
    {
        await GotoPokey(_page!);
        Expect(_page!.GetByRole(AriaRole.Img, new PageGetByRoleOptions { Name = "Pokey" }));
        
    }

    [Test]
    public async Task BothTimesShouldBeVisibleOnGet()
    {
        await GotoPokey(_page!);
        var handleList = _page!.QuerySelectorAllAsync("//*[ contains(text(), 'time is' ) ]").Result;
        Assert.That(handleList, Has.Count.EqualTo(2));
    }

    [Test]
    public async Task BothTimesShouldMatchOnGet()
    {
        await GotoPokey(_page!);
        var handleList = _page!.QuerySelectorAllAsync("//*[ contains(text(), 'time is' ) ]").Result;
        var time1= await handleList[0].TextContentAsync();
        var time2 = await handleList[1].TextContentAsync();
     
        // ReSharper disable once StringIndexOfIsCultureSpecific.1
        var startIndex1 = time1!.IndexOf(" is ") + 4;
        var dateTime1 = DateTime.Parse(time1[startIndex1..]);
        // ReSharper disable once StringIndexOfIsCultureSpecific.1
        var startIndex2 = time2!.IndexOf(" is ") + 4;
        var dateTime2 = DateTime.Parse(time1[startIndex2..]);
        
        Assert.That(dateTime1, Is.EqualTo(dateTime2));
 
    }

    /*** HELPERS ***/
    
    private static async Task PageSnap(IPage page, string filename)
    {
        await page.ScreenshotAsync(new PageScreenshotOptions { FullPage = true, Path = ScreenshotRoot+"/"+filename});
    }

    private static async Task ElementSnap(ILocator locator, string filename)
    {
        await locator.ScreenshotAsync(new LocatorScreenshotOptions { Path = ScreenshotRoot+"/"+filename });
    }
    
    private static async Task GotoPokey(IPage page)
    {
        await page.GetByRole(AriaRole.Link, new PageGetByRoleOptions { Name = "Pokey" }).ClickAsync();
    }
    
    private static async Task WaitForApp(IPage page)
    {
        var pageIsLoaded = false;
        while (!pageIsLoaded)
        {
            try
            {
                await page.GotoAsync(HomeUrl, new PageGotoOptions() { Timeout = AppInitDelay }); 
                pageIsLoaded = true;
            }
            catch
            {
                await Task.Delay(AppInitDelay);
            }
        }

        var appIsLoaded = false;
        while (!appIsLoaded)
        {
            try
            {
                var titleAsync = await page.TitleAsync();
                if (HomePageRegex().Match(titleAsync).Success)
                {
                    appIsLoaded = true;
                    continue;
                };
            }
            catch
            {
                // _logger.Information("Error loading app");
            }

            // _logger.Information("App not loaded, delaying before retrying...");
            await Task.Delay(AppInitDelay);
        }
        // _logger.Information($"{nameof(WaitForApp)} completed");
    }
}