<?php
/**
 * Snooze Public API
 * =================
 *
 * Procedural extension API for the Snooze feature. These functions are
 * the supported PHP-side surface for theme overrides and external
 * plugins — the procedural counterpart to the `autoship_snooze_*`
 * filter and action hooks.
 *
 * Stability contract:
 *   - All functions in this file are part of the plugin's public API.
 *     Signatures, return types and side-effects are stable across minor
 *     releases. Breaking changes will follow a normal deprecation cycle.
 *   - Internal Snooze logic lives in `app/Domain/Snooze/`,
 *     `app/Services/Snooze/` and `app/Modules/Snooze/`. Plugin code
 *     should resolve the relevant interface from the service container
 *     instead of calling these functions.
 *
 * Container-availability fallback:
 *   Every function below guards against `Plugin::get_service_container()`
 *   returning null. That branch is only reachable during very early
 *   bootstrap (before `plugins_loaded`) or during uninstall, when the
 *   DI container has not been built. The fallback values are picked to
 *   be safe defaults — never to mask a runtime configuration bug.
 *
 * @package    Autoship
 * @subpackage Snooze\PublicApi
 * @since      2.13.0
 * @see        docs/snooze-public-api.md
 */

defined( 'ABSPATH' ) || exit;

// ===========================================================================
// Settings
// ===========================================================================

/**
 * Whether the Snooze feature is enabled in Autoship settings.
 *
 * @api
 * @since 2.13.0
 *
 * @return bool True when the merchant has enabled Snooze.
 */
function autoship_is_snooze_enabled() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return false;
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeSettingsInterface::class )->is_enabled();
}

/**
 * Merchant-configured label for the Snooze action (e.g. "Snooze", "Pause").
 *
 * @api
 * @since 2.13.0
 *
 * @return string The configured label.
 */
function autoship_get_snooze_action_label() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return 'Snooze';
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeSettingsInterface::class )->get_action_label();
}

/**
 * How Snooze interacts with the standard Pause action.
 *
 * @api
 * @since 2.13.0
 *
 * @return string Either "alongside" (Snooze appears next to Pause) or
 *                "instead" (Snooze replaces Pause).
 */
function autoship_get_snooze_pause_behavior() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return 'alongside';
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeSettingsInterface::class )->get_pause_behavior();
}

/**
 * Source for the snooze duration list shown to subscribers.
 *
 * @api
 * @since 2.13.0
 *
 * @return string Either "qmc" (fetched from QPilot CustomerPortalSettings)
 *                or "plugin" (the merchant-configured plugin defaults).
 */
function autoship_get_snooze_frequency_source() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return 'qmc';
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeSettingsInterface::class )->get_frequency_source();
}

/**
 * Whether subscribers may pick an arbitrary calendar date as their resume date.
 *
 * @api
 * @since 2.13.0
 *
 * @return bool True when custom dates are permitted by the merchant.
 */
function autoship_is_snooze_custom_date_allowed() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return false;
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeSettingsInterface::class )->is_custom_date_allowed();
}

/**
 * Merchant-configured cap on snooze duration, in days.
 *
 * @api
 * @since 2.13.0
 *
 * @return int Maximum snooze duration in days. `0` means no cap.
 */
function autoship_get_snooze_max_duration_days() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return 0;
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeSettingsInterface::class )->get_max_duration_days();
}

// ===========================================================================
// Order status helpers
// ===========================================================================

/**
 * Whether a scheduled order is in the composite snoozed state.
 *
 * Snooze is not a distinct backend status — it is the composite of
 * `status === "Paused"` AND a populated `snoozeUntilUtc` AND
 * `snoozeDuration > 0`. Templates and integrations should use this
 * helper rather than checking the status string directly.
 *
 * @api
 * @since 2.13.0
 *
 * @param object|array $order Scheduled order (object from the QPilot API
 *                            or array from a converted template payload).
 *
 * @return bool
 */
function autoship_is_order_snoozed( $order ) {
	return \Autoship\Domain\Snooze\SnoozeStatus::is_snoozed( $order );
}

/**
 * Format a snooze duration as a human-readable label.
 *
 * Examples: `(1, 'Weeks')` → `"1 Week"`; `(3, 'Months')` → `"3 Months"`.
 * The result passes through the `autoship_snooze_duration_label` filter.
 *
 * @api
 * @since 2.13.0
 *
 * @param int    $duration      The duration value.
 * @param string $duration_type The duration type: Days, Weeks, or Months.
 *
 * @return string
 */
function autoship_format_snooze_duration_label( $duration, $duration_type ) {
	$label = \Autoship\Domain\Snooze\SnoozeStatus::format_duration_label( (int) $duration, (string) $duration_type );

	return apply_filters( 'autoship_snooze_duration_label', $label, $duration, $duration_type );
}

/**
 * Calculate the UTC ISO 8601 resume date for a snooze of a given length.
 *
 * Mirrors the V2 Subscriber Portal calculation logic — Days/Weeks/Months
 * advance from "now" in the UTC timezone.
 *
 * @api
 * @since 2.13.0
 *
 * @param int    $duration      The duration value.
 * @param string $duration_type The duration type: Days, Weeks, or Months.
 *
 * @return string Resume date in `Y-m-d\TH:i:s\Z` format.
 */
