<?php
/**
 * Sensor facade — Pfad B (Threat-Intelligence Network).
 *
 * Single entry point that wires the sensor sub-modules into the plugin, drives
 * the cron tick, handles the admin "Threat Network" tab actions, and exposes a
 * read API for the UI. The sensor turns this install into a privacy-preserving
 * telemetry source for the central TIN, but only after explicit opt-in
 * (sensor_enabled) AND registration.
 *
 * Sub-modules (includes/sensor/):
 *   - Shieldforge_Sensor_Privacy   identity, global g1$ indicator, consent
 *   - Shieldforge_Sensor_Batcher   bounded local queue + transparency audit ring
 *   - Shieldforge_Sensor_Collector subscribes to shieldforge_event_emitted
 *   - Shieldforge_Sensor_Transport register / salt-fetch / signed flush (Phase 1)
 *
 * @package Brainwerk Security Suite
 */

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

class Shieldforge_Sensor {

    const CRON_HOOK   = 'shieldforge_sensor_tick';
    const CRON_SCHED  = 'shieldforge_5min';
    const ACTION_NONCE = 'shieldforge_sensor_action';

    public static function register( $loader ) {
        $dir = SHIELDFORGE_PATH . 'includes/sensor/';
        require_once $dir . 'class-shieldforge-sensor-privacy.php';
        require_once $dir . 'class-shieldforge-sensor-batcher.php';
        require_once $dir . 'class-shieldforge-sensor-collector.php';
        require_once $dir . 'class-shieldforge-sensor-transport.php';
        // Intel return path (Phase 2): consume the signed central feed.
        require_once SHIELDFORGE_PATH . 'includes/intel/class-shieldforge-intel-client.php';

        Shieldforge_Sensor_Collector::register( $loader );
        Shieldforge_Intel_Client::register( $loader );

        // Cron: custom 5-min schedule + the tick worker + (un)schedule on init.
        $loader->add_filter( 'cron_schedules', __CLASS__, 'add_cron_schedule' );
        $loader->add_action( self::CRON_HOOK, 'Shieldforge_Sensor_Transport', 'tick' );
        // Immun-rule telemetry rides the same cadence + opt-in gate as the sensor flush.
        $loader->add_action( self::CRON_HOOK, 'Shieldforge_Intel_Client', 'flush_immun' );
        $loader->add_action( 'init', __CLASS__, 'maybe_schedule_cron' );

        // Admin: handle the tab's register / send / salt buttons.
        $loader->add_action( 'admin_init', __CLASS__, 'maybe_handle_actions' );
    }

    /* ------------------------------------------------------------------
     * cron
     * ------------------------------------------------------------------ */

    public static function add_cron_schedule( $schedules ) {
        if ( ! isset( $schedules[ self::CRON_SCHED ] ) ) {
            $schedules[ self::CRON_SCHED ] = array(
                'interval' => 5 * MINUTE_IN_SECONDS,
                'display'  => __( 'Every 5 minutes (ShieldForge sensor)', 'brainwerk-security-suite' ),
            );
        }
        return $schedules;
    }

    /** Schedule the tick when opted in + registered; clear it otherwise. */
    public static function maybe_schedule_cron() {
        $active = Shieldforge_Sensor_Privacy::consent_given() && Shieldforge_Sensor_Privacy::is_registered();
        $next   = wp_next_scheduled( self::CRON_HOOK );
        if ( $active && ! $next ) {
            wp_schedule_event( time() + 60, self::CRON_SCHED, self::CRON_HOOK );
        } elseif ( ! $active && $next ) {
            wp_unschedule_event( $next, self::CRON_HOOK );
        }
    }

    /* ------------------------------------------------------------------
     * admin actions (Threat Network tab buttons)
     * ------------------------------------------------------------------ */

