How do you approach a query that needs several layers of logic at once?
Decompose it by grain. Every layer of a query operates at a row granularity, and the most common cause of a wrong answer is a mismatch between the grain of one layer and the next. Start by writing down, in one sentence, what one row of the final output represents — "one row per customer per status" — and then work backwards from there.
The standard layers are: filter rows, join to add columns, aggregate to a grain, filter the aggregates, and finally reshape or rank. Each layer changes the number of rows, so the order is not arbitrary. Filters that can apply to raw rows should be applied before the aggregation, because they change what the aggregates mean. Filters on aggregates have to come after. Joins that multiply rows must come before any aggregate you do not want inflated, or after it if you aggregate in a derived table first.
Three habits make this concrete. First, build and check one layer at a time — run the query without the final ORDER BY and look at the row count at each stage, because a row count that surprises you is the earliest signal that a join fanned out. Second, name every intermediate result, whether with a CTE or a derived table, because an unnamed nested subquery is where grain mistakes hide. Third, keep the raw and the derived columns in the output while you are debugging, so you can see which value came from where.
And when a query is genuinely hard, decompose it into two queries. Compute the aggregate in one, then filter or join it in another. The two-step version is not a compromise — it is usually the answer, because it lets you check the intermediate numbers against a source of truth before you trust the final output.