defmodule Towerops.MobileSessions.QRLoginTokenTest do
  use Towerops.DataCase

  alias Towerops.MobileSessions.QRLoginToken

  describe "create_changeset/2" do
    test "valid changeset with user_id auto-generates token and expires_at" do
      attrs = %{user_id: Ecto.UUID.generate()}

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

      assert changeset.valid?
      assert get_field(changeset, :token)
      assert get_field(changeset, :expires_at)
    end

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

      changeset = QRLoginToken.create_changeset(%QRLoginToken{}, 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: "custom-token"
      }

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

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

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

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

      assert expires_at

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

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

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

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

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

    test "requires user_id" do
      attrs = %{}

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

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

    test "token is a non-empty string" do
      attrs = %{user_id: Ecto.UUID.generate()}

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

      assert is_binary(token)
      assert byte_size(token) > 0
    end
  end

  describe "complete_changeset/2" do
    test "sets completed_at to approximately now" do
      now = DateTime.utc_now()
      mobile_session_id = Ecto.UUID.generate()

      changeset = QRLoginToken.complete_changeset(%QRLoginToken{}, mobile_session_id)
      completed_at = get_field(changeset, :completed_at)

      assert completed_at

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

    test "sets mobile_session_id" do
      mobile_session_id = Ecto.UUID.generate()

      changeset = QRLoginToken.complete_changeset(%QRLoginToken{}, mobile_session_id)

      assert get_field(changeset, :mobile_session_id) == mobile_session_id
    end
  end
end
