using Kavita.Models.Entities.Enums;
using Kavita.Server.Helpers;

namespace Kavita.Server.Tests.Helpers;

public class BrowserHelperTests
{
    #region DetermineClientType Tests

    [Theory]
    [InlineData("", ClientDeviceType.Unknown)]
    [InlineData(null, ClientDeviceType.Unknown)]
    public void DetermineClientType_ReturnsUnknown_ForEmptyOrNullUserAgent(string userAgent, ClientDeviceType expected)
    {
        var result = BrowserHelper.DetermineClientType(userAgent);
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData("Mozilla/5.0 (Linux; Android 11; Pixel 5) KOReader/2023.10", ClientDeviceType.KoReader)]
    [InlineData("koreader/1.0", ClientDeviceType.KoReader)]
    [InlineData("KOREADER", ClientDeviceType.KoReader)]
    [InlineData("Mozilla/5.0 (Linux; U; Android 2.0; en-us;) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 (Kobo Touch)", ClientDeviceType.KoReader)]
    public void DetermineClientType_ReturnsKOReader_ForKOReaderUserAgents(string userAgent, ClientDeviceType expected)
    {
        var result = BrowserHelper.DetermineClientType(userAgent);
        Assert.Equal(expected, result);
    }


    [Theory]
    [InlineData("Panels/2.0", ClientDeviceType.Panels)]
    [InlineData("panels", ClientDeviceType.Panels)]
    public void DetermineClientType_ReturnsPanels_ForPanelsUserAgents(string userAgent, ClientDeviceType expected)
    {
        var result = BrowserHelper.DetermineClientType(userAgent);
        Assert.Equal(expected, result);
    }


    [Theory]
    [InlineData("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")]
    [InlineData("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0")]
    [InlineData("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15")]
    [InlineData("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0")]
    public void DetermineClientType_ReturnsWebBrowser_ForBrowserUserAgents(string userAgent)
    {
        var result = BrowserHelper.DetermineClientType(userAgent);
        Assert.Equal(ClientDeviceType.WebBrowser, result);
    }

    [Theory]
    [InlineData("curl/7.68.0")]
    [InlineData("PostmanRuntime/7.32.3")]
    [InlineData("SomeCustomClient/1.0")]
    public void DetermineClientType_ReturnsUnknown_ForUnrecognizedUserAgents(string userAgent)
    {
        var result = BrowserHelper.DetermineClientType(userAgent);
        Assert.Equal(ClientDeviceType.Unknown, result);
    }

    [Fact]
    public void DetermineClientType_PrioritizesSpecificClients_OverWebBrowser()
    {
        // KOReader running on Android with Chrome-like UA
        var userAgent = "Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36 Chrome/91.0 KOReader/2023.10";
        var result = BrowserHelper.DetermineClientType(userAgent);
        Assert.Equal(ClientDeviceType.KoReader, result);
    }

    #endregion

    #region DetectPlatform Tests

