Override global query results without hooks

It is quite hard to understand what you need to do here, but you need to look at the following

  • Do not use the global variables as local variables, it breaks the global variables and causes issues with the loop. It is also quite hard to debug when you run into issues. The only global variable that should be used as a local variable is when you work with setup_postdata(). setup_postdata() requires the $post global. You just need to remember to reset the $post global afterwards.

  • Use the actions and filters available inside WP_Query to change the result from a specific query object

In general, the $post_count property is calculated from the amount of posts inside $posts. Just before posts are counted, we get the the_posts filter. This allows us to add/remove post objects (or rearrange the post order) from the $posts array. Any alteration here in the amount of posts will result in the `$post_count property being altered

Here is the relevant code from the WP_Query class

if ( ! $q['suppress_filters'] ) {
    /**
     * Filter the array of retrieved posts after they've been fetched and
     * internally processed.
     *
     * @since 1.5.0
     *
     * @param array    $posts The array of retrieved posts.
     * @param WP_Query &$this The WP_Query instance (passed by reference).
     */
    $this->posts = apply_filters_ref_array( 'the_posts', array( $this->posts, &$this ) );
}
// Ensure that any posts added/modified via one of the filters above are
// of the type WP_Post and are filtered.
if ( $this->posts ) {
    $this->post_count = count( $this->posts );
    $this->posts = array_map( 'get_post', $this->posts );
    if ( $q['cache_results'] )
        update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
    $this->post = reset( $this->posts );
} else {
    $this->post_count = 0;
    $this->posts = array();
}

If you want to add a post into the array of posts returned, this will be the place to do it

add_filter( 'the_posts', function ( $posts, \WP_Query $q )
{
    if ( !$q->is_main_query ) // Only target the main query, return if not. Add any additional conditions
        return $posts;

    $post_to_add = [
        // Valid post properties
    ]; 

    $post_to_add = array_map( 'get_post', $post_to_add );

    // Add some checks to make sure our $post_to_inject is a valid.

    // Add $post_to_add in front of $posts array
    $posts = array_merge( $post_to_add, $posts );

    // If you need to replace $posts with your object
    //$posts = [$post_to_add];

    return $posts;
}, 10, 2 );

$post gets set from the first post in the $posts array, so there is also no need to fiddle with that.

As for $found_posts you can make use of the found_posts filter to adjust the amount of posts found

add_filter( 'found_posts', function ( $found_posts, \WP_Query $q )
{
        if ( !$q->is_main_query ) // Only target the main query, return if not. Add any additional conditions
            return $found_posts;

    $found_posts = 1; // Taken info from your question

    return $found_posts;
}):    

As I said, I’m not particulary sure what you need to do, but I hope I did touch the point you are after