require "test_helper"

class EntryRequestFlowTest < ActionDispatch::IntegrationTest
  test "complete flow: request -> admin approve -> user accepts -> entry active" do
    # Step 1: Public user submits entry request
    assert_difference([ "User.count", "Entry.count" ], 1) do
      post requests_path, params: {
        entry: {
          name: "Flow Test User",
          email: "flowtest@example.com",
          category: "word",
          fi: "testi",
          en: "test",
          notes: "Testing complete flow"
        }
      }
    end

    assert_redirected_to root_path
    follow_redirect!
    assert_response :success

    entry = Entry.last
    user = User.last

    assert_equal "requested", entry.status
    assert_equal user, entry.requested_by
    assert_nil user.invitation_token

    # Step 2: Admin reviews and approves request
    admin = users(:admin_user)
    login_as(admin)

    get admin_requests_path
    assert_response :success
    assert_select "td", text: entry.fi

    # View the request
    get admin_request_path(entry)
    assert_response :success
    assert_select "div", text: entry.fi

    # Approve the request
    assert_enqueued_emails 1 do
      post approve_admin_request_path(entry)
    end

    entry.reload
    user.reload

    assert_equal "approved", entry.status
    assert_not_nil user.invitation_token
    assert_not_nil user.invitation_sent_at
    assert_equal admin, user.invited_by

    # Verify the invitation email includes entry information
    perform_enqueued_jobs
    sent_email = ActionMailer::Base.deliveries.last
    assert_match "Your entry request has been approved", sent_email.subject
    assert_match entry.fi, sent_email.body.encoded
    assert_match entry.en, sent_email.body.encoded

    logout

    # Step 3: User accepts invitation
    get invitation_path(user.invitation_token)
    assert_response :success

    patch accept_invitation_path(user.invitation_token), params: {
      user: {
        password: "securepassword123",
        password_confirmation: "securepassword123"
      }
    }

    entry.reload
    user.reload

    # Entry should now be active
    assert_equal "active", entry.status
    assert_not_nil user.invitation_accepted_at
    assert_nil user.invitation_token
    assert_equal user.id, session[:user_id]

    # Step 4: Verify entry is visible on public site
    get root_path
    assert_response :success
    # Entry should be in search results
  end

  test "rejected request removes entry and user" do
    # Create a request
    post requests_path, params: {
      entry: {
        name: "To Be Rejected",
        email: "rejected@example.com",
        category: "word",
        fi: "hylätty",
        en: "rejected"
      }
    }

    assert_redirected_to root_path

    entry = Entry.last
    user = User.last
    entry_id = entry.id
    user_id = user.id

    # Admin rejects it
    login_as(users(:admin_user))

    assert_difference([ "User.count", "Entry.count" ], -1) do
      delete reject_admin_request_path(entry)
    end

    assert_not Entry.exists?(entry_id)
    assert_not User.exists?(user_id)
  end

  test "requested and approved entries not visible on public site" do
    requested = entries(:requested_entry)
    approved = entries(:approved_entry)
    active = entries(:one)

    get root_path
    assert_response :success

    # Active entry should be counted
    assert_select "div", text: "#{Entry.active_entries.count} entries"

    # Verify counts exclude requested/approved entries
    total_entries = Entry.count
    active_entries = Entry.active_entries.count

    assert total_entries > active_entries, "Should have non-active entries in fixtures"
  end

  test "multiple entries by same requester all activated on invitation acceptance" do
    # Create user with multiple approved entries
    user = User.create!(
      name: "Multi Entry User",
      email: "multi@example.com",
      password: SecureRandom.alphanumeric(32),
      role: :contributor,
      invitation_token: "multi_token_123",
      invitation_sent_at: 1.day.ago,
      invited_by: users(:admin_user)
    )

    entry1 = Entry.create!(
      category: :word,
      fi: "sana1",
      en: "word1",
      status: :approved,
      requested_by: user
    )

    entry2 = Entry.create!(
      category: :phrase,
      fi: "fraasi1",
      en: "phrase1",
      status: :approved,
      requested_by: user
    )

    # User accepts invitation
    patch accept_invitation_path("multi_token_123"), params: {
      user: {
        password: "securepassword123",
        password_confirmation: "securepassword123"
      }
    }

    entry1.reload
    entry2.reload

    assert_equal "active", entry1.status
    assert_equal "active", entry2.status
  end

  test "admin can edit entry details before approval" do
    # Create a request
    post requests_path, params: {
      entry: {
        name: "Needs Editing",
        email: "edit@example.com",
        category: "word",
        fi: "väärin kirjoitettu",
        en: "wrong spelling"
      }
    }

    assert_redirected_to root_path

    entry = Entry.last

    # Admin edits the entry
    login_as(users(:admin_user))

    get edit_admin_request_path(entry)
    assert_response :success

    patch admin_request_path(entry), params: {
      entry: {
        fi: "oikein kirjoitettu",
        en: "correct spelling",
        category: "phrase"
      }
    }

    entry.reload
    assert_equal "oikein kirjoitettu", entry.fi
    assert_equal "correct spelling", entry.en
    assert_equal "phrase", entry.category

    # Then approve with corrected details
    post approve_admin_request_path(entry)

    entry.reload
    assert_equal "approved", entry.status
    assert_equal "oikein kirjoitettu", entry.fi
  end

  test "cannot submit request with existing user email" do
    existing_user = users(:contributor_user)

    post requests_path, params: {
      entry: {
        name: "Test",
        email: existing_user.email,
        category: "word",
        fi: "test"
      }
    }

    assert_redirected_to login_path
    assert_match(/already exists/i, flash[:alert])
  end
end
