defmodule Microwaveprop.BeaconMonitorsTest do
  use Microwaveprop.DataCase

  import Microwaveprop.AccountsFixtures

  alias Microwaveprop.BeaconMonitors
  alias Microwaveprop.BeaconMonitors.BeaconMonitor

  describe "create_monitor/2" do
    test "creates a monitor with a generated token" do
      user = user_fixture()

      assert {:ok, %BeaconMonitor{} = monitor} =
               BeaconMonitors.create_monitor(user, %{"name" => "Shack Pi"})

      assert monitor.user_id == user.id
      assert monitor.name == "Shack Pi"
      assert is_binary(monitor.token)
      # strong_rand_bytes(32) |> url_encode64(padding: false) is 43 chars
      assert String.length(monitor.token) == 43
    end

    test "generates a unique token per monitor" do
      user = user_fixture()
      {:ok, m1} = BeaconMonitors.create_monitor(user, %{"name" => "One"})
      {:ok, m2} = BeaconMonitors.create_monitor(user, %{"name" => "Two"})

      refute m1.token == m2.token
    end

    test "requires a name" do
      user = user_fixture()

      assert {:error, changeset} = BeaconMonitors.create_monitor(user, %{"name" => ""})
      assert %{name: ["can't be blank"]} = errors_on(changeset)
    end
  end

  describe "list_monitors_for_user/1" do
    test "returns monitors belonging to the user, newest first" do
      user = user_fixture()
      other = user_fixture()

      {:ok, first} = BeaconMonitors.create_monitor(user, %{"name" => "First"})
      Process.sleep(1100)
      {:ok, second} = BeaconMonitors.create_monitor(user, %{"name" => "Second"})
      {:ok, _other} = BeaconMonitors.create_monitor(other, %{"name" => "Nope"})

      assert [second_result, first_result] = BeaconMonitors.list_monitors_for_user(user)
      assert second_result.id == second.id
      assert first_result.id == first.id
    end

    test "returns empty list when user has no monitors" do
      user = user_fixture()
      assert BeaconMonitors.list_monitors_for_user(user) == []
    end
  end

  describe "delete_monitor/2" do
    test "deletes a monitor owned by the user" do
      user = user_fixture()
      {:ok, monitor} = BeaconMonitors.create_monitor(user, %{"name" => "Bye"})

      assert {:ok, %BeaconMonitor{}} = BeaconMonitors.delete_monitor(user, monitor.id)
      assert BeaconMonitors.list_monitors_for_user(user) == []
    end

    test "does not delete a monitor owned by another user" do
      user = user_fixture()
      other = user_fixture()
      {:ok, monitor} = BeaconMonitors.create_monitor(other, %{"name" => "Theirs"})

      assert {:error, :not_found} = BeaconMonitors.delete_monitor(user, monitor.id)
      assert [_] = BeaconMonitors.list_monitors_for_user(other)
    end

    test "returns :not_found for nonexistent id" do
      user = user_fixture()

      assert {:error, :not_found} =
               BeaconMonitors.delete_monitor(user, "11111111-1111-1111-1111-111111111111")
    end
  end

  describe "get_monitor_by_token/1" do
    test "returns the monitor matching the token" do
      user = user_fixture()
      {:ok, monitor} = BeaconMonitors.create_monitor(user, %{"name" => "Find Me"})

      found = BeaconMonitors.get_monitor_by_token(monitor.token)
      assert found.id == monitor.id
    end

    test "returns nil for unknown token" do
      refute BeaconMonitors.get_monitor_by_token("not-a-real-token")
    end
  end
end
