defmodule Towerops.MobileSessions.MobileSessionTest do
  use Towerops.DataCase

  alias Towerops.MobileSessions.MobileSession

  describe "create_changeset/2" do
    test "valid changeset with just user_id" do
      attrs = %{user_id: Ecto.UUID.generate()}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      assert changeset.valid?
    end

    test "auto-generates token when not provided" do
      attrs = %{user_id: Ecto.UUID.generate()}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)
      token = get_field(changeset, :token)

      assert token
      assert is_binary(token)
      assert String.length(token) > 0
    end

    test "does not override provided token" do
      attrs = %{user_id: Ecto.UUID.generate(), token: "my-custom-token"}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      assert get_field(changeset, :token) == "my-custom-token"
    end

    test "auto-generates expires_at approximately 90 days from now" do
      now = DateTime.utc_now()
      attrs = %{user_id: Ecto.UUID.generate()}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)
      expires_at = get_field(changeset, :expires_at)

      assert expires_at

      diff_seconds = DateTime.diff(expires_at, now, :second)
      expected_seconds = 90 * 24 * 60 * 60
      assert_in_delta diff_seconds, expected_seconds, 60
    end

    test "auto-generates last_used_at approximately now" do
      now = DateTime.utc_now()
      attrs = %{user_id: Ecto.UUID.generate()}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)
      last_used_at = get_field(changeset, :last_used_at)

      assert last_used_at

      diff_seconds = abs(DateTime.diff(last_used_at, now, :second))
      assert_in_delta diff_seconds, 0, 60
    end

    test "does not override provided expires_at" do
      custom_expires_at =
        DateTime.utc_now() |> DateTime.add(30, :day) |> DateTime.truncate(:second)

      attrs = %{user_id: Ecto.UUID.generate(), expires_at: custom_expires_at}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      assert DateTime.compare(get_field(changeset, :expires_at), custom_expires_at) == :eq
    end

    test "requires user_id" do
      attrs = %{}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      refute changeset.valid?
      assert %{user_id: ["can't be blank"]} = errors_on(changeset)
    end

    test "validates push_platform accepts apns" do
      attrs = %{user_id: Ecto.UUID.generate(), push_platform: "apns"}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      assert changeset.valid?
      assert get_field(changeset, :push_platform) == "apns"
    end

    test "validates push_platform accepts fcm" do
      attrs = %{user_id: Ecto.UUID.generate(), push_platform: "fcm"}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      assert changeset.valid?
      assert get_field(changeset, :push_platform) == "fcm"
    end

    test "validates push_platform accepts nil" do
      attrs = %{user_id: Ecto.UUID.generate(), push_platform: nil}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      assert changeset.valid?
    end

    test "validates push_platform rejects invalid values" do
      attrs = %{user_id: Ecto.UUID.generate(), push_platform: "invalid"}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      refute changeset.valid?
      assert %{push_platform: ["is invalid"]} = errors_on(changeset)
    end

    test "accepts device_name, device_os, and app_version" do
      attrs = %{
        user_id: Ecto.UUID.generate(),
        device_name: "iPhone 15 Pro",
        device_os: "iOS 17.2",
        app_version: "1.0.0"
      }

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      assert changeset.valid?
      assert get_field(changeset, :device_name) == "iPhone 15 Pro"
      assert get_field(changeset, :device_os) == "iOS 17.2"
      assert get_field(changeset, :app_version) == "1.0.0"
    end

    test "defaults alerts_enabled to true" do
      attrs = %{user_id: Ecto.UUID.generate()}

      changeset = MobileSession.create_changeset(%MobileSession{}, attrs)

      assert get_field(changeset, :alerts_enabled) == true
    end
  end

  describe "touch_changeset/1" do
    test "updates last_used_at to approximately now" do
      now = DateTime.utc_now()

      session = %MobileSession{
        last_used_at: DateTime.utc_now() |> DateTime.add(-1, :day) |> DateTime.truncate(:second)
      }

      changeset = MobileSession.touch_changeset(session)
      last_used_at = get_field(changeset, :last_used_at)

      assert last_used_at

      diff_seconds = abs(DateTime.diff(last_used_at, now, :second))
      assert_in_delta diff_seconds, 0, 60
    end
  end
end
