defmodule ToweropsWeb.UserSettingsLive.HelpersTest do
  use ExUnit.Case, async: true

  alias ToweropsWeb.UserSettingsLive.Helpers

  describe "current_session?/2" do
    test "returns true when session token matches current token" do
      session = %{user_token_id: "abc123"}
      assert Helpers.current_session?(session, "abc123")
    end

    test "returns false when session token does not match" do
      session = %{user_token_id: "abc123"}
      refute Helpers.current_session?(session, "different-token")
    end

    test "returns false when current token is nil" do
      session = %{user_token_id: "abc123"}
      refute Helpers.current_session?(session, nil)
    end

    test "returns true when both are nil" do
      session = %{user_token_id: nil}
      assert Helpers.current_session?(session, nil)
    end
  end

  describe "format_timestamp_in_timezone/2" do
    test "formats datetime in the given timezone" do
      {:ok, datetime} = DateTime.new(~D[2025-03-15], ~T[14:30:00], "Etc/UTC")
      result = Helpers.format_timestamp_in_timezone(datetime, "America/New_York")

      assert result =~ "Mar 15, 2025"
      assert result =~ "EDT" or result =~ "EST"
    end

    test "formats datetime in UTC with 24h default" do
      {:ok, datetime} = DateTime.new(~D[2025-06-20], ~T[08:15:00], "Etc/UTC")
      result = Helpers.format_timestamp_in_timezone(datetime, "Etc/UTC")

      assert result =~ "Jun 20, 2025"
      assert result =~ "08:15:00"
      assert result =~ "UTC"
    end

    test "formats datetime in 12h format when specified" do
      {:ok, datetime} = DateTime.new(~D[2025-06-20], ~T[08:15:00], "Etc/UTC")
      result = Helpers.format_timestamp_in_timezone(datetime, "Etc/UTC", "12h")

      assert result =~ "Jun 20, 2025"
      assert result =~ "08:15 AM"
      assert result =~ "UTC"
    end

    test "falls back to UTC for invalid timezone" do
      {:ok, datetime} = DateTime.new(~D[2025-01-10], ~T[12:00:00], "Etc/UTC")
      result = Helpers.format_timestamp_in_timezone(datetime, "Invalid/Zone")

      assert result =~ "Jan 10, 2025"
      assert result =~ "UTC"
    end

    test "formats PM times correctly in 24h format" do
      {:ok, datetime} = DateTime.new(~D[2025-12-25], ~T[23:45:00], "Etc/UTC")
      result = Helpers.format_timestamp_in_timezone(datetime, "Etc/UTC")

      assert result =~ "Dec 25, 2025"
      assert result =~ "23:45:00"
    end

    test "formats PM times correctly in 12h format" do
      {:ok, datetime} = DateTime.new(~D[2025-12-25], ~T[23:45:00], "Etc/UTC")
      result = Helpers.format_timestamp_in_timezone(datetime, "Etc/UTC", "12h")

      assert result =~ "Dec 25, 2025"
      assert result =~ "11:45 PM"
    end

    test "formats midnight correctly in 24h format" do
      {:ok, datetime} = DateTime.new(~D[2025-07-04], ~T[00:00:00], "Etc/UTC")
      result = Helpers.format_timestamp_in_timezone(datetime, "Etc/UTC")

      assert result =~ "Jul 04, 2025"
      assert result =~ "00:00:00"
    end
  end

  describe "format_browser_info/1" do
    test "returns device_name when browser_name is nil and device_name is set" do
      session = %{browser_name: nil, browser_version: nil, os_name: nil, device_name: "iPhone 15"}
      assert Helpers.format_browser_info(session) == "iPhone 15"
    end

    test "returns 'Unknown Browser' when browser_name and device_name are nil" do
      session = %{browser_name: nil, browser_version: nil, os_name: nil, device_name: nil}
      assert Helpers.format_browser_info(session) == "Unknown Browser"
    end

    test "returns browser name only when version and os are nil" do
      session = %{browser_name: "Firefox", browser_version: nil, os_name: nil, device_name: nil}
      assert Helpers.format_browser_info(session) == "Firefox"
    end

    test "returns browser with version when os is nil" do
      session = %{browser_name: "Chrome", browser_version: "120", os_name: nil, device_name: nil}
      assert Helpers.format_browser_info(session) == "Chrome 120"
    end

    test "returns browser on os when version is nil" do
      session = %{browser_name: "Safari", browser_version: nil, os_name: "macOS", device_name: nil}
      assert Helpers.format_browser_info(session) == "Safari on macOS"
    end

    test "returns browser version on os when all present" do
      session = %{
        browser_name: "Chrome",
        browser_version: "120",
        os_name: "Windows 11",
        device_name: nil
      }

      assert Helpers.format_browser_info(session) == "Chrome 120 on Windows 11"
    end

    test "prioritizes device_name over os/version when browser_name is nil" do
      session = %{
        browser_name: nil,
        browser_version: "1.0",
        os_name: "iOS",
        device_name: "iPad Pro"
      }

      assert Helpers.format_browser_info(session) == "iPad Pro"
    end
  end

  describe "format_location/1" do
    test "returns full location with city, state, and country" do
      record = %{city_name: "Portland", subdivision_1_name: "Oregon", country_name: "United States"}
      assert Helpers.format_location(record) == "Portland, Oregon, United States"
    end

    test "returns city and country when state is nil" do
      record = %{city_name: "London", subdivision_1_name: nil, country_name: "United Kingdom"}
      assert Helpers.format_location(record) == "London, United Kingdom"
    end

    test "returns country only when city and state are nil" do
      record = %{city_name: nil, subdivision_1_name: nil, country_name: "Japan"}
      assert Helpers.format_location(record) == "Japan"
    end

    test "returns 'Unknown Location' when all fields are nil" do
      record = %{city_name: nil, subdivision_1_name: nil, country_name: nil}
      assert Helpers.format_location(record) == "Unknown Location"
    end

    test "returns 'Unknown Location' for state only (no city or country)" do
      record = %{city_name: nil, subdivision_1_name: "California", country_name: nil}
      assert Helpers.format_location(record) == "Unknown Location"
    end

    test "returns 'Unknown Location' for city and state without country" do
      record = %{city_name: "Portland", subdivision_1_name: "Oregon", country_name: nil}
      assert Helpers.format_location(record) == "Unknown Location"
    end
  end

  describe "format_relative_time/1" do
    test "returns 'Just now' for times less than 60 seconds ago" do
      datetime = DateTime.utc_now()
      assert Helpers.format_relative_time(datetime) == "Just now"
    end

    test "returns 'Just now' for time 30 seconds ago" do
      datetime = DateTime.add(DateTime.utc_now(), -30, :second)
      assert Helpers.format_relative_time(datetime) == "Just now"
    end

    test "returns minutes ago for times between 60 seconds and 1 hour" do
      datetime = DateTime.add(DateTime.utc_now(), -300, :second)
      assert Helpers.format_relative_time(datetime) == "5 minutes ago"
    end

    test "returns 1 minutes ago for times just over 60 seconds" do
      datetime = DateTime.add(DateTime.utc_now(), -90, :second)
      assert Helpers.format_relative_time(datetime) == "1 minutes ago"
    end

    test "returns hours ago for times between 1 hour and 24 hours" do
      datetime = DateTime.add(DateTime.utc_now(), -7200, :second)
      assert Helpers.format_relative_time(datetime) == "2 hours ago"
    end

    test "returns days ago for times between 1 day and 7 days" do
      datetime = DateTime.add(DateTime.utc_now(), -259_200, :second)
      assert Helpers.format_relative_time(datetime) == "3 days ago"
    end

    test "returns formatted date for times older than 7 days" do
      {:ok, datetime} = DateTime.new(~D[2024-01-15], ~T[10:00:00], "Etc/UTC")
      result = Helpers.format_relative_time(datetime)
      assert result =~ "Jan 15, 2024"
    end
  end

  describe "login_method_info/1" do
    test "returns lock icon and 'Password' for password method" do
      assert Helpers.login_method_info("password") == {"hero-lock-closed", "Password"}
    end

    test "returns envelope icon and 'Magic Link' for magic_link method" do
      assert Helpers.login_method_info("magic_link") == {"hero-envelope", "Magic Link"}
    end

    test "returns phone icon and 'Mobile QR' for mobile_qr method" do
      assert Helpers.login_method_info("mobile_qr") == {"hero-device-phone-mobile", "Mobile QR"}
    end

    test "returns question mark icon and method string for unknown methods" do
      assert Helpers.login_method_info("sso") == {"hero-question-mark-circle", "sso"}
    end

    test "returns the raw method string as label for unknown methods" do
      assert Helpers.login_method_info("webauthn") == {"hero-question-mark-circle", "webauthn"}
    end
  end

  describe "pagination_range/2" do
    test "returns all pages when total is 7 or fewer" do
      assert Helpers.pagination_range(1, 5) == [1, 2, 3, 4, 5]
      assert Helpers.pagination_range(3, 7) == [1, 2, 3, 4, 5, 6, 7]
      assert Helpers.pagination_range(1, 1) == [1]
    end

    test "returns start-biased range when current page is near the start" do
      assert Helpers.pagination_range(1, 20) == [1, 2, 3, 4, 5, :ellipsis, 20]
      assert Helpers.pagination_range(3, 20) == [1, 2, 3, 4, 5, :ellipsis, 20]
      assert Helpers.pagination_range(4, 20) == [1, 2, 3, 4, 5, :ellipsis, 20]
    end

    test "returns end-biased range when current page is near the end" do
      assert Helpers.pagination_range(20, 20) == [1, :ellipsis, 16, 17, 18, 19, 20]
      assert Helpers.pagination_range(18, 20) == [1, :ellipsis, 16, 17, 18, 19, 20]
      assert Helpers.pagination_range(17, 20) == [1, :ellipsis, 16, 17, 18, 19, 20]
    end

    test "returns middle range with ellipsis on both sides" do
      assert Helpers.pagination_range(10, 20) == [1, :ellipsis, 9, 10, 11, :ellipsis, 20]
      assert Helpers.pagination_range(5, 10) == [1, :ellipsis, 4, 5, 6, :ellipsis, 10]
    end

    test "handles boundary between start and middle" do
      # Page 5 of 10 should be in the middle range
      assert Helpers.pagination_range(5, 10) == [1, :ellipsis, 4, 5, 6, :ellipsis, 10]
    end

    test "handles boundary between middle and end" do
      # Page 7 of 10 should be near the end
      assert Helpers.pagination_range(7, 10) == [1, :ellipsis, 6, 7, 8, 9, 10]
    end

    test "handles 8 total pages with page 1 selected" do
      assert Helpers.pagination_range(1, 8) == [1, 2, 3, 4, 5, :ellipsis, 8]
    end

    test "handles 8 total pages with page 8 selected" do
      assert Helpers.pagination_range(8, 8) == [1, :ellipsis, 4, 5, 6, 7, 8]
    end
  end
end
