<?php
/**
 * Maintenance Mode Module
 *
 * Enable Coming Soon, Maintenance, Staging or Development mode for your site.
 *
 * @package BlaminhorEssentials
 */

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Maintenance module class
 */
class Blaminhor_Essentials_Module_Maintenance extends Blaminhor_Essentials_Module {

    /**
     * Module ID
     *
     * @var string
     */
    protected $id = 'maintenance';

    /**
     * Module name
     *
     * @var string
     */
    protected $name = 'Coming soon / Maintenance';

    /**
     * Initialize module
     */
    protected function init() {
        // Note: Strings are translated in the base class get_name() and get_description() methods.
        $this->name        = 'Coming soon / Maintenance';
        $this->description = 'Enable Coming Soon or Maintenance mode for your site.';
    }

    /**
     * Get default settings
     *
     * @return array
     */
    protected function get_default_settings() {
        return array(
            'enabled'           => false,
            'mode'              => 'maintenance',
            'title'             => '',
            'headline'          => '',
            'message'           => '',
            'bg_color'          => '#f1f1f1',
            'text_color'        => '#444444',
            'bypass_roles'      => array( 'administrator' ),
            'bypass_ips'        => '',
            'show_login_link'   => true,
            'logo_id'           => 0,
            'countdown_target'  => '',
            'end_time'          => '',
            'contact_shortcode' => '',
            'signup_shortcode'  => '',
            'live_site_url'     => '',
        );
    }

    /**
     * Available modes with their metadata.
     *
     * @return array
     */
    private function get_modes() {
        return array(
            'maintenance' => array(
                'label'       => __( 'Maintenance Mode', 'blaminhor-essentials' ),
                'description' => __( 'For temporary downtime during updates or fixes.', 'blaminhor-essentials' ),
                'http_status' => 503,
                'badge'       => __( 'Maintenance Mode Active', 'blaminhor-essentials' ),
                'headline'    => __( 'Maintenance in Progress', 'blaminhor-essentials' ),
                'message'     => __( "This site is temporarily unavailable due to scheduled maintenance.\n\nPlease check back shortly.", 'blaminhor-essentials' ),
            ),
            'coming_soon' => array(
                'label'       => __( 'Coming Soon Mode', 'blaminhor-essentials' ),
                'description' => __( 'For new sites not yet ready to launch.', 'blaminhor-essentials' ),
                'http_status' => 503,
                'badge'       => __( 'Coming Soon Mode Active', 'blaminhor-essentials' ),
                'headline'    => __( 'Something New is Coming', 'blaminhor-essentials' ),
                'message'     => __( "We are preparing a new experience for this site.\n\nPlease check back soon for updates and launch information.", 'blaminhor-essentials' ),
            ),
            'staging'     => array(
                'label'       => __( 'Staging Mode', 'blaminhor-essentials' ),
                'description' => __( 'For preview environments shared with clients or internal reviewers.', 'blaminhor-essentials' ),
                'http_status' => 200,
                'badge'       => __( 'Staging Mode Active', 'blaminhor-essentials' ),
                'headline'    => __( 'Project Preview Portal', 'blaminhor-essentials' ),
                'message'     => __( "This is a preview environment for reviewing active development work.\n\nPlease review functionality and content before production release.\n\nChanges may occur without notice.", 'blaminhor-essentials' ),
            ),
            'development' => array(
                'label'       => __( 'Development Mode', 'blaminhor-essentials' ),
                'description' => __( 'For internal development environments with restricted visibility.', 'blaminhor-essentials' ),
                'http_status' => 200,
                'badge'       => __( 'Development Mode Active', 'blaminhor-essentials' ),
                'headline'    => __( 'Development Environment', 'blaminhor-essentials' ),
                'message'     => __( "This site is currently under active development.\n\nFeatures, content, and functionality may change without notice.\n\nAccess is intended for authorized users only.", 'blaminhor-essentials' ),
            ),
        );
    }

    /**
     * Get the currently selected mode definition (with fallback).
     *
     * @return array
     */
    private function get_current_mode() {
        $modes = $this->get_modes();
        $mode  = $this->get_setting( 'mode', 'maintenance' );
        return isset( $modes[ $mode ] ) ? $modes[ $mode ] : $modes['maintenance'];
    }

