defmodule Towerops.Accounts.UserAgentParserTest do
  use ExUnit.Case, async: true

  alias Towerops.Accounts.UserAgentParser

  doctest UserAgentParser

  describe "parse/1 - nil and empty strings" do
    test "returns unknown device for nil" do
      result = UserAgentParser.parse(nil)

      assert result.browser_name == "Unknown"
      assert result.browser_version == nil
      assert result.os_name == "Unknown"
      assert result.os_version == nil
      assert result.device_type == "desktop"
      assert result.device_name == "Unknown on Unknown"
    end

    test "returns unknown device for empty string" do
      result = UserAgentParser.parse("")

      assert result.browser_name == "Unknown"
      assert result.browser_version == nil
      assert result.os_name == "Unknown"
      assert result.os_version == nil
      assert result.device_type == "desktop"
      assert result.device_name == "Unknown on Unknown"
    end
  end

  describe "parse/1 - Chrome on various platforms" do
    test "parses Chrome on macOS" do
      ua =
        "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"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Chrome"
      assert result.browser_version == "120.0"
      assert result.os_name == "macOS"
      assert result.os_version == "10.15.7"
      assert result.device_type == "desktop"
      assert result.device_name == "Chrome on macOS"
    end

    test "parses Chrome on Windows 10" do
      ua =
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Chrome"
      assert result.browser_version == "120.0"
      assert result.os_name == "Windows"
      assert result.os_version == "10"
      assert result.device_type == "desktop"
      assert result.device_name == "Chrome on Windows"
    end

    test "parses Chrome on Linux" do
      ua =
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Chrome"
      assert result.browser_version == "120.0"
      assert result.os_name == "Linux"
      assert result.os_version == nil
      assert result.device_type == "desktop"
      assert result.device_name == "Chrome on Linux"
    end

    test "parses Chrome on Android mobile" do
      ua =
        "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Chrome"
      assert result.browser_version == "120.0"
      assert result.os_name == "Android"
      # Android version without decimal point doesn't match the regex
      assert result.os_version == nil
      assert result.device_type == "mobile"
      assert result.device_name == "Chrome on Android"
    end

    test "parses Chrome on Android tablet with version" do
      ua =
        "Mozilla/5.0 (Linux; Android 13.0; Pixel Tablet) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Chrome"
      assert result.browser_version == "120.0"
      assert result.os_name == "Android"
      assert result.os_version == "13.0"
      # "Pixel Tablet" matches Android.*Tablet regex
      assert result.device_type == "tablet"
    end
  end

  describe "parse/1 - Safari on iOS" do
    test "parses Safari on iPhone" do
      ua =
        "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"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Safari"
      assert result.browser_version == "17.2"
      assert result.os_name == "iOS"
      assert result.os_version == "17.2"
      assert result.device_type == "mobile"
      assert result.device_name == "Safari on iOS"
    end

    test "parses Safari on iPad" do
      ua =
        "Mozilla/5.0 (iPad; CPU OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Safari"
      assert result.browser_version == "17.2"
      assert result.os_name == "iOS"
      assert result.os_version == "17.2"
      assert result.device_type == "tablet"
      assert result.device_name == "Safari on iOS"
    end

    test "parses Safari on macOS" do
      ua =
        "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"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Safari"
      assert result.browser_version == "17.2"
      assert result.os_name == "macOS"
      assert result.os_version == "10.15.7"
      assert result.device_type == "desktop"
      assert result.device_name == "Safari on macOS"
    end
  end

  describe "parse/1 - Firefox" do
    test "parses Firefox on macOS" do
      ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Firefox"
      assert result.browser_version == "121.0"
      assert result.os_name == "macOS"
      # Firefox uses different version format
      assert result.device_type == "desktop"
      assert result.device_name == "Firefox on macOS"
    end

    test "parses Firefox on Windows" do
      ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Firefox"
      assert result.browser_version == "121.0"
      assert result.os_name == "Windows"
      assert result.os_version == "10"
      assert result.device_type == "desktop"
      assert result.device_name == "Firefox on Windows"
    end

    test "parses Firefox on Android" do
      ua = "Mozilla/5.0 (Android 13; Mobile; rv:121.0) Gecko/121.0 Firefox/121.0"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Firefox"
      assert result.browser_version == "121.0"
      assert result.os_name == "Android"
      assert result.device_type == "mobile"
      assert result.device_name == "Firefox on Android"
    end
  end

  describe "parse/1 - Edge" do
    test "parses Edge on Windows" do
      ua =
        "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"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Edge"
      assert result.browser_version == "120.0"
      assert result.os_name == "Windows"
      assert result.os_version == "10"
      assert result.device_type == "desktop"
      assert result.device_name == "Edge on Windows"
    end

    test "parses Edge on macOS" do
      ua =
        "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 Edg/120.0"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Edge"
      assert result.browser_version == "120.0"
      assert result.os_name == "macOS"
      assert result.os_version == "10.15.7"
      assert result.device_type == "desktop"
      assert result.device_name == "Edge on macOS"
    end

    test "parses Edge on iOS (EdgeiOS)" do
      ua =
        "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/120.0 Version/17.0 Mobile/15E148 Safari/604.1"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Edge"
      assert result.browser_version == "120.0"
      assert result.os_name == "iOS"
      assert result.os_version == "17.2"
      assert result.device_type == "mobile"
      assert result.device_name == "Edge on iOS"
    end
  end

  describe "parse/1 - Opera" do
    test "parses Opera on Windows (OPR)" do
      ua =
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 OPR/106.0"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Opera"
      assert result.browser_version == "106.0"
      assert result.os_name == "Windows"
      assert result.os_version == "10"
      assert result.device_type == "desktop"
      assert result.device_name == "Opera on Windows"
    end

    test "parses legacy Opera format" do
      ua = "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.10.289 Version/12.02"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Opera"
      assert result.browser_version == "9.80"
      assert result.os_name == "Windows"
      assert result.os_version == "7"
      assert result.device_type == "desktop"
      assert result.device_name == "Opera on Windows"
    end
  end

  describe "parse/1 - Windows version detection" do
    test "detects Windows 10" do
      ua =
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)
      assert result.os_version == "10"
    end

    test "detects Windows 8.1" do
      ua =
        "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)
      assert result.os_version == "8.1"
    end

    test "detects Windows 8" do
      ua =
        "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)
      assert result.os_version == "8"
    end

    test "detects Windows 7" do
      ua =
        "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)
      assert result.os_version == "7"
    end
  end

  describe "parse/1 - device type detection" do
    test "detects tablet from iPad" do
      ua =
        "Mozilla/5.0 (iPad; CPU OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1"

      result = UserAgentParser.parse(ua)
      assert result.device_type == "tablet"
    end

    test "detects tablet from Android Tablet keyword" do
      ua =
        "Mozilla/5.0 (Linux; Android 13; SM-X906C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)
      # Without "Tablet" keyword in UA, this defaults to desktop
      # Real Android tablet UA would have "Tablet" in it
      assert result.device_type == "desktop"
    end

    test "detects mobile from iPhone" do
      ua =
        "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"

      result = UserAgentParser.parse(ua)
      assert result.device_type == "mobile"
    end

    test "detects mobile from iPod" do
      ua =
        "Mozilla/5.0 (iPod touch; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1"

      result = UserAgentParser.parse(ua)
      assert result.device_type == "mobile"
    end

    test "detects mobile from Android Mobile keyword" do
      ua =
        "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"

      result = UserAgentParser.parse(ua)
      assert result.device_type == "mobile"
    end

    test "defaults to desktop for unknown devices" do
      ua =
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

      result = UserAgentParser.parse(ua)
      assert result.device_type == "desktop"
    end
  end

  describe "parse/1 - unknown browsers" do
    test "handles unknown browser gracefully" do
      ua = "SomeWeirdBrowser/1.0"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Unknown"
      assert result.browser_version == nil
      assert result.os_name == "Unknown"
      assert result.os_version == nil
      assert result.device_type == "desktop"
      assert result.device_name == "Unknown on Unknown"
    end

    test "handles bot user agents" do
      ua = "Googlebot/2.1 (+http://www.google.com/bot.html)"

      result = UserAgentParser.parse(ua)

      assert result.browser_name == "Unknown"
      assert result.browser_version == nil
      assert result.os_name == "Unknown"
    end
  end
end
