<?php
/**
 * Anomaly tab: enable toggle, thresholds, baseline reset, status overview.
 *
 * @package Brainwerk Security Suite
 */

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

if ( ! empty( $_POST['shieldforge_anomaly_action'] ) && check_admin_referer( 'shieldforge_anomaly' ) && current_user_can( Shieldforge_Admin::CAP ) ) {
    if ( 'reset_baseline' === sanitize_key( wp_unslash( $_POST['shieldforge_anomaly_action'] ) ) ) {
        Shieldforge_Anomaly::reset_all();
        add_settings_error( 'brainwerk-security-suite', 'sf_baseline_reset', __( 'Baseline cleared.', 'brainwerk-security-suite' ), 'updated' );
    }
}

global $wpdb;
$baseline_table = Shieldforge_Utils::table( 'baseline' );
// $baseline_table is a trusted internal table name ($wpdb->prefix . 'shieldforge_*'), never user input; %i is unavailable on the supported WP 5.8 floor.
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom security table; direct live read by design; not cacheable.
$baseline_count = (int) $wpdb->get_var( 'SELECT COUNT(*) FROM ' . $baseline_table );
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom security table; direct live read by design; not cacheable.
$user_count     = (int) $wpdb->get_var( 'SELECT COUNT(DISTINCT user_id) FROM ' . $baseline_table );
$enabled        = (bool) Shieldforge_Settings::get( 'anomaly_enabled', false );
$alert_score    = (int) Shieldforge_Settings::get( 'anomaly_alert_score', 50 );
$block_score    = (int) Shieldforge_Settings::get( 'anomaly_block_score', 80 );
$recent         = Shieldforge_Anomaly::recent_anomalies( 20 );