    /**
     * Register hooks
     */
    protected function register_hooks() {
        // Admin hooks.
        add_action( 'admin_init', array( $this, 'handle_settings_submission' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );

        // Sync the cross-module cache-bypass sentinel whenever the maintenance
        // setting is toggled, so the cache drop-in can stop serving stale HTML
        // the moment maintenance mode is flipped on (or resume serving it the
        // moment it is flipped off). The sentinel itself is a zero-byte flag
        // checked by the drop-in via file_exists().
        add_action(
            'update_option_blaminhor_essentials_module_maintenance',
            array( $this, 'sync_cache_bypass_sentinel' ),
            10,
            2
        );

        // Only check maintenance mode if enabled, OR if an admin is asking
        // for a ?be_preview=<mode> tour (lets them see what visitors will get
        // without flipping the switch for the whole site).
        if ( $this->get_setting( 'enabled', false ) || $this->get_preview_mode() ) {
            add_action( 'template_redirect', array( $this, 'maybe_show_maintenance_page' ), 1 );
            add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_notice' ), 100 );
            // Make sure the sentinel exists at boot too, in case it was missed
            // (e.g. setting was set programmatically without firing the hook).
            $this->sync_cache_bypass_sentinel();
        }
    }

    /**
     * Admin-only preview mechanism. When an admin opens the front-end with
     * `?be_preview=<mode>` we force-render the maintenance page using that
     * mode, regardless of the "Enable" toggle and without bypass logic. Used
     * to spot-check headlines / messages / countdown / shortcode rendering
     * before activating the mode for real visitors.
     *
     * @return string Validated mode key, or '' if no preview was requested.
     */
    private function get_preview_mode() {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only preview dispatch, capability-gated below.
        if ( empty( $_GET['be_preview'] ) ) {
            return '';
        }
        if ( ! is_user_logged_in() || ! current_user_can( 'manage_options' ) ) {
            return '';
        }
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only preview dispatch.
        $requested = sanitize_key( wp_unslash( $_GET['be_preview'] ) );
        return array_key_exists( $requested, $this->get_modes() ) ? $requested : '';
    }

    /**
     * Write or remove the .maintenance sentinel file used by the Cache module's
     * advanced-cache.php drop-in to bypass the cache while maintenance mode is
     * active. Idempotent and silent.
     *
     * @param mixed $old_value Unused (signature for update_option_*).
     * @param mixed $new_value Unused.
     */
    public function sync_cache_bypass_sentinel( $old_value = null, $new_value = null ) {
        $upload = wp_get_upload_dir();
        if ( empty( $upload['basedir'] ) ) {
            return;
        }
        $dir      = trailingslashit( $upload['basedir'] ) . 'blaminhor-essentials/cache';
        $sentinel = $dir . '/.maintenance';
        $enabled  = ! empty( $this->get_setting( 'enabled', false ) );

        if ( $enabled ) {
            if ( ! is_dir( $dir ) ) {
                wp_mkdir_p( $dir );
            }
            if ( ! file_exists( $sentinel ) ) {
                @file_put_contents( $sentinel, (string) time() );
            }
        } elseif ( file_exists( $sentinel ) ) {
            wp_delete_file( $sentinel );
        }
    }

    /**
     * Check if current user should bypass maintenance mode
     *
     * @return bool
     */
    private function should_bypass() {
        // Always allow AJAX, Cron, CLI.
        if ( wp_doing_ajax() || wp_doing_cron() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
            return true;
        }

        // Allow login page.
        if ( $this->is_login_page() ) {
            return true;
        }

        // Check user roles.
        if ( is_user_logged_in() ) {
            $user         = wp_get_current_user();
            $bypass_roles = $this->get_setting( 'bypass_roles', array( 'administrator' ) );

            foreach ( $bypass_roles as $role ) {
                if ( in_array( $role, (array) $user->roles, true ) ) {
                    return true;
                }
            }
        }

        // Check IP whitelist.
        $bypass_ips = $this->get_setting( 'bypass_ips', '' );
        if ( ! empty( $bypass_ips ) ) {
            $ips        = array_map( 'trim', explode( "\n", $bypass_ips ) );
            $visitor_ip = $this->get_visitor_ip();

            if ( in_array( $visitor_ip, $ips, true ) ) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if current page is login page
     *
     * @return bool
     */
    private function is_login_page() {
        return in_array( $GLOBALS['pagenow'], array( 'wp-login.php', 'wp-register.php' ), true );
    }

    /**
     * Get visitor IP address
     *
     * @return string
     */
    private function get_visitor_ip() {
        $ip = '';

        if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
            $ip = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CLIENT_IP'] ) );
        } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
            $ip = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) );
            // Get first IP if multiple.
            $ip = explode( ',', $ip )[0];
        } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
            $ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
        }

        return trim( $ip );
    }

    /**
     * Maybe show maintenance page
     */
    public function maybe_show_maintenance_page() {
        // Admin preview: never bypass, always render with the requested mode.
        // Skip status_header/Retry-After so the preview stays a 200 in the
        // browser (avoids confusing DevTools and uptime monitors during QA).
        $preview = $this->get_preview_mode();
        if ( '' !== $preview ) {
            $this->render_maintenance_page( true, $preview );
            exit;
        }

        if ( $this->should_bypass() ) {
            return;
        }

        $this->render_maintenance_page();
        exit;
    }

    /**
     * Render maintenance page
     *
     * @param bool   $skip_headers     When true, skip status_header/header() calls
     *                                 so the HTML can be captured from a context
     *                                 that has no live response (CLI preview).
     * @param string $forced_mode_key  Optional. Mode key to force-render (admin
     *                                 preview via ?be_preview=…). When empty,
     *                                 falls back to the saved setting.
     */
    public function render_maintenance_page( $skip_headers = false, $forced_mode_key = '' ) {
        if ( '' !== $forced_mode_key ) {
            $modes    = $this->get_modes();
            $mode_key = $forced_mode_key;
            $mode     = isset( $modes[ $mode_key ] ) ? $modes[ $mode_key ] : $modes['maintenance'];
        } else {
            $mode_key = $this->get_setting( 'mode', 'maintenance' );
            $mode     = $this->get_current_mode();
        }
        $title      = $this->get_setting( 'title', '' );
        $headline   = $this->get_setting( 'headline', '' );
        $message    = $this->get_setting( 'message', '' );
        $bg_color   = $this->get_setting( 'bg_color', '#f1f1f1' );
        $text_color = $this->get_setting( 'text_color', '#444444' );
        $show_login = $this->get_setting( 'show_login_link', true );
        $logo_id    = (int) $this->get_setting( 'logo_id', 0 );

        if ( empty( $title ) ) {
            $title = get_bloginfo( 'name' );
        }
        if ( empty( $headline ) ) {
            $headline = $mode['headline'];
        }
        if ( empty( $message ) ) {
            $message = $mode['message'];
        }

        // HTTP status: 503 for maintenance/coming_soon (real downtime), 200 for
        // staging/development (so uptime monitors and reviewers do not see the
        // preview environment as broken).
        if ( ! $skip_headers ) {
            if ( 503 === (int) $mode['http_status'] ) {
                status_header( 503 );
                header( 'Retry-After: 3600' );
            } else {
                status_header( 200 );
            }
            header( 'Content-Type: text/html; charset=utf-8' );
        }

        $logo_url = '';
        if ( $logo_id > 0 ) {
            $logo_url = wp_get_attachment_image_url( $logo_id, 'medium' );
        }

        $countdown_target  = $this->get_setting( 'countdown_target', '' );
        $end_time          = $this->get_setting( 'end_time', '' );
        $contact_shortcode = $this->get_setting( 'contact_shortcode', '' );
        $signup_shortcode  = $this->get_setting( 'signup_shortcode', '' );
        $live_site_url     = $this->get_setting( 'live_site_url', '' );

        // Countdown ISO datetime (UTC) for JS consumer. Coming Soon counts
        // down to launch (countdown_target); Maintenance counts down to the
        // estimated end of downtime (end_time) — both render through the same
        // .maintenance-countdown widget for visual consistency.
        $countdown_iso = '';
        if ( 'coming_soon' === $mode_key && ! empty( $countdown_target ) ) {
            $ts = strtotime( $countdown_target . ' ' . wp_timezone_string() );
            if ( false !== $ts && $ts > time() ) {
                $countdown_iso = gmdate( 'c', $ts );
            }
        } elseif ( 'maintenance' === $mode_key && ! empty( $end_time ) ) {
            $ts = strtotime( $end_time . ' ' . wp_timezone_string() );
            if ( false !== $ts && $ts > time() ) {
                $countdown_iso = gmdate( 'c', $ts );
            }
        }

        ?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo( 'charset' ); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="robots" content="noindex, nofollow">
    <title><?php echo esc_html( $title ); ?></title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
            background-color: <?php echo esc_attr( $bg_color ); ?>;
            color: <?php echo esc_attr( $text_color ); ?>;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            padding: 20px;
            text-align: center;
        }
        .maintenance-container { max-width: 640px; width: 100%; }
        .maintenance-logo { margin: 0 auto 2rem; max-width: 200px; max-height: 120px; }
        .maintenance-logo img { width: 100%; height: auto; display: block; }
        h1 { font-size: 2.5rem; font-weight: 600; margin-bottom: 1rem; line-height: 1.2; }
        p { font-size: 1.125rem; line-height: 1.6; opacity: 0.9; }
        p + p { margin-top: 1rem; }
        .maintenance-meta { margin-top: 1.5rem; font-size: 0.95rem; opacity: 0.75; }
        .maintenance-countdown {
            display: flex; justify-content: center; gap: 1rem;
            margin-top: 2rem; flex-wrap: wrap;
        }
        .maintenance-countdown-unit {
            min-width: 70px; padding: 0.75rem 0.5rem;
            border: 1px solid currentColor; border-radius: 6px; opacity: 0.85;
        }
        .maintenance-countdown-unit strong {
            display: block; font-size: 1.75rem; font-weight: 700; line-height: 1.1;
        }
        .maintenance-countdown-unit span {
            display: block; font-size: 0.75rem; text-transform: uppercase;
            letter-spacing: 0.05em; margin-top: 0.25rem; opacity: 0.7;
        }
        .maintenance-form {
            margin-top: 2rem; padding-top: 1.5rem;
            border-top: 1px solid currentColor; opacity: 0.9;
        }
        .maintenance-actions { margin-top: 2rem; }
        .maintenance-actions a {
            color: inherit; text-decoration: underline;
            font-size: 0.875rem; opacity: 0.7; margin: 0 0.75rem;
        }
        .maintenance-actions a:hover { opacity: 1; }
    </style>
