Insert post ID into the end of a slug preceeded by a dash

The rewrite argument in register_post_type is limited, but you can define a more complex structure with add_permastruct. The added benefits are that this will generate all the rewrite rules for you, and the new rules will overwrite the originals. You just have to be sure to hook after the post type is registered.

function wpd_woo_product_permastruct(){
    add_permastruct(
        'product',
        '%product_cat%/%product%-%post_id%/',
        array(
            'walk_dirs' => false,
            'with_front' => false
        )
    );
}
add_action( 'init', 'wpd_woo_product_permastruct', 99 );

And that is, magically, all you need. The rewrite tag replacements will be done for you, so the post_type_link filter won’t be needed.

Normally, the absence of a static slug would cause clashes with other rules, but in this case it works because the embedded post ID triggers a more strict match.

What you can’t have is the %product_cat% rules without a static slug, which is why we have to set walk_dirs to false. Otherwise, any request for a root page will be overridden by the taxonomy rule, and WordPress will go looking for a term that matches your page slug.

If you do want rules that introduce this ambiguity, you can do something like this answer, where you manually resolve conflicts.