function autoship_calculate_snooze_resume_date( $duration, $duration_type ) {
	return \Autoship\Domain\Snooze\SnoozeStatus::calculate_resume_date( (int) $duration, (string) $duration_type );
}

/**
 * Localised "Snoozed until [date]" text for a snoozed order.
 *
 * Returns an empty string when the order is not in the snoozed state, so
 * templates can safely echo the result unconditionally.
 *
 * @api
 * @since 2.13.0
 *
 * @param object|array $autoship_order Scheduled order.
 *
 * @return string Formatted text, or `''` when not snoozed.
 */
function autoship_get_snooze_until_text( $autoship_order ) {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return '';
	}
	return $container->get( \Autoship\Services\Snooze\Implementations\SnoozeActionFilters::class )->get_snooze_until_text( $autoship_order );
}

/**
 * Localised resume date for a snoozed order, without any surrounding text.
 *
 * Lets templates compose their own sentence around the date (e.g.
 * "Auto-resumes on …", "Will resume …") while keeping the date format
 * — `get_option( 'date_format' )` via `date_i18n()` — in one place.
 *
 * Returns an empty string when the order is not snoozed or the
 * `snoozeUntilUtc` value is unparseable.
 *
 * @api
 * @since 2.13.0
 *
 * @param object|array $autoship_order Scheduled order.
 *
 * @return string Localised resume date, or `''` when unavailable.
 */
function autoship_get_snooze_resume_date_formatted( $autoship_order ) {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return '';
	}
	return $container->get( \Autoship\Services\Snooze\Implementations\SnoozeActionFilters::class )->get_snooze_resume_date_formatted( $autoship_order );
}

// ===========================================================================
// Duration options
// ===========================================================================

/**
 * Plugin-default snooze frequency list.
 *
 * Returned by the resolver when the merchant has selected "plugin" as the
 * frequency source, or as a fallback when QMC returns nothing usable.
 *
 * @api
 * @since 2.13.0
 *
 * @return array<int, array<string, mixed>>
 */
function autoship_get_default_snooze_options() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return array();
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeOptionsProviderInterface::class )->get_default_options();
}

/**
 * Resolved snooze frequency list for the current site.
 *
 * Routes through the configured source (QMC or plugin), applies the
 * cache, and falls back to plugin defaults when QMC returns nothing.
 * The returned list passes through the `autoship_snooze_frequencies`
 * filter so callers can inject additional options.
 *
 * @api
 * @since 2.13.0
 *
 * @param bool $refresh Force a fresh fetch, bypassing the cache.
 *
 * @return array<int, array<string, mixed>>
 */
function autoship_get_snooze_options( $refresh = false ) {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return array();
	}
	$options = $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeOptionsProviderInterface::class )->get_options( (bool) $refresh );

	return apply_filters( 'autoship_snooze_frequencies', $options );
}

/**
 * Invalidate the cached QMC snooze frequencies for the current site.
 *
 * Call after writing settings that affect the QMC payload, or from
 * admin tooling that needs the next page load to refetch.
 *
 * @api
 * @since 2.13.0
 *
 * @return void
 */
function autoship_clear_snooze_options_cache() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return;
	}
	$container->get( \Autoship\Services\Snooze\Interfaces\SnoozeOptionsProviderInterface::class )->clear_cache();
}

// ===========================================================================
// QPilot feature flags
// ===========================================================================

/**
 * The merged global + site feature flag list returned by QPilot.
 *
 * @api
 * @since 2.13.0
 *
 * @return array<int, string>
 */
function autoship_get_site_feature_flags() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return array();
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeFeatureFlagsInterface::class )->get_flags();
}

/**
 * Whether the QPilot `enable-snooze` feature flag is set.
 *
 * Permissive default: returns `true` when the flag list cannot be
 * fetched, so a transient QPilot outage does not silently disable
 * Snooze for already-onboarded sites.
 *
 * @api
 * @since 2.13.0
 *
 * @return bool
 */
function autoship_is_qpilot_snooze_flag_enabled() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return true; // permissive default.
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeFeatureFlagsInterface::class )->is_snooze_flag_enabled();
}

/**
 * Whether QPilot definitively reports the `enable-snooze` flag as off.
 *
 * Distinguishes "fetch failed" from "fetch succeeded and flag is absent"
 * — used by the admin warning banner so we only nag merchants when we
 * are sure the flag is off, not when we couldn't ask.
 *
 * @api
 * @since 2.13.0
 *
 * @return bool
 */
function autoship_qpilot_snooze_flag_definitively_off() {
	$container = \Autoship\Core\Plugin::get_service_container();
	if ( null === $container ) {
		return false;
	}
	return $container->get( \Autoship\Services\Snooze\Interfaces\SnoozeFeatureFlagsInterface::class )->is_snooze_flag_definitively_off();
}