</head>
<body>
    <div class="maintenance-container">
        <?php if ( $logo_url ) : ?>
            <div class="maintenance-logo"><img src="<?php echo esc_url( $logo_url ); ?>" alt="<?php echo esc_attr( $title ); ?>"></div>
        <?php endif; ?>

        <h1><?php echo esc_html( $headline ); ?></h1>
        <?php echo wp_kses_post( wpautop( $message ) ); ?>

        <?php if ( $countdown_iso ) : ?>
            <div class="maintenance-countdown" data-countdown-target="<?php echo esc_attr( $countdown_iso ); ?>">
                <div class="maintenance-countdown-unit"><strong data-unit="days">0</strong><span><?php esc_html_e( 'Days', 'blaminhor-essentials' ); ?></span></div>
                <div class="maintenance-countdown-unit"><strong data-unit="hours">0</strong><span><?php esc_html_e( 'Hours', 'blaminhor-essentials' ); ?></span></div>
                <div class="maintenance-countdown-unit"><strong data-unit="minutes">0</strong><span><?php esc_html_e( 'Minutes', 'blaminhor-essentials' ); ?></span></div>
                <div class="maintenance-countdown-unit"><strong data-unit="seconds">0</strong><span><?php esc_html_e( 'Seconds', 'blaminhor-essentials' ); ?></span></div>
            </div>
            <script>
            (function(){
                var box = document.querySelector('[data-countdown-target]');
                if (!box) return;
                var target = new Date(box.getAttribute('data-countdown-target')).getTime();
                var els = {
                    days: box.querySelector('[data-unit="days"]'),
                    hours: box.querySelector('[data-unit="hours"]'),
                    minutes: box.querySelector('[data-unit="minutes"]'),
                    seconds: box.querySelector('[data-unit="seconds"]')
                };
                function tick() {
                    var diff = Math.max(0, target - Date.now());
                    var s = Math.floor(diff / 1000);
                    els.days.textContent    = Math.floor(s / 86400);
                    els.hours.textContent   = Math.floor((s % 86400) / 3600);
                    els.minutes.textContent = Math.floor((s % 3600) / 60);
                    els.seconds.textContent = s % 60;
                    if (diff <= 0) { clearInterval(timer); }
                }
                tick();
                var timer = setInterval(tick, 1000);
            })();
            </script>
        <?php endif; ?>

        <?php if ( 'staging' === $mode_key && ! empty( $live_site_url ) ) : ?>
            <p class="maintenance-meta">
                <a href="<?php echo esc_url( $live_site_url ); ?>" target="_blank" rel="noopener">
                    <?php esc_html_e( 'View Live Site', 'blaminhor-essentials' ); ?>
                </a>
            </p>
        <?php endif; ?>

        <?php
        // Maintenance: contact form shortcode. Coming Soon: email signup shortcode.
        $shortcode_to_render = '';
        if ( 'maintenance' === $mode_key && ! empty( $contact_shortcode ) ) {
            $shortcode_to_render = $contact_shortcode;
        } elseif ( 'coming_soon' === $mode_key && ! empty( $signup_shortcode ) ) {
            $shortcode_to_render = $signup_shortcode;
        }
        if ( $shortcode_to_render ) :
            ?>
            <div class="maintenance-form">
                <?php echo do_shortcode( $shortcode_to_render ); ?>
            </div>
            <?php
        endif;
        ?>

        <?php if ( $show_login && ! is_user_logged_in() ) : ?>
            <div class="maintenance-actions">
                <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php esc_html_e( 'Admin Login', 'blaminhor-essentials' ); ?></a>
            </div>
        <?php endif; ?>
    </div>
