<?php
/**
 * REST API Network Dashboard Controller.
 *
 * @package NimblyMail\SMTP
 *
 * @since 1.0.0
 */

namespace NimblyMail\SMTP\Rest\Network;

use NimblyMail\SMTP\Network\StatsAggregator;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;

defined( 'ABSPATH' ) || exit;

/**
 * Class NetworkDashboardController
 *
 * Provides aggregated email statistics across all sites on the network. The
 * controller itself never iterates every blog: StatsAggregator computes
 * stats inline for small networks or via a chunked Action Scheduler job for
 * large ones, and this controller only ever reads or triggers that
 * aggregation. StatsAggregator also owns the cache transient's key and both
 * of its durations; they are only ever read here, keeping the dependency
 * one-way.
 *
 * @since 1.0.0
 * @since 1.0.4 Delegated computation to StatsAggregator instead of running
 *              an unbounded per-site loop inline; responses now include a
 *              `status` field ('ready'|'refreshing'|'background_unavailable').
 */
class NetworkDashboardController extends AbstractNetworkController {

    /**
     * Register the REST routes.
     *
     * @since 1.0.0
     *
     * @return void
     */
    protected function do_register_routes(): void {
        register_rest_route(
            self::NAMESPACE,
            '/network/dashboard',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_stats' ),
                    'permission_callback' => array( $this, 'permissions_check' ),
                    'args'                => array(
                        'refresh' => array(
                            'type'    => 'integer',
                            'default' => 0,
                        ),
                    ),
                ),
            )
        );

        register_rest_route(
            self::NAMESPACE,
            '/network/dashboard/widgets',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_widgets' ),
                    'permission_callback' => array( $this, 'permissions_check' ),
                ),
            )
        );
    }

    /**
     * Get extension widgets for the network dashboard.
     *
     * Same descriptor shape as DashboardController::get_widgets() — see that
     * method's docblock for the full field reference. Filter name differs so
     * Pro can distinguish single-site vs. network context.
     *
     * @since 1.0.0
     *
     * @return WP_REST_Response
     */
    public function get_widgets(): WP_REST_Response {
        /**
         * Filters the list of widgets rendered on the network dashboard.
         *
         * Pro add-ons hook this filter to inject network-aware widgets.
         *
         * @since 1.0.0
         *
         * @param array                      $widgets    Numerically-indexed list of widget descriptors.
         * @param NetworkDashboardController $controller The controller instance.
         */
        $widgets = apply_filters( 'nimblymail_network_dashboard_widgets', array(), $this );
        return new WP_REST_Response( array( 'widgets' => array_values( (array) $widgets ) ) );
    }

    /**
     * Get aggregated network-wide email statistics.
     *
     * A cached snapshot is served as-is while fresh; once stale (or on
     * ?refresh=1, or with no cache at all) a recompute is triggered.
     * Networks at or under StatsAggregator::FAST_PATH_THRESHOLD sites are
     * aggregated synchronously (`status: 'ready'`); larger networks trigger
     * (or let continue) the chunked Action Scheduler job and get back the
     * last-known snapshot — stale beats blank — or an empty shape on a true
     * cold start, with `status: 'refreshing'`. If Action Scheduler is
     * unavailable, `status: 'background_unavailable'` is returned instead,
     * since nothing would ever flip it back to 'refreshing' on its own.
     *
     * @since 1.0.0
     * @since 1.0.4 Delegated computation to StatsAggregator; response now
     *              includes a `status` field and never blocks on the full
     *              per-site loop for large networks.
     *
     * @param WP_REST_Request $request The REST request.
     *
     * @return WP_REST_Response
     */
    public function get_stats( WP_REST_Request $request ): WP_REST_Response {
        $refresh = (bool) $request->get_param( 'refresh' );

        $cached    = get_site_transient( StatsAggregator::TRANSIENT_KEY );
        $has_cache = is_array( $cached );

        $is_stale = $refresh || ! $has_cache
            || ! isset( $cached['cached_until'] ) || time() >= (int) $cached['cached_until'];

        if ( ! $is_stale ) {
            $cached['status'] = StatsAggregator::is_running() ? 'refreshing' : 'ready';
            return new WP_REST_Response( $cached );
        }

        $total_sites = (int) get_sites( array( 'count' => true ) );

        if ( $total_sites <= StatsAggregator::FAST_PATH_THRESHOLD ) {
            $data = StatsAggregator::compute_now();
            StatsAggregator::store_snapshot( $data );
            $data['status'] = 'ready';
            return new WP_REST_Response( $data );
        }

        $background_active = StatsAggregator::start_or_continue();

        $data           = $has_cache ? $cached : StatsAggregator::empty_snapshot();
        $data['status'] = $background_active ? 'refreshing' : 'background_unavailable';

        return new WP_REST_Response( $data );
    }
}