// Live threat snapshot — same data the daily digest uses, rendered at the top.
$threat_data    = Shieldforge_Threat_Intel::build_digest();
$threat_score   = (int) $threat_data['score']['score'];
$threat_label   = (string) $threat_data['score']['label'];
$threat_24h     = (int) ( $threat_data['snapshot_24h']['anomalies'] ?? 0 );
$threat_top_ip  = ! empty( $threat_data['top_attackers'] ) ? $threat_data['top_attackers'][0]->ip : '';
$per_user_rows  = $wpdb->get_results( 'SELECT user_id, COUNT(*) AS metrics, SUM(sample_count) AS samples, MAX(updated_at) AS last_seen FROM ' . $baseline_table . ' GROUP BY user_id ORDER BY last_seen DESC LIMIT 10' ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- $baseline_table is a trusted internal table name ($wpdb->prefix), never user input; custom security table, direct live read by design, not cacheable.
?>
<div class="sf-threat-header is-<?php echo esc_attr( $threat_label ); ?>">
    <div class="sf-threat-score"><?php echo esc_html( $threat_score ); ?></div>
    <div style="flex:1; min-width:0">
        <div class="sf-threat-label"><?php echo esc_html( strtoupper( $threat_label ) ); ?></div>
        <div class="sf-threat-meta">
            <?php
            printf(
                /* translators: 1: anomalies in 24h, 2: top attacker IP or "none" */
                esc_html__( '%1$d anomalous logins in the last 24h. Top attacker IP: %2$s', 'brainwerk-security-suite' ),
                (int) $threat_24h,
                $threat_top_ip ? '<code>' . esc_html( $threat_top_ip ) . '</code>' : esc_html__( 'none', 'brainwerk-security-suite' )
            );
            ?>
        </div>
    </div>
    <div class="sf-threat-bar"><span style="width: <?php echo (int) $threat_score; ?>%"></span></div>
</div>

<div class="shieldforge-card">
    <h2><?php esc_html_e( 'Anomaly detection', 'brainwerk-security-suite' ); ?> <span class="sf-badge"><?php esc_html_e( 'beta', 'brainwerk-security-suite' ); ?></span></h2>
    <p class="muted">
        <?php esc_html_e( 'A lightweight, explainable Z-score model that flags logins outside a user\'s normal pattern (hour of day, IP family, user-agent class).', 'brainwerk-security-suite' ); ?>
    </p>

    <form method="post" action="">
        <?php wp_nonce_field( Shieldforge_Admin::NONCE ); ?>
        <input type="hidden" name="shieldforge_action" value="save_settings">
        <input type="hidden" name="shieldforge_tab_keys[]" value="anomaly_enabled">
        <input type="hidden" name="shieldforge_tab_keys[]" value="anomaly_alert_score">
        <input type="hidden" name="shieldforge_tab_keys[]" value="anomaly_block_score">

        <table class="form-table" role="presentation">
            <tr>
                <th scope="row"><?php esc_html_e( 'Enable', 'brainwerk-security-suite' ); ?></th>
                <td>
                    <label class="sf-toggle">
                        <input type="checkbox" name="shieldforge[anomaly_enabled]" value="1" <?php checked( $enabled ); ?>>
                        <?php esc_html_e( 'Record baselines on every successful login.', 'brainwerk-security-suite' ); ?>
                    </label>
                </td>
            </tr>
            <tr>
                <th scope="row"><?php esc_html_e( 'Alert threshold', 'brainwerk-security-suite' ); ?></th>
                <td>
                    <input type="number" name="shieldforge[anomaly_alert_score]" value="<?php echo esc_attr( $alert_score ); ?>" min="1" max="100" class="small-text">
                    <p class="description"><?php esc_html_e( 'Score 0–100. Above this value, the event is logged as severity HIGH.', 'brainwerk-security-suite' ); ?></p>
                </td>
            </tr>
            <tr>
                <th scope="row"><?php esc_html_e( 'Block threshold (future)', 'brainwerk-security-suite' ); ?></th>
                <td>
                    <input type="number" name="shieldforge[anomaly_block_score]" value="<?php echo esc_attr( $block_score ); ?>" min="1" max="100" class="small-text">
                    <p class="description"><?php esc_html_e( 'Reserved for a later release. Currently informational only.', 'brainwerk-security-suite' ); ?></p>
                </td>
            </tr>
        </table>

        <p>
            <button type="submit" class="button button-primary"><?php esc_html_e( 'Save', 'brainwerk-security-suite' ); ?></button>
        </p>
    </form>
</div>

<div class="shieldforge-card">
    <h2><?php esc_html_e( 'Baseline status', 'brainwerk-security-suite' ); ?></h2>
    <p>
        <?php
        printf(
            esc_html( _n( '%1$s baseline record across %2$s user.', '%1$s baseline records across %2$s users.', $user_count, 'brainwerk-security-suite' ) ),
            '<strong>' . esc_html( number_format_i18n( $baseline_count ) ) . '</strong>',
            '<strong>' . esc_html( number_format_i18n( $user_count ) ) . '</strong>'
        );
        ?>
        <span class="muted"> &mdash; <?php esc_html_e( 'scoring becomes meaningful after ~5 logins per user.', 'brainwerk-security-suite' ); ?></span>
    </p>

    <?php if ( ! empty( $per_user_rows ) ) : ?>
        <table class="widefat striped">
            <thead>
                <tr>
                    <th><?php esc_html_e( 'User', 'brainwerk-security-suite' ); ?></th>
                    <th><?php esc_html_e( 'Tracked metrics', 'brainwerk-security-suite' ); ?></th>
                    <th><?php esc_html_e( 'Total samples', 'brainwerk-security-suite' ); ?></th>
                    <th><?php esc_html_e( 'Last update (UTC)', 'brainwerk-security-suite' ); ?></th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ( $per_user_rows as $r ) :
                    $u = get_userdata( (int) $r->user_id );
                    $name = $u ? $u->user_login : sprintf( '#%d', (int) $r->user_id );
                ?>
                    <tr>
                        <td><?php echo esc_html( $name ); ?></td>
                        <td><?php echo esc_html( (int) $r->metrics ); ?> / 3</td>
                        <td><?php echo esc_html( (int) $r->samples ); ?></td>
                        <td><?php echo esc_html( $r->last_seen ); ?></td>
                    </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    <?php endif; ?>

    <p style="margin-top:1em">
        <form method="post" action="" onsubmit="return confirm('<?php echo esc_js( __( 'Clear all baseline data? Users will need to log in a few times before scoring is meaningful again.', 'brainwerk-security-suite' ) ); ?>');" style="display:inline">
            <?php wp_nonce_field( 'shieldforge_anomaly' ); ?>
            <input type="hidden" name="shieldforge_anomaly_action" value="reset_baseline">
            <button type="submit" class="button"><?php esc_html_e( 'Reset baseline', 'brainwerk-security-suite' ); ?></button>
        </form>
    </p>
</div>

<div class="shieldforge-card">
    <h2><?php esc_html_e( 'Recent anomalies', 'brainwerk-security-suite' ); ?></h2>
    <?php if ( empty( $recent ) ) : ?>
        <p class="muted">
            <?php esc_html_e( 'No anomalous logins yet. Once a user has at least 5 successful logins, future logins outside their normal pattern will appear here.', 'brainwerk-security-suite' ); ?>
        </p>
    <?php else : ?>
        <p class="description">
            <?php esc_html_e( 'Score is the maximum across all tracked metrics. The "top metric" column shows which signal drove the score, with observed value vs. baseline mean ± stddev.', 'brainwerk-security-suite' ); ?>
        </p>
        <table class="widefat striped">
            <thead>
                <tr>
                    <th><?php esc_html_e( 'When (UTC)', 'brainwerk-security-suite' ); ?></th>
                    <th><?php esc_html_e( 'User', 'brainwerk-security-suite' ); ?></th>
                    <th><?php esc_html_e( 'IP', 'brainwerk-security-suite' ); ?></th>
                    <th><?php esc_html_e( 'Score', 'brainwerk-security-suite' ); ?></th>
                    <th><?php esc_html_e( 'Top metric', 'brainwerk-security-suite' ); ?></th>
                    <th><?php esc_html_e( 'Observed vs. baseline', 'brainwerk-security-suite' ); ?></th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ( $recent as $row ) :
                    $ctx        = isset( $row->ctx ) ? $row->ctx : array();
                    $top_metric = isset( $ctx['top_metric'] ) ? (string) $ctx['top_metric'] : '';
                    $top_score  = isset( $ctx['top_score'] ) ? (int) $ctx['top_score'] : 0;
                    $label      = isset( $ctx['label'] ) ? (string) $ctx['label'] : '';
                    $observed   = isset( $ctx['observation'] ) ? $ctx['observation'] : null;
                    $mean       = isset( $ctx['mean'] ) ? $ctx['mean'] : null;
                    $stddev     = isset( $ctx['stddev'] ) ? $ctx['stddev'] : null;
                    $z          = isset( $ctx['z'] ) ? (float) $ctx['z'] : 0.0;

                    $badge_class = 'sf-badge';
                    if ( $top_score >= 80 ) {
                        $badge_class .= ' sf-badge-high';
                    } elseif ( $top_score >= 50 ) {
                        $badge_class .= ' sf-badge-warn';
                    }
                ?>
                    <tr>
                        <td><?php echo esc_html( $row->created_at ); ?></td>
                        <td><?php echo esc_html( $row->username ); ?></td>
                        <td><code><?php echo esc_html( $row->ip ); ?></code></td>
                        <td>
                            <span class="<?php echo esc_attr( $badge_class ); ?>"><?php echo esc_html( $top_score ); ?></span>
                            <span class="muted"> <?php echo esc_html( $label ); ?></span>
                        </td>
                        <td>
                            <?php echo esc_html( Shieldforge_Anomaly::metric_label( $top_metric ) ); ?>
                            <span class="muted"> z=<?php echo esc_html( number_format_i18n( $z, 2 ) ); ?></span>
                        </td>
                        <td>
                            <?php
                            echo esc_html( Shieldforge_Anomaly::metric_observed_label( $top_metric, $observed ) );
                            if ( null !== $mean && null !== $stddev ) {
                                printf(
                                    ' <span class="muted">vs. %s &plusmn; %s</span>',
                                    esc_html( number_format_i18n( (float) $mean, 2 ) ),
                                    esc_html( number_format_i18n( (float) $stddev, 2 ) )
                                );
                            }
                            ?>
                        </td>
                    </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    <?php endif; ?>
</div>

<?php
$sf_hint_title    = __( 'Upgrade anomaly detection in Pro', 'brainwerk-security-suite' );
$sf_hint_body     = __( 'The free build flags outliers using fixed Z-score thresholds. Pro adds per-user adaptive thresholds, geo-velocity ("impossible travel"), and step-up auth challenges instead of just logging.', 'brainwerk-security-suite' );
$sf_hint_features = array(
    __( 'Per-user adaptive thresholds', 'brainwerk-security-suite' ),
    __( 'Geo-velocity / impossible-travel detection', 'brainwerk-security-suite' ),
    __( 'Step-up challenge (2FA prompt) on suspicious logins', 'brainwerk-security-suite' ),
);
include SHIELDFORGE_PATH . 'admin/views/partials/upgrade-hint.php';
?>