    [Theory]
    [InlineData("", ClientDevicePlatform.Unknown)]
    [InlineData(null, ClientDevicePlatform.Unknown)]
    public void DetectPlatform_ReturnsUnknown_ForEmptyOrNullUserAgent(string userAgent, ClientDevicePlatform expected)
    {
        var result = BrowserHelper.DetectPlatform(userAgent);
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", ClientDevicePlatform.Windows)]
    [InlineData("Mozilla/5.0 (Windows NT 6.1; WOW64)", ClientDevicePlatform.Windows)]
    [InlineData("Mozilla/5.0 (win32)", ClientDevicePlatform.Windows)]
    [InlineData("Mozilla/5.0 (win64)", ClientDevicePlatform.Windows)]
    [InlineData("WINDOWS", ClientDevicePlatform.Windows)]
    public void DetectPlatform_ReturnsWindows_ForWindowsUserAgents(string userAgent, ClientDevicePlatform expected)
    {
        var result = BrowserHelper.DetectPlatform(userAgent);
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15", ClientDevicePlatform.MacOs)]
    [InlineData("Mozilla/5.0 (Macintosh; Intel Mac OS X 11_6) AppleWebKit/537.36", ClientDevicePlatform.MacOs)]
    [InlineData("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15", ClientDevicePlatform.MacOs)]
    [InlineData("macintosh", ClientDevicePlatform.MacOs)]
    public void DetectPlatform_ReturnsMacOS_ForMacOSUserAgents(string userAgent, ClientDevicePlatform expected)
    {
        var result = BrowserHelper.DetectPlatform(userAgent);
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36", ClientDevicePlatform.Linux)]
    [InlineData("Mozilla/5.0 (X11; Ubuntu; Linux x86_64)", ClientDevicePlatform.Linux)]
    [InlineData("linux", ClientDevicePlatform.Linux)]
    [InlineData("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0", ClientDevicePlatform.Linux)]
    public void DetectPlatform_ReturnsLinux_ForLinuxUserAgents(string userAgent, ClientDevicePlatform expected)
    {
        var result = BrowserHelper.DetectPlatform(userAgent);
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData("Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15", ClientDevicePlatform.Ios)]
    [InlineData("Mozilla/5.0 (iPad; CPU OS 17_2 like Mac OS X) AppleWebKit/605.1.15", ClientDevicePlatform.Ios)]
    [InlineData("Mozilla/5.0 (iPod touch; CPU iPhone OS 12_0 like Mac OS X)", ClientDevicePlatform.Ios)]
    [InlineData("Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1", ClientDevicePlatform.Ios)]
    [InlineData("Mozilla/5.0 (iPad; CPU OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1", ClientDevicePlatform.Ios)]
    [InlineData("iphone", ClientDevicePlatform.Ios)]
    [InlineData("ipad", ClientDevicePlatform.Ios)]
    [InlineData("ipod", ClientDevicePlatform.Ios)]
    [InlineData("mac os", ClientDevicePlatform.Ios)]
    public void DetectPlatform_ReturnsIOS_ForIOSUserAgents(string userAgent, ClientDevicePlatform expected)
    {
        var result = BrowserHelper.DetectPlatform(userAgent);
        Assert.Equal(expected, result);
    }

    [Theory]
    [InlineData("Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36", ClientDevicePlatform.Android)]
    [InlineData("Mozilla/5.0 (Linux; Android 11; SM-G991B)", ClientDevicePlatform.Android)]
    [InlineData("android", ClientDevicePlatform.Android)]
    [InlineData("Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36", ClientDevicePlatform.Android)]
    [InlineData("Mozilla/5.0 (Linux; Android 15; SM-S931B Build/AP3A.240905.015.A2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/127.0.6533.103 Mobile Safari/537.36", ClientDevicePlatform.Android)]
    public void DetectPlatform_ReturnsAndroid_ForAndroidUserAgents(string userAgent, ClientDevicePlatform expected)
    {
        var result = BrowserHelper.DetectPlatform(userAgent);
        Assert.Equal(expected, result);
    }

    [Fact]
    public void DetectPlatform_ReturnsAndroid_NotLinux_ForAndroidUserAgents()
    {
        // Android UAs contain "Linux" but should be detected as Android
        const string userAgent = "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36";
        var result = BrowserHelper.DetectPlatform(userAgent);
        Assert.Equal(ClientDevicePlatform.Android, result);
    }

    [Theory]
    [InlineData("curl/7.68.0")]
    [InlineData("PostmanRuntime/7.32.3")]
    [InlineData("FreeBSD")]
    [InlineData("OpenBSD")]
    public void DetectPlatform_ReturnsUnknown_ForUnrecognizedPlatforms(string userAgent)
    {
        var result = BrowserHelper.DetectPlatform(userAgent);
        Assert.Equal(ClientDevicePlatform.Unknown, result);
    }

    [Fact]
    public void DetectPlatform_IsCaseInsensitive()
    {
        Assert.Equal(ClientDevicePlatform.Windows, BrowserHelper.DetectPlatform("WINDOWS NT 10.0"));
        Assert.Equal(ClientDevicePlatform.Android, BrowserHelper.DetectPlatform("ANDROID 13"));
        Assert.Equal(ClientDevicePlatform.MacOs, BrowserHelper.DetectPlatform("MACINTOSH; INTEL MAC OS X"));
        Assert.Equal(ClientDevicePlatform.Ios, BrowserHelper.DetectPlatform("IPHONE"));
        Assert.Equal(ClientDevicePlatform.Linux, BrowserHelper.DetectPlatform("LINUX X86_64"));
    }

    #endregion

    #region Real-World User Agent Tests

    [Theory]
    [InlineData(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        ClientDeviceType.WebBrowser,
        ClientDevicePlatform.Windows)]
    [InlineData(
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        ClientDeviceType.WebBrowser,
        ClientDevicePlatform.MacOs)]
    [InlineData(
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        ClientDeviceType.WebBrowser,
        ClientDevicePlatform.Linux)]
    [InlineData(
        "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1",
        ClientDeviceType.WebBrowser,
        ClientDevicePlatform.Ios)]
    [InlineData(
        "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",
        ClientDeviceType.WebBrowser,
        ClientDevicePlatform.Android)]
    [InlineData(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
        ClientDeviceType.WebBrowser,
        ClientDevicePlatform.Windows)]
    [InlineData(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
        ClientDeviceType.WebBrowser,
        ClientDevicePlatform.Windows)]

    [InlineData(
        "Mozilla/5.0 (X11; Linux x86_64; Librera) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.2997.373167658 Safari/537.36",
        ClientDeviceType.Librera,
        ClientDevicePlatform.Linux)] // Should be Android but not sure how to actually correct
    public void RealWorld_UserAgents_AreDetectedCorrectly(string userAgent, ClientDeviceType expectedClientType, ClientDevicePlatform expectedPlatform)
    {
        var clientType = BrowserHelper.DetermineClientType(userAgent);
        var platform = BrowserHelper.DetectPlatform(userAgent);

        Assert.Equal(expectedClientType, clientType);
        Assert.Equal(expectedPlatform, platform);
    }

    #endregion
}
