using System.Runtime.InteropServices;

namespace ElectronNET.IntegrationTests.Tests
{
    using ElectronNET.API;
    using ElectronNET.API.Entities;
    using ElectronNET.Common;
    using ElectronNET.IntegrationTests.Common;

    [Collection("ElectronCollection")]
    public class WebContentsTests : IntegrationTestBase
    {
        public WebContentsTests(ElectronFixture fx) : base(fx)
        {
        }

        [IntegrationFact]
        public async Task Can_get_url_after_navigation()
        {
            var wc = this.MainWindow.WebContents;
            await wc.LoadURLAsync("https://example.com");
            var url = await wc.GetUrl();
            url.Should().Contain("example.com");
        }

        [IntegrationFact]
        public async Task ExecuteJavaScript_returns_title()
        {
            var wc = this.MainWindow.WebContents;
            await wc.LoadURLAsync("https://example.com");
            var title = await wc.ExecuteJavaScriptAsync<string>("document.title");
            title.Should().NotBeNull();
        }

        [IntegrationFact]
        public async Task DomReady_event_fires()
        {
            var wc = this.MainWindow.WebContents;
            var fired = false;
            wc.OnDomReady += () => fired = true;
            await wc.LoadURLAsync("https://example.com");
            await Task.Delay(500.ms());
            fired.Should().BeTrue();
        }

        [IntegrationFact]
        public async Task Can_print_to_pdf()
        {
            var html = "data:text/html,<html><body><h1>PDF Test</h1><p>Electron.NET</p></body></html>";
            await this.MainWindow.WebContents.LoadURLAsync(html);
            var tmp = Path.Combine(Path.GetTempPath(), $"electronnet_pdf_{Guid.NewGuid():N}.pdf");
            try
            {
                var ok = await this.MainWindow.WebContents.PrintToPDFAsync(tmp);
                ok.Should().BeTrue();
                File.Exists(tmp).Should().BeTrue();
                new FileInfo(tmp).Length.Should().BeGreaterThan(0);
            }
            finally
            {
                if (File.Exists(tmp))
                {
                    File.Delete(tmp);
                }
            }
        }

        [IntegrationFact]
        public async Task Can_basic_print()
        {
            var html = "data:text/html,<html><body><h2>Print Test</h2></body></html>";
            await this.MainWindow.WebContents.LoadURLAsync(html);
            var ok = await this.MainWindow.WebContents.PrintAsync(new PrintOptions { Silent = true, PrintBackground = true });
            ok.Should().BeTrue();
        }

        [IntegrationFact]
        public async Task GetPrintersAsync_check()
        {
            var info = await this.MainWindow.WebContents.GetPrintersAsync();
            info.Should().NotBeNull();
        }

        [IntegrationFact]
        public async Task GetSetZoomFactor_check()
        {
            await this.MainWindow.WebContents.GetZoomFactorAsync();
            var ok = await this.MainWindow.WebContents.GetZoomFactorAsync();
            ok.Should().BeGreaterThan(0.0);
            this.MainWindow.WebContents.SetZoomFactor(2.0);
            await Task.Delay(500.ms());
            ok = await this.MainWindow.WebContents.GetZoomFactorAsync();
            ok.Should().Be(2.0);
        }

        [IntegrationFact]
        public async Task GetSetZoomLevel_check()
        {
            BrowserWindow window = null;

            try
            {
                window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, "about:blank");

                await Task.Delay(100.ms());

                window.WebContents.SetZoomLevel(0);
                await Task.Delay(500.ms());

                var ok = await window.WebContents.GetZoomLevelAsync();
                ok.Should().Be(0);

                window.WebContents.SetZoomLevel(2);
                await Task.Delay(500.ms());

                ok = await window.WebContents.GetZoomLevelAsync();
                ok.Should().Be(2);
            }
            finally
            {
                window?.Destroy();
            }
        }

        [IntegrationFact]
        public async Task DevTools_check()
        {
            BrowserWindow window = null;

            try
            {
                window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, "about:blank");

                await Task.Delay(3.seconds());

                window.WebContents.IsDevToolsOpened().Should().BeFalse();
                window.WebContents.OpenDevTools();
                await Task.Delay(5.seconds());

                window.WebContents.IsDevToolsOpened().Should().BeTrue();
                window.WebContents.CloseDevTools();
                await Task.Delay(2.seconds());

                window.WebContents.IsDevToolsOpened().Should().BeFalse();
            }
            finally
            {
                window?.Destroy();
            }
        }

        [IntegrationFact]
        public async Task GetSetAudioMuted_check()
        {
            this.MainWindow.WebContents.SetAudioMuted(true);
            await Task.Delay(500.ms());
            var ok = await this.MainWindow.WebContents.IsAudioMutedAsync();
            ok.Should().BeTrue();
            this.MainWindow.WebContents.SetAudioMuted(false);
            await Task.Delay(500.ms());
            ok = await this.MainWindow.WebContents.IsAudioMutedAsync();
            ok.Should().BeFalse();

            // Assuming no audio is playing, IsCurrentlyAudibleAsync should return false
            // there is no way to play audio in this test
            ok = await this.MainWindow.WebContents.IsCurrentlyAudibleAsync();
            ok.Should().BeFalse();
        }

        [IntegrationFact]
        public async Task GetSetUserAgent_check()
        {
            BrowserWindow window = null;

            try
            {
                await Task.Delay(1.seconds());

                window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions { Show = true }, "about:blank");

                await Task.Delay(5.seconds());

                window.WebContents.SetUserAgent("MyUserAgent/1.0");

                await Task.Delay(2.seconds());

                var ok = await window.WebContents.GetUserAgentAsync();
                ok.Should().Be("MyUserAgent/1.0");
            }
            finally
            {
                window?.Destroy();
            }
        }

    }
}