defmodule AprsmeWeb.UserResetPasswordLiveTest do
  use AprsmeWeb.ConnCase

  import Aprsme.AccountsFixtures
  import Phoenix.LiveViewTest

  alias Aprsme.Accounts

  setup do
    user = user_fixture()

    token =
      extract_user_token(fn url ->
        Accounts.deliver_user_reset_password_instructions(user, url)
      end)

    %{token: token, user: user}
  end

  describe "Reset password page" do
    test "renders reset password with valid token", %{conn: conn, token: token} do
      {:ok, _lv, html} = live(conn, ~p"/users/reset_password/#{token}", on_error: :warn)
      assert html =~ "Reset Password"
    end

    test "does not render reset password with invalid token", %{conn: conn} do
      {:error, {:redirect, to}} = live(conn, ~p"/users/reset_password/invalid", on_error: :warn)

      assert to == %{
               flash: %{"error" => "Reset password link is invalid or it has expired."},
               to: "/"
             }
    end

    test "validate event re-renders the form", %{conn: conn, token: token} do
      {:ok, lv, _html} = live(conn, ~p"/users/reset_password/#{token}", on_error: :warn)

      result =
        lv
        |> element("#reset_password_form")
        |> render_change(user: %{"password" => "secret12", "password_confirmation" => "secret123456"})

      # The validate event runs without raising and the form is re-rendered.
      assert result =~ "Reset Password"
    end
  end

  describe "Reset Password" do
    test "resets password once", %{conn: conn, token: token, user: user} do
      {:ok, lv, _html} = live(conn, ~p"/users/reset_password/#{token}", on_error: :warn)

      {:ok, conn} =
        lv
        |> form("#reset_password_form",
          user: %{
            "password" => "new valid password",
            "password_confirmation" => "new valid password"
          }
        )
        |> render_submit()
        |> follow_redirect(conn, ~p"/users/log_in")

      refute get_session(conn, :user_token)
      assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Password reset successfully"
      assert Accounts.get_user_by_email_and_password(user.email, "new valid password")
    end

    test "does not reset password on invalid data", %{conn: conn, token: token} do
      {:ok, lv, _html} = live(conn, ~p"/users/reset_password/#{token}", on_error: :warn)

      result =
        lv
        |> form("#reset_password_form",
          user: %{
            "password" => "too short",
            "password_confirmation" => "does not match"
          }
        )
        |> render_submit()

      # The template shows a generic "Oops, something went wrong!" banner when
      # the changeset action is :insert, rather than per-field errors.
      assert result =~ "Reset Password"
      assert result =~ "Oops, something went wrong!"
    end
  end
end
