<?php

/**
 * Heartbeat Control Module
 *
 * Controls WordPress heartbeat API frequency across admin, editor, and frontend
 * to reduce server load and improve admin performance.
 *
 * @package ProRank\SEO\Modules\Performance
 * @since   2.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Modules\Performance;

use ProRank\SEO\Modules\BaseModule;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}


/**
 * HeartbeatControlModule class
 *
 * Hooks into WordPress heartbeat API to throttle or disable the interval
 * based on user-configured settings. Reads from prorank_database_settings
 * via the unified BaseModule::get_setting() path.
 *
 * Settings used:
 *   heartbeat_control            (bool) – master toggle
 *   heartbeat_frequency          (int)  – legacy global default (15–600, 0 = disable)
 *   heartbeat_frequency_front    (int)  – frontend interval; falls back to global; 0 = disable
 *   heartbeat_frequency_admin    (int)  – admin (non-editor) interval; falls back to global; 0 = disable
 *   heartbeat_frequency_editor   (int)  – post editor interval; falls back to global; clamped to 15+ for autosave safety
 */


class HeartbeatControlModule extends BaseModule {

    /**
     * Required tier for this module
     */
    protected string $feature_tier = 'free';

    private const ZONE_FRONT  = 'front';
    private const ZONE_ADMIN  = 'admin';
    private const ZONE_EDITOR = 'editor';

    /**
     * Constructor
     */
    public function __construct() {
        $this->slug        = 'heartbeat_control';
        $this->name        = 'Heartbeat Control';
        $this->description = 'Control WordPress heartbeat API frequency to reduce server load';
        $this->parent_slug = 'performance';
    }

    /**
     * Initialize module hooks
     *
     * @return void
     */
    public function init_hooks(): void {
        if ( ! $this->is_heartbeat_control_enabled() ) {
            return;
        }

        add_filter( 'heartbeat_settings', [ $this, 'filter_heartbeat_interval' ] );
        add_action( 'init', [ $this, 'maybe_deregister_heartbeat' ], 1 );
    }

    /**
     * Apply the per-zone interval to the heartbeat settings.
     *
     * @param array $settings
     * @return array
     */
    public function filter_heartbeat_interval( array $settings ): array {
        $interval = $this->get_zone_interval( $this->current_zone() );

        if ( $interval > 0 ) {
            $settings['interval'] = max( 15, min( $interval, 600 ) );
        }

        return $settings;
    }

    /**
     * Deregister the heartbeat script when the current zone is set to 0.
     *
     * The editor zone is never deregistered – autosave + post locks depend on it.
     *
     * @return void
     */
    public function maybe_deregister_heartbeat(): void {
        $zone     = $this->current_zone();
        $interval = $this->get_zone_interval( $zone );

        if ( $interval !== 0 ) {
            return;
        }

        // Never disable heartbeat in the post editor – autosave + lock rely on it.
        if ( $zone === self::ZONE_EDITOR ) {
            return;
        }

        wp_deregister_script( 'heartbeat' );
    }

    /**
     * Detect which heartbeat zone the current request belongs to.
     *
     * @return string one of ZONE_FRONT, ZONE_ADMIN, ZONE_EDITOR
     */
    private function current_zone(): string {
        if ( ! is_admin() ) {
            return self::ZONE_FRONT;
        }

        global $pagenow;
        if ( in_array( $pagenow, [ 'post.php', 'post-new.php' ], true ) ) {
            return self::ZONE_EDITOR;
        }

        return self::ZONE_ADMIN;
    }

    /**
     * Resolve the interval for a zone, falling back to the legacy global setting.
     *
     * Editor zone is clamped to a minimum of 15 seconds so autosave keeps working
     * even if the user (or a migration) wrote a lower value.
     *
     * @param string $zone
     * @return int seconds, or 0 to disable
     */
    private function get_zone_interval( string $zone ): int {
        $global_default = (int) $this->get_setting( 'heartbeat_frequency', 60 );
        $key            = 'heartbeat_frequency_' . $zone;
        $raw            = $this->get_setting( $key, null );

        if ( $raw === null || $raw === '' ) {
            $value = $global_default;
        } else {
            $value = (int) $raw;
        }

        if ( $zone === self::ZONE_EDITOR && $value > 0 && $value < 15 ) {
            $value = 15;
        }

        return $value;
    }

    /**
     * Check if heartbeat control is enabled
     *
     * @return bool
     */
    private function is_heartbeat_control_enabled(): bool {
        $value = $this->get_setting( 'heartbeat_control', false );

        if ( is_string( $value ) ) {
            return in_array( strtolower( $value ), [ 'true', '1', 'yes', 'on' ], true );
        }

        return (bool) $value;
    }
}
