require "test_helper"

class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
  setup do
    @user = users(:admin_user)
    @user.update!(invitation_accepted_at: Time.current)
  end

  # NEW tests
  test "should get new" do
    get new_password_reset_url
    assert_response :success
  end

  test "should show password reset form" do
    get new_password_reset_url
    assert_select "form"
    assert_select "input[type=email]"
  end

  # CREATE tests
  test "should send reset email for existing user" do
    assert_enqueued_emails 1 do
      post password_resets_url, params: { email: @user.email }
    end
    assert_redirected_to login_url
    assert_match /password reset instructions/i, flash[:notice]
  end

  test "should generate reset token for existing user" do
    post password_resets_url, params: { email: @user.email }
    @user.reload
    assert_not_nil @user.reset_password_token
    assert_not_nil @user.reset_password_sent_at
  end

  test "should handle non-existent email gracefully" do
    post password_resets_url, params: { email: "nonexistent@example.com" }
    assert_redirected_to login_url
    assert_match /if that email address is in our system/i, flash[:notice]
  end

  test "should send invitation for user without accepted invitation" do
    pending_user = users(:pending_invitation)
    assert_nil pending_user.invitation_accepted_at

    assert_enqueued_emails 1 do
      post password_resets_url, params: { email: pending_user.email }
    end
    assert_redirected_to login_url
  end

  test "should handle blank email" do
    post password_resets_url, params: { email: "" }
    assert_redirected_to login_url
  end

  test "should handle email with whitespace" do
    post password_resets_url, params: { email: "  #{@user.email}  " }
    @user.reload
    assert_not_nil @user.reset_password_token
  end

  # EDIT tests
  test "should show reset password form with valid token" do
    @user.update!(
      reset_password_token: SecureRandom.urlsafe_base64(32),
      reset_password_sent_at: Time.current
    )
    get edit_password_reset_url(@user.reset_password_token)
    assert_response :success
    assert_select "form"
    assert_select "input[type=password]", count: 2
  end

  test "should reject invalid token" do
    get edit_password_reset_url("invalid_token")
    assert_redirected_to login_url
    assert_match /invalid/i, flash[:alert]
  end

  test "should reject expired token" do
    @user.update!(
      reset_password_token: SecureRandom.urlsafe_base64(32),
      reset_password_sent_at: 2.hours.ago
    )
    get edit_password_reset_url(@user.reset_password_token)
    assert_redirected_to new_password_reset_url
    assert_match /expired/i, flash[:alert]
  end

  # UPDATE tests
  test "should reset password with valid token" do
    @user.update!(
      reset_password_token: SecureRandom.urlsafe_base64(32),
      reset_password_sent_at: Time.current
    )

    patch password_reset_url(@user.reset_password_token), params: {
      password: "newpassword12345",
      password_confirmation: "newpassword12345"
    }

    assert_redirected_to root_url
    assert_match /password has been reset/i, flash[:notice]

    @user.reload
    assert_nil @user.reset_password_token
    assert_nil @user.reset_password_sent_at
    assert @user.authenticate("newpassword12345")
  end

  test "should auto-login after successful password reset" do
    @user.update!(
      reset_password_token: SecureRandom.urlsafe_base64(32),
      reset_password_sent_at: Time.current
    )

    patch password_reset_url(@user.reset_password_token), params: {
      password: "newpassword12345",
      password_confirmation: "newpassword12345"
    }

    assert_equal @user.id, session[:user_id]
  end

  test "should reject mismatched passwords" do
    @user.update!(
      reset_password_token: SecureRandom.urlsafe_base64(32),
      reset_password_sent_at: Time.current
    )

    patch password_reset_url(@user.reset_password_token), params: {
      password: "newpassword12345",
      password_confirmation: "differentpassword"
    }

    assert_response :unprocessable_entity
    assert_match /doesn't match/i, flash[:alert]
  end

  test "should reject blank password" do
    @user.update!(
      reset_password_token: SecureRandom.urlsafe_base64(32),
      reset_password_sent_at: Time.current
    )

    patch password_reset_url(@user.reset_password_token), params: {
      password: "",
      password_confirmation: ""
    }

    assert_response :unprocessable_entity
    assert_match /cannot be blank/i, flash[:alert]
  end

  test "should reject expired token on update" do
    @user.update!(
      reset_password_token: SecureRandom.urlsafe_base64(32),
      reset_password_sent_at: 2.hours.ago
    )

    patch password_reset_url(@user.reset_password_token), params: {
      password: "newpassword12345",
      password_confirmation: "newpassword12345"
    }

    assert_redirected_to new_password_reset_url
    assert_match /expired/i, flash[:alert]
  end

  test "should reject invalid token on update" do
    patch password_reset_url("invalid_token"), params: {
      password: "newpassword12345",
      password_confirmation: "newpassword12345"
    }

    assert_redirected_to login_url
    assert_match /invalid/i, flash[:alert]
  end

  test "should enforce password validations" do
    @user.update!(
      reset_password_token: SecureRandom.urlsafe_base64(32),
      reset_password_sent_at: Time.current
    )

    # Password too short (less than 12 characters)
    patch password_reset_url(@user.reset_password_token), params: {
      password: "short",
      password_confirmation: "short"
    }

    assert_response :unprocessable_entity
  end
end
