Future post ID not showing

The problem is that you are using get_the_ID() outside the loop. Also, you are getting the global $post overriding the $post object passed to the function and then overriding it again with get_post() function. As you have already the $post object which status has changed, you need nothing of the get_the_ID, get_post or global $post. Just use the $post object you already have.

add_action( 'transition_post_status', 'status_changes', 100, 3 );
function status_changes( $new_status, $old_status, $post ) {

    if ($new_status == 'publish') {

        $post_title = $post->post_title;
        $author = get_userdata($post->post_author);
        $link = get_permalink($post->ID);
        $date = mysql2date('M j Y', $post->post_date);
        $category = get_the_category($post->ID);
        $category = $category[0]->cat_name;

        $to = "//left blank to void out email";
        $subject = $post_title;
        $message = "<br><h1> schedulenotificte </h1></br> Let's begin: author " . //$author .
            " the link? " . $link;
        wp_mail( $to, $subjet, $message);
     }


}