namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;

public sealed class LegacyInteractionMetricsNativeContractTests
{
    private static readonly string RepositoryRoot = FindRepositoryRoot();
    private static readonly string AppRoot = Path.Combine(
        RepositoryRoot,
        "src",
        "MBN_STOCK_WEBVIEW.LegacyParityApp");
    private static readonly string Window = File.ReadAllText(
        Path.Combine(AppRoot, "MainWindow.xaml.cs"));

    [Fact]
    public void NativeWindowReadsBothWindowsDragThresholdsInCssDipCoordinates()
    {
        Assert.Contains("private const int SmCxDrag = 68;", Window,
            StringComparison.Ordinal);
        Assert.Contains("private const int SmCyDrag = 69;", Window,
            StringComparison.Ordinal);
        Assert.Contains("[DllImport(\"user32.dll\", ExactSpelling = true)]", Window,
            StringComparison.Ordinal);
        Assert.Contains(
            "GetSystemMetricsForDpi(\n" +
            "                    SmCxDrag,\n" +
            "                    LegacyInteractionMetrics.CssPixelsPerInch)",
            Window.Replace("\r\n", "\n", StringComparison.Ordinal),
            StringComparison.Ordinal);
        Assert.Contains(
            "GetSystemMetricsForDpi(\n" +
            "                    SmCyDrag,\n" +
            "                    LegacyInteractionMetrics.CssPixelsPerInch)",
            Window.Replace("\r\n", "\n", StringComparison.Ordinal),
            StringComparison.Ordinal);
        Assert.DoesNotContain("GetSystemMetrics(", Window, StringComparison.Ordinal);
        Assert.Contains("LegacyInteractionMetrics.FromPixelsAtDpi(", Window,
            StringComparison.Ordinal);
        Assert.Contains("private static extern uint GetDoubleClickTime();", Window,
            StringComparison.Ordinal);
        Assert.Contains(
            "doubleClickTimeMilliseconds: (int)GetDoubleClickTime()",
            Window,
            StringComparison.Ordinal);
        Assert.Equal(2, CountOccurrences(
            Window,
            "[DllImport(\"user32.dll\", ExactSpelling = true)]"));
        Assert.Contains("logical DIP coordinate space used by XAML", Window,
            StringComparison.Ordinal);
        Assert.Contains("Root.XamlRoot?.RasterizationScale", Window,
            StringComparison.Ordinal);
    }

    [Fact]
    public void NativeWindowRefreshesMetricsAfterRuntimeSettingsAndDpiChanges()
    {
        Assert.Contains("interactionMetrics: _interactionMetrics", Window,
            StringComparison.Ordinal);
        Assert.Contains("private const uint WmSettingChange = 0x001A;", Window,
            StringComparison.Ordinal);
        Assert.Contains("private const uint WmDisplayChange = 0x007E;", Window,
            StringComparison.Ordinal);
        Assert.Contains("private const uint WmDpiChanged = 0x02E0;", Window,
            StringComparison.Ordinal);
        Assert.Contains("AttachInteractionMetricsRefresh();", Window,
            StringComparison.Ordinal);
        Assert.Contains("DetachInteractionMetricsRefresh();", Window,
            StringComparison.Ordinal);
        Assert.Contains("SetWindowSubclass(", Window, StringComparison.Ordinal);
        Assert.Contains("RemoveWindowSubclass(", Window, StringComparison.Ordinal);
        Assert.Contains(
            "message is WmSettingChange or WmDisplayChange or WmDpiChanged",
            Window,
            StringComparison.Ordinal);
        Assert.Contains("QueueInteractionMetricsRefresh();", Window,
            StringComparison.Ordinal);
        Assert.Contains("DispatcherQueuePriority.High", Window,
            StringComparison.Ordinal);
        Assert.True(
            CountOccurrences(Window, "RefreshInteractionMetrics();") >= 3,
            "Metrics must be refreshed at setup, runtime change, and state posting.");
        Assert.DoesNotContain(
            "private readonly LegacyInteractionMetrics _interactionMetrics",
            Window,
            StringComparison.Ordinal);
    }

    [Fact]
    public void NativeWindowDisablesFutureWebZoomAndFallsBackWithoutPrivateApis()
    {
        Assert.Contains(
            "coreWebView.Settings.AreBrowserAcceleratorKeysEnabled = false;",
            Window,
            StringComparison.Ordinal);
        Assert.Contains("coreWebView.Settings.IsZoomControlEnabled = false;", Window,
            StringComparison.Ordinal);
        Assert.Contains("coreWebView.Settings.IsPinchZoomEnabled = false;", Window,
            StringComparison.Ordinal);
        Assert.DoesNotContain("CoreWebView2Controller.ZoomFactor", Window,
            StringComparison.Ordinal);
        Assert.Contains("catch (DllNotFoundException)", Window,
            StringComparison.Ordinal);
        Assert.Contains("catch (EntryPointNotFoundException)", Window,
            StringComparison.Ordinal);
        Assert.Contains("catch (BadImageFormatException)", Window,
            StringComparison.Ordinal);
        Assert.Contains("catch (PlatformNotSupportedException)", Window,
            StringComparison.Ordinal);
        Assert.Equal(
            4,
            CountOccurrences(Window, "return CreateFallbackInteractionMetrics();"));
        Assert.Contains(
            "LegacyInteractionMetrics.Default with\n" +
            "        {\n" +
            "            HostRasterizationScale = ReadHostRasterizationScale()",
            Window.Replace("\r\n", "\n", StringComparison.Ordinal),
            StringComparison.Ordinal);
    }

    private static int CountOccurrences(string value, string search)
    {
        var count = 0;
        var index = 0;
        while ((index = value.IndexOf(search, index, StringComparison.Ordinal)) >= 0)
        {
            count++;
            index += search.Length;
        }

        return count;
    }

    private static string FindRepositoryRoot()
    {
        var current = new DirectoryInfo(AppContext.BaseDirectory);
        while (current is not null)
        {
            if (File.Exists(Path.Combine(current.FullName, "MBN_STOCK_WEBVIEW.sln")))
            {
                return current.FullName;
            }

            current = current.Parent;
        }

        throw new DirectoryNotFoundException("Repository root was not found.");
    }
}
