Within the products/index template:
{if segment_2 == ""}
Display all top level product categories
CURRENT TEMPLATE IS /products/index - so would embed another template?
{if:elseif segment_3 == "entries"}
Lists the products within current category
{embed=products/entries}
{if:elseif segment_3 == "list"}
Lists the subcategories for any top level categories
{embed=products/list}
{if:elseif segment_2 == "detail"}
Shows the entry for the product
{embed=products/detail}
{if:else}
404!
{/if}
But, I would recommend that /products/details/XXX is an ugly URL for the customer and for SEO purposes. You can actually do away with this and assume the product url_title directly at segment_2, then rely on the {if no_results} tag to capture the 404. So from the above example, replace this:
{if:elseif segment_2 == "detail"}
Shows the entry for the product
{embed=products/detail}
{if:else}
404!
{/if}
...with just this:
{if:else}
Shows the entry for the product
{embed=products/detail}
{/if}
...and then in the products/details template:
{exp:channel:entries
status="not Closed"
channel="products"
dynamic="no"
url_title="{segment_2}"
require_entry="yes"
track_views="one"
disable="member_data|pagination"}
{if no_results}
EMBED YOUR 404 TEMPLATE HERE
{/if}
...
NOTE: An edit was made to the above answer stripping out quotes and curlies from the conditionals e.g. it was:
{if:elseif "{segment_3}" == "entries"}
So the amended answer is correct if you're using the latest version of
EE (possible v2.9 onwards), but historically with older versions I've
encountered numerous issues with conditional parsing if the segment or
value is not defined ( {if:elseif segment_3 == "entries"}
gets
parsed as {if:elseif == "entries"}
if segment_3 has no value and generates
parsing errors. Hence the need to wrap in quotes and define as EE variables.
You can be even more smart with the URLs and do away with all the identifier segments ("entries", "list" and "details"), where you utilise the no_results tag pair for product details, no results conditional assume the listing, then on the listing detect if it's a top level category or sub category, or if it's a no result, then display 404. If you decide on this path, you'll probably need low2seg and GW Code Has Children.