    public static function maybe_handle_actions() {
        if ( empty( $_POST['shieldforge_action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
            return;
        }
        $action = sanitize_key( wp_unslash( $_POST['shieldforge_action'] ) );
        $known  = array( 'sensor_register', 'sensor_unregister', 'sensor_send_now', 'sensor_fetch_salt' );
        if ( ! in_array( $action, $known, true ) ) {
            return;
        }
        if ( ! check_admin_referer( self::ACTION_NONCE ) ) {
            return;
        }
        if ( ! current_user_can( 'manage_options' ) && ! current_user_can( 'manage_network_options' ) ) {
            return;
        }

        switch ( $action ) {
            case 'sensor_register':
                $res = Shieldforge_Sensor_Transport::register( true );
                self::notice( $res['ok'] ? 'success' : 'error',
                    $res['ok'] ? __( 'Site registered with the Threat Network.', 'brainwerk-security-suite' )
                               : sprintf( __( 'Registration failed: %s', 'brainwerk-security-suite' ), $res['message'] ) );
                break;
            case 'sensor_unregister':
                Shieldforge_Sensor_Privacy::clear_registration();
                self::notice( 'success', __( 'This site is no longer registered. No further data will be sent.', 'brainwerk-security-suite' ) );
                break;
            case 'sensor_fetch_salt':
                $res = Shieldforge_Sensor_Transport::fetch_salt();
                self::notice( $res['ok'] ? 'success' : 'error',
                    $res['ok'] ? __( 'Network salt refreshed.', 'brainwerk-security-suite' )
                               : sprintf( __( 'Salt refresh failed: %s', 'brainwerk-security-suite' ), $res['message'] ) );
                break;
            case 'sensor_send_now':
                $res = Shieldforge_Sensor_Transport::flush();
                self::notice( $res['ok'] ? 'success' : 'error',
                    $res['ok'] ? sprintf( __( 'Sent %d event(s) to the Threat Network.', 'brainwerk-security-suite' ), (int) $res['sent'] )
                               : sprintf( __( 'Send failed: %s', 'brainwerk-security-suite' ), $res['message'] ) );
                break;
        }
        self::maybe_schedule_cron();

        $url = add_query_arg(
            array( 'page' => 'shieldforge', 'tab' => 'threat-network' ),
            is_network_admin() ? network_admin_url( 'admin.php' ) : admin_url( 'admin.php' )
        );
        wp_safe_redirect( $url );
        exit;
    }

    private static function notice( $type, $message ) {
        set_transient( 'shieldforge_sensor_notice_' . get_current_user_id(), array( 'type' => $type, 'message' => $message ), 30 );
    }

    /** Pull-and-clear the one-shot notice for the current user. */
    public static function take_notice() {
        $key    = 'shieldforge_sensor_notice_' . get_current_user_id();
        $notice = get_transient( $key );
        if ( $notice ) {
            delete_transient( $key );
        }
        return is_array( $notice ) ? $notice : null;
    }

    /* ------------------------------------------------------------------
     * Read API for the Threat Network tab
     * ------------------------------------------------------------------ */

    public static function is_enabled() { return Shieldforge_Sensor_Privacy::consent_given(); }
    public static function is_registered() { return Shieldforge_Sensor_Privacy::is_registered(); }
    public static function registration() { return Shieldforge_Sensor_Privacy::get_registration(); }
    public static function network_salt() { return Shieldforge_Sensor_Privacy::get_network_salt(); }
    public static function stats() { return Shieldforge_Sensor_Batcher::stats(); }
    public static function audit_log() { return Shieldforge_Sensor_Batcher::audit_log(); }
    public static function site_id() { return Shieldforge_Sensor_Privacy::site_id(); }
    public static function current_epoch() { return Shieldforge_Sensor_Privacy::current_epoch(); }
    public static function api_base() { return Shieldforge_Sensor_Transport::api_base(); }
    public static function threatmap( $window = '24h' ) { return Shieldforge_Sensor_Transport::get_threatmap( $window ); }
    public static function stateofwp( $window = '24h' ) { return Shieldforge_Sensor_Transport::get_stateofwp( $window ); }
}
