docs: public TimedPhase getNextTimedPhase(final DefaultSubscriptionBase subscription, final DateTime effectiveDate, final Catalog catalog, final InternalTenantContext context) {
  
          try {
              final SubscriptionBaseTransition pendingOrLastPlanTransition;
              if (subscription.getState() == EntitlementState.PENDING) {
                  pendingOrLastPlanTransition = subscription.getPendingTransition();
              } else {
                  pendingOrLastPlanTransition = subscription.getLastTransitionForCurrentPlan();
              }
  
              switch (pendingOrLastPlanTransition.getTransitionType()) {
                  // If we never had any Plan change, borrow the logic for createPlan alignment
                  case CREATE:
                  case TRANSFER:
                      final List<TimedPhase> timedPhases = getTimedPhaseOnCreate(subscription.getAlignStartDate(),
                                                                                 subscription.getBundleStartDate(),
                                                                                 pendingOrLastPlanTransition.getNextPlan(),
                                                                                 pendingOrLastPlanTransition.getNextPhase().getPhaseType(),
                                                                                 catalog,
                                                                                 // Use the catalog version at subscription creation time: this allows
                                                                                 // for PHASE events and uncancel operations for plans/products/pricelists already retired
                                                                                 // This is not 100% correct in a scenario where the catalog was updated and the alignment rules changed since
                                                                                 // See https://github.com/killbill/killbill/issues/784
                                                                                 subscription.getAlignStartDate(),
                                                                                 context);
                      return getTimedPhase(timedPhases, effectiveDate, WhichPhase.NEXT);
                  case CHANGE:
                      return getTimedPhaseOnChange(subscription.getAlignStartDate(),
                                                   subscription.getBundleStartDate(),
                                                   pendingOrLastPlanTransition.getPreviousPhase(),
                                                   pendingOrLastPlanTransition.getPreviousPlan(),
                                                   pendingOrLastPlanTransition.getNextPlan(),
                                                   effectiveDate,
                                                   // Same remark as above
                                                   subscription.getAlignStartDate(),
                                                   pendingOrLastPlanTransition.getEffectiveTransitionTime(),
                                                   subscription.getAllTransitions().get(0).getNextPhase().getPhaseType(),
                                                   null,
                                                   WhichPhase.NEXT,
                                                   catalog,
                                                   context);
                  default:
                      throw new SubscriptionBaseError(String.format("Unexpected initial transition %s for current plan %s on subscription %s",
                                                                    pendingOrLastPlanTransition.getTransitionType(), subscription.getCurrentPlan(), subscription.getId()));
              }
          } catch (Exception /* SubscriptionBaseApiException, CatalogApiException */ e) {
              throw new SubscriptionBaseError(String.format("Could not compute next phase change for subscription %s", subscription.getId()), e);
          }
      }