</body>
</html>
        <?php
    }

    /**
     * Add admin bar notice when maintenance mode is active
     *
     * @param WP_Admin_Bar $admin_bar Admin bar instance.
     */
    public function add_admin_bar_notice( $admin_bar ) {
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        $mode  = $this->get_current_mode();
        $label = $mode['badge'];

        $admin_bar->add_node( array(
            'id'    => 'blaminhor-essentials-maintenance-notice',
            'title' => '<span class="ap-admin-bar-badge">' . esc_html( $label ) . '</span>',
            'href'  => admin_url( 'admin.php?page=blaminhor-essentials-maintenance' ),
            'meta'  => array(
                'title' => __( 'Click to configure', 'blaminhor-essentials' ),
            ),
        ) );
    }

    /**
     * Process settings
     *
     * @param array $data Form data.
     */
    protected function process_settings( $data ) {
        // WordPress slashes $_POST automatically. Unslash once recursively so
        // sanitize_* and wp_kses_post calls below receive clean input and
        // apostrophes do not accumulate backslashes across successive saves.
        $data = wp_unslash( $data );

        $settings = array();

        $settings['enabled']         = isset( $data['enabled'] );

        $allowed_modes               = array_keys( $this->get_modes() );
        $submitted_mode              = isset( $data['mode'] ) ? sanitize_key( $data['mode'] ) : 'maintenance';
        $settings['mode']            = in_array( $submitted_mode, $allowed_modes, true ) ? $submitted_mode : 'maintenance';

        $settings['title']           = isset( $data['title'] ) ? sanitize_text_field( $data['title'] ) : '';
        $settings['headline']        = isset( $data['headline'] ) ? sanitize_text_field( $data['headline'] ) : '';
        $settings['message']         = isset( $data['message'] ) ? wp_kses_post( $data['message'] ) : '';
        $settings['bg_color']        = isset( $data['bg_color'] ) ? sanitize_hex_color( $data['bg_color'] ) : '#f1f1f1';
        $settings['text_color']      = isset( $data['text_color'] ) ? sanitize_hex_color( $data['text_color'] ) : '#444444';
        $settings['show_login_link'] = isset( $data['show_login_link'] );

        // Logo: media attachment ID.
        $settings['logo_id'] = isset( $data['logo_id'] ) ? absint( $data['logo_id'] ) : 0;

        // Date/time fields (HTML datetime-local format: YYYY-MM-DDTHH:MM).
        $settings['countdown_target'] = '';
        if ( ! empty( $data['countdown_target'] ) ) {
            $candidate = sanitize_text_field( $data['countdown_target'] );
            if ( preg_match( '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/', $candidate ) ) {
                $settings['countdown_target'] = $candidate;
            }
        }
        $settings['end_time'] = '';
        if ( ! empty( $data['end_time'] ) ) {
            $candidate = sanitize_text_field( $data['end_time'] );
            if ( preg_match( '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/', $candidate ) ) {
                $settings['end_time'] = $candidate;
            }
        }

        // Shortcode fields. wp_kses_post keeps them flexible enough for plugin shortcodes.
        $settings['contact_shortcode'] = isset( $data['contact_shortcode'] ) ? wp_kses_post( $data['contact_shortcode'] ) : '';
        $settings['signup_shortcode']  = isset( $data['signup_shortcode'] ) ? wp_kses_post( $data['signup_shortcode'] ) : '';

        // Live site URL (Staging mode).
        $settings['live_site_url'] = '';
        if ( ! empty( $data['live_site_url'] ) ) {
            $url = esc_url_raw( trim( $data['live_site_url'] ) );
            if ( $url ) {
                $settings['live_site_url'] = $url;
            }
        }

        // Bypass roles.
        $settings['bypass_roles'] = array();
        if ( isset( $data['bypass_roles'] ) && is_array( $data['bypass_roles'] ) ) {
            $settings['bypass_roles'] = array_map( 'sanitize_key', $data['bypass_roles'] );
        }

        // Bypass IPs.
        $settings['bypass_ips'] = '';
        if ( isset( $data['bypass_ips'] ) ) {
            $ips = explode( "\n", $data['bypass_ips'] );
            $ips = array_map( 'trim', $ips );
            $ips = array_filter( $ips );
            $settings['bypass_ips'] = implode( "\n", $ips );
        }

        $previous_enabled = ! empty( $this->settings['enabled'] );
        $this->save_settings( $settings );

        // Toggling maintenance mode changes what every visitor sees, so any
        // cached frontend pages from a different state must be invalidated.
        if ( $previous_enabled !== ! empty( $settings['enabled'] ) ) {
            do_action( 'blaminhor_essentials_cache_purge_request' );
        }

        add_action( 'admin_notices', function () {
            blaminhor_essentials_admin_notice( __( 'Settings saved.', 'blaminhor-essentials' ), 'success' );
        } );
    }

    /**
     * Enqueue admin assets on the maintenance settings page.
     *
     * @param string $hook Current admin page hook.
     */
    public function enqueue_assets( $hook ) {
        if ( strpos( (string) $hook, 'blaminhor-essentials-maintenance' ) === false ) {
            return;
        }

        // Media Library picker for the logo field.
        wp_enqueue_media();
    }

    /**
     * Render settings page
     */
    public function render_settings_page() {
        $enabled      = $this->get_setting( 'enabled', false );
        $mode         = $this->get_setting( 'mode', 'maintenance' );
        $modes        = $this->get_modes();
        $bypass_roles = $this->get_setting( 'bypass_roles', array( 'administrator' ) );
        $all_roles    = wp_roles()->get_names();
        $logo_id      = (int) $this->get_setting( 'logo_id', 0 );
        $logo_url     = $logo_id > 0 ? wp_get_attachment_image_url( $logo_id, 'thumbnail' ) : '';

        // Per-mode preset (used as placeholder in the headline/message fields).
        $current_mode_meta = isset( $modes[ $mode ] ) ? $modes[ $mode ] : $modes['maintenance'];
        ?>
        <div class="wrap blaminhor-essentials-wrap">
            <div class="blaminhor-essentials-header">
                <h1><?php esc_html_e( 'Coming soon / Maintenance', 'blaminhor-essentials' ); ?></h1>
                <p class="blaminhor-essentials-tagline"><?php esc_html_e( 'Enable Coming Soon, Maintenance, Staging or Development mode for your site.', 'blaminhor-essentials' ); ?></p>
            </div>

            <div class="blaminhor-essentials-tabs-wrapper">
                <div class="blaminhor-essentials-tabs">
                    <button type="button" class="blaminhor-essentials-tab active" data-tab="settings"><?php esc_html_e( 'Settings', 'blaminhor-essentials' ); ?></button>
                    <button type="button" class="blaminhor-essentials-tab" data-tab="design"><?php esc_html_e( 'Design', 'blaminhor-essentials' ); ?></button>
                    <button type="button" class="blaminhor-essentials-tab" data-tab="access"><?php esc_html_e( 'Access', 'blaminhor-essentials' ); ?></button>
                </div>

                <form method="post">
                    <?php $this->render_nonce_field(); ?>

                    <!-- Settings Tab -->
                    <div class="blaminhor-essentials-tab-content active" data-tab-content="settings">
                        <h3><?php esc_html_e( 'Mode Settings', 'blaminhor-essentials' ); ?></h3>

                        <table class="form-table">
                            <tr>
                                <th scope="row"><?php esc_html_e( 'Enable', 'blaminhor-essentials' ); ?></th>
                                <td>
                                    <label>
                                        <input type="checkbox" name="enabled" value="1" <?php checked( $enabled ); ?>>
                                        <?php esc_html_e( 'Activate maintenance/coming soon mode', 'blaminhor-essentials' ); ?>
                                    </label>
                                    <?php if ( $enabled ) : ?>
                                        <p class="description ap-desc-danger-bold">
                                            <?php esc_html_e( 'Mode is currently ACTIVE. Visitors cannot access your site.', 'blaminhor-essentials' ); ?>
                                        </p>
                                    <?php endif; ?>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row"><?php esc_html_e( 'Mode', 'blaminhor-essentials' ); ?></th>
                                <td>
                                    <?php
                                    $i = 0;
                                    $total_modes = count( $modes );
                                    foreach ( $modes as $mode_key => $mode_data ) :
                                        $i++;
                                        ?>
                                        <label>
                                            <input type="radio" name="mode" value="<?php echo esc_attr( $mode_key ); ?>" <?php checked( $mode, $mode_key ); ?> data-mode-radio>
                                            <?php echo esc_html( $mode_data['label'] ); ?>
                                        </label>
                                        <p class="description"><?php echo esc_html( $mode_data['description'] ); ?></p>
                                        <?php if ( $i < $total_modes ) : ?>
                                            <br>
                                        <?php endif; ?>
                                    <?php endforeach; ?>
                                </td>
                            </tr>
                        </table>

                        <hr>

                        <h3><?php esc_html_e( 'Content', 'blaminhor-essentials' ); ?></h3>

                        <table class="form-table">
                            <tr>
                                <th scope="row">
                                    <label for="title"><?php esc_html_e( 'Page Title', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <input type="text" id="title" name="title" class="regular-text"
                                        value="<?php echo esc_attr( $this->get_setting( 'title', '' ) ); ?>"
                                        placeholder="<?php echo esc_attr( get_bloginfo( 'name' ) ); ?>">
                                    <p class="description"><?php esc_html_e( 'Browser tab title. If left empty, the value shown in grey will be used.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="headline"><?php esc_html_e( 'Headline', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <input type="text" id="headline" name="headline" class="regular-text"
                                        value="<?php echo esc_attr( $this->get_setting( 'headline', '' ) ); ?>"
                                        placeholder="<?php echo esc_attr( $current_mode_meta['headline'] ); ?>">
                                    <p class="description"><?php esc_html_e( 'If left empty, the value shown in grey will be used.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="message"><?php esc_html_e( 'Message', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <textarea id="message" name="message" rows="6" class="large-text"
                                        placeholder="<?php echo esc_attr( $current_mode_meta['message'] ); ?>"><?php echo esc_textarea( $this->get_setting( 'message', '' ) ); ?></textarea>
                                    <p class="description"><?php esc_html_e( 'Basic HTML allowed. If left empty, the value shown in grey will be used.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                        </table>

                        <hr>

                        <h3><?php esc_html_e( 'Mode-specific options', 'blaminhor-essentials' ); ?></h3>
                        <p class="description"><?php esc_html_e( 'The fields below appear automatically when relevant for the selected mode.', 'blaminhor-essentials' ); ?></p>

                        <table class="form-table" data-mode-section="maintenance">
                            <tr>
                                <th scope="row">
                                    <label for="end_time"><?php esc_html_e( 'Estimated end time', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <input type="datetime-local" id="end_time" name="end_time"
                                        value="<?php echo esc_attr( $this->get_setting( 'end_time', '' ) ); ?>">
                                    <p class="description"><?php esc_html_e( 'Optional. Displays a live countdown to this date and time.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="contact_shortcode"><?php esc_html_e( 'Contact form shortcode', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <input type="text" id="contact_shortcode" name="contact_shortcode" class="regular-text"
                                        value="<?php echo esc_attr( $this->get_setting( 'contact_shortcode', '' ) ); ?>"
                                        placeholder='[contact-form-7 id="123"]'>
                                    <p class="description"><?php esc_html_e( 'Optional. Paste a shortcode from your contact form plugin (Contact Form 7, WPForms, etc.).', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                        </table>

                        <table class="form-table" data-mode-section="coming_soon">
                            <tr>
                                <th scope="row">
                                    <label for="countdown_target"><?php esc_html_e( 'Countdown target', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <input type="datetime-local" id="countdown_target" name="countdown_target"
                                        value="<?php echo esc_attr( $this->get_setting( 'countdown_target', '' ) ); ?>">
                                    <p class="description"><?php esc_html_e( 'Optional. Displays a live countdown to this date and time.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="signup_shortcode"><?php esc_html_e( 'Email signup shortcode', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <input type="text" id="signup_shortcode" name="signup_shortcode" class="regular-text"
                                        value="<?php echo esc_attr( $this->get_setting( 'signup_shortcode', '' ) ); ?>"
                                        placeholder='[mc4wp_form id="123"]'>
                                    <p class="description"><?php esc_html_e( 'Optional. Paste a shortcode from your newsletter plugin (Mailchimp, MC4WP, etc.).', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                        </table>

                        <table class="form-table" data-mode-section="staging">
                            <tr>
                                <th scope="row">
                                    <label for="live_site_url"><?php esc_html_e( 'Live site URL', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <input type="url" id="live_site_url" name="live_site_url" class="regular-text"
                                        value="<?php echo esc_attr( $this->get_setting( 'live_site_url', '' ) ); ?>"
                                        placeholder="https://example.com">
                                    <p class="description"><?php esc_html_e( 'Optional. Adds a "View Live Site" link to help reviewers compare staging with production.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                        </table>

                        <p class="submit">
                            <button type="submit" class="button button-primary"><?php esc_html_e( 'Save Settings', 'blaminhor-essentials' ); ?></button>
                        </p>
                    </div>

                    <!-- Design Tab -->
                    <div class="blaminhor-essentials-tab-content" data-tab-content="design">
                        <h3><?php esc_html_e( 'Logo', 'blaminhor-essentials' ); ?></h3>

                        <table class="form-table">
                            <tr>
                                <th scope="row"><?php esc_html_e( 'Site Logo', 'blaminhor-essentials' ); ?></th>
                                <td>
                                    <input type="hidden" id="logo_id" name="logo_id" value="<?php echo esc_attr( $logo_id ); ?>">
                                    <div class="ap-image-selector">
                                        <div id="ap-maint-logo-preview" class="ap-image-preview<?php echo $logo_url ? '' : ' ap-no-image'; ?>">
                                            <?php if ( $logo_url ) : ?>
                                                <img src="<?php echo esc_url( $logo_url ); ?>" alt="">
                                            <?php else : ?>
                                                <span class="dashicons dashicons-format-image"></span>
                                            <?php endif; ?>
                                        </div>
                                        <div>
                                            <button type="button" class="button" id="ap-maint-logo-select"><?php esc_html_e( 'Select Image', 'blaminhor-essentials' ); ?></button>
                                            <button type="button" class="button" id="ap-maint-logo-remove" <?php echo $logo_url ? '' : 'style="display:none"'; ?>><?php esc_html_e( 'Remove image', 'blaminhor-essentials' ); ?></button>
                                        </div>
                                    </div>
                                    <p class="description"><?php esc_html_e( 'Optional. Displayed above the headline on the public page.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                        </table>

                        <hr>

                        <h3><?php esc_html_e( 'Colors', 'blaminhor-essentials' ); ?></h3>

                        <table class="form-table">
                            <tr>
                                <th scope="row">
                                    <label for="bg_color"><?php esc_html_e( 'Background Color', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <?php $bla_mt_bg = $this->get_setting( 'bg_color', '#f1f1f1' ); ?>
                                    <span class="blaminhor-essentials-color-control">
                                        <input type="color" id="bg_color" name="bg_color" value="<?php echo esc_attr( $bla_mt_bg ); ?>" class="blaminhor-essentials-color-swatch">
                                        <input type="text" value="<?php echo esc_attr( $bla_mt_bg ); ?>" class="blaminhor-essentials-color-hex" maxlength="7" pattern="^#[0-9A-Fa-f]{6}$" aria-label="<?php esc_attr_e( 'Hex color value', 'blaminhor-essentials' ); ?>">
                                    </span>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="text_color"><?php esc_html_e( 'Text Color', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <?php $bla_mt_txt = $this->get_setting( 'text_color', '#444444' ); ?>
                                    <span class="blaminhor-essentials-color-control">
                                        <input type="color" id="text_color" name="text_color" value="<?php echo esc_attr( $bla_mt_txt ); ?>" class="blaminhor-essentials-color-swatch">
                                        <input type="text" value="<?php echo esc_attr( $bla_mt_txt ); ?>" class="blaminhor-essentials-color-hex" maxlength="7" pattern="^#[0-9A-Fa-f]{6}$" aria-label="<?php esc_attr_e( 'Hex color value', 'blaminhor-essentials' ); ?>">
                                    </span>
                                </td>
                            </tr>
                        </table>

                        <hr>

                        <h3><?php esc_html_e( 'Options', 'blaminhor-essentials' ); ?></h3>

                        <table class="form-table">
                            <tr>
                                <th scope="row"><?php esc_html_e( 'Login Link', 'blaminhor-essentials' ); ?></th>
                                <td>
                                    <label>
                                        <input type="checkbox" name="show_login_link" <?php checked( $this->get_setting( 'show_login_link', true ) ); ?>>
                                        <?php esc_html_e( 'Show admin login link', 'blaminhor-essentials' ); ?>
                                    </label>
                                </td>
                            </tr>
                        </table>

                        <p class="submit">
                            <button type="submit" class="button button-primary"><?php esc_html_e( 'Save Settings', 'blaminhor-essentials' ); ?></button>
                        </p>
                    </div>

                    <!-- Access Tab -->
                    <div class="blaminhor-essentials-tab-content" data-tab-content="access">
                        <h3><?php esc_html_e( 'Bypass Access', 'blaminhor-essentials' ); ?></h3>
                        <p class="description"><?php esc_html_e( 'Configure who can bypass the maintenance page.', 'blaminhor-essentials' ); ?></p>

                        <table class="form-table">
                            <tr>
                                <th scope="row"><?php esc_html_e( 'User Roles', 'blaminhor-essentials' ); ?></th>
                                <td>
                                    <fieldset>
                                        <?php foreach ( $all_roles as $role_key => $role_name ) : ?>
                                            <label class="ap-label-block">
                                                <input type="checkbox" name="bypass_roles[]" value="<?php echo esc_attr( $role_key ); ?>"
                                                    <?php checked( in_array( $role_key, $bypass_roles, true ) ); ?>
                                                    <?php disabled( 'administrator' === $role_key ); ?>>
                                                <?php echo esc_html( translate_user_role( $role_name ) ); ?>
                                            </label>
                                        <?php endforeach; ?>
                                    </fieldset>
                                    <p class="description"><?php esc_html_e( 'Administrators always have access.', 'blaminhor-essentials' ); ?></p>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row">
                                    <label for="bypass_ips"><?php esc_html_e( 'IP Whitelist', 'blaminhor-essentials' ); ?></label>
                                </th>
                                <td>
                                    <textarea id="bypass_ips" name="bypass_ips" rows="4" class="regular-text"
                                        placeholder="192.168.1.1&#10;10.0.0.1"><?php echo esc_textarea( $this->get_setting( 'bypass_ips', '' ) ); ?></textarea>
                                    <p class="description">
                                        <?php esc_html_e( 'One IP address per line. These IPs can access the site without logging in.', 'blaminhor-essentials' ); ?>
                                        <br>
                                        <?php
                                        printf(
                                            /* translators: %s: Current IP address */
                                            esc_html__( 'Your current IP: %s', 'blaminhor-essentials' ),
                                            '<code>' . esc_html( $this->get_visitor_ip() ) . '</code>'
                                        );
                                        ?>
                                    </p>
                                </td>
                            </tr>
                        </table>

                        <p class="submit">
                            <button type="submit" class="button button-primary"><?php esc_html_e( 'Save Settings', 'blaminhor-essentials' ); ?></button>
                        </p>
                    </div>
                </form>
            </div>
        </div>

        <script>
        jQuery(document).ready(function($) {
            // Toggle visibility of mode-specific sections based on the currently selected radio.
            function applyModeSections() {
                var current = $('input[name="mode"]:checked').val() || 'maintenance';
                $('[data-mode-section]').each(function () {
                    var section = $(this).data('mode-section');
                    $(this).toggle(section === current);
                });
            }
            applyModeSections();
            $('input[name="mode"]').on('change', applyModeSections);

            // Media Library logo picker.
            var frame;
            $('#ap-maint-logo-select').on('click', function (e) {
                e.preventDefault();
                if (frame) { frame.open(); return; }
                frame = wp.media({
                    title: '<?php echo esc_js( __( 'Select Site Logo', 'blaminhor-essentials' ) ); ?>',
                    button: { text: '<?php echo esc_js( __( 'Use this image', 'blaminhor-essentials' ) ); ?>' },
                    library: { type: 'image' },
                    multiple: false
                });
                frame.on('select', function () {
                    var attachment = frame.state().get('selection').first().toJSON();
                    var url = (attachment.sizes && attachment.sizes.thumbnail) ? attachment.sizes.thumbnail.url : attachment.url;
                    $('#logo_id').val(attachment.id);
                    var $preview = $('#ap-maint-logo-preview');
                    $preview.removeClass('ap-no-image').html('<img src="' + url + '" alt="">');
                    $('#ap-maint-logo-remove').show();
                });
                frame.open();
            });
            $('#ap-maint-logo-remove').on('click', function (e) {
                e.preventDefault();
                $('#logo_id').val('0');
                $('#ap-maint-logo-preview').addClass('ap-no-image').html('<span class="dashicons dashicons-format-image"></span>');
                $(this).hide();
            });
        });
        </script>
        <?php
    }
}
