<?php
/**
 * Trusted Devices — login-fingerprint based new-device EARLY WARNING.
 *
 * Bei erfolgreichem Login: Fingerprint (SHA256 von UA + IP-Subnet + Accept-
 * Language) in usermeta (max. 20 Geräte/User). Bei einem bisher UNBEKANNTEN
 * Fingerprint: Warn-Mail an den User („Neuer Login von unbekanntem Gerät").
 *
 * Scope-Hinweis: Dies ist ein reines Account-Takeover-Frühwarnsystem (Mail +
 * Geräte-Historie). Es ist KEIN 2FA-Gate — ShieldForge verlangt 2FA bereits bei
 * JEDEM Login enrollter User (es gibt keinen „remember device"-2FA-Skip, der
 * hier zu erzwingen wäre). Der Hook läuft auf `wp_login`, also nach gesetztem
 * Auth-Cookie; er kann/soll den Login nicht blockieren, nur benachrichtigen.
 *
 * @package Brainwerk Security Suite
 */

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

class Shieldforge_Trusted_Devices {

    const META_KEY = 'shieldforge_trusted_devices'; // array of fingerprint => { first_seen, last_seen, ua_short }

    public static function register( Shieldforge_Loader $loader ) {
        if ( ! Shieldforge_Settings::get( 'trusted_devices_enabled', false ) ) return;
        $loader->add_action( 'wp_login', __CLASS__, 'on_login', 10, 2 );
    }

    public static function on_login( $login, $user ) {
        if ( ! $user instanceof WP_User ) return;
        $fp = self::fingerprint();
        if ( '' === $fp ) return;
        $devices = (array) get_user_meta( $user->ID, self::META_KEY, true );
        $is_new = empty( $devices ) || ! isset( $devices[ $fp ] );

        $now = time();
        $devices[ $fp ] = array(
            'first_seen' => $devices[ $fp ]['first_seen'] ?? $now,
            'last_seen'  => $now,
            'ua_short'   => self::short_ua(),
            'ip_anon'    => self::ip_anon(),
        );
        // Limit auf 20 devices/user — älteste raus
        if ( count( $devices ) > 20 ) {
            uasort( $devices, function ( $a, $b ) { return ( $b['last_seen'] ?? 0 ) - ( $a['last_seen'] ?? 0 ); } );
            $devices = array_slice( $devices, 0, 20, true );
        }
        update_user_meta( $user->ID, self::META_KEY, $devices );

        if ( $is_new && ! empty( $user->user_email ) ) {
            self::notify_new_device( $user );
        }
    }

    private static function fingerprint() {
        $ua  = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
        $lang= isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : '';
        $ip  = class_exists( 'Shieldforge_Utils' ) ? Shieldforge_Utils::get_real_ip() : ( isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '' );
        $subnet = self::ip_subnet( $ip );
        if ( '' === $ua && '' === $ip ) return '';
        return hash( 'sha256', $ua . '|' . $lang . '|' . $subnet );
    }
    private static function ip_subnet( $ip ) {
        if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
            return preg_replace( '/\.\d+$/', '.0', $ip );
        }
        if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
            $parts = explode( ':', $ip );
            return implode( ':', array_slice( $parts, 0, 4 ) ) . ':...';
        }
        return '';
    }
    private static function ip_anon() {
        $ip = class_exists( 'Shieldforge_Utils' ) ? Shieldforge_Utils::get_real_ip() : ( isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '' );
        return self::ip_subnet( $ip );
    }
    private static function short_ua() {
        $ua = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
        if ( false !== strpos( $ua, 'iPhone' ) )      return 'iPhone / Safari';
        if ( false !== strpos( $ua, 'iPad' ) )        return 'iPad / Safari';
        if ( false !== strpos( $ua, 'Android' ) )     return 'Android';
        if ( false !== strpos( $ua, 'Windows' ) )     return 'Windows';
        if ( false !== strpos( $ua, 'Macintosh' ) )   return 'Mac';
        if ( false !== strpos( $ua, 'X11' ) )         return 'Linux';
        return mb_substr( $ua, 0, 40 );
    }

    private static function notify_new_device( $user ) {
        $subject = sprintf( __( '[%s] Neuer Login von unbekanntem Gerät', 'brainwerk-security-suite' ), get_bloginfo( 'name' ) );
        $body  = '<p>' . sprintf( __( 'Hallo %s,', 'brainwerk-security-suite' ), esc_html( $user->display_name ) ) . '</p>';
        $body .= '<p>' . __( 'Es hat sich jemand mit Ihrem Account eingeloggt — von einem Gerät, das wir bisher nicht gesehen haben.', 'brainwerk-security-suite' ) . '</p>';
        $body .= '<p><strong>' . __( 'Details:', 'brainwerk-security-suite' ) . '</strong></p><ul>';
        $body .= '<li>' . __( 'Zeit:', 'brainwerk-security-suite' ) . ' ' . wp_date( 'd.m.Y H:i' ) . '</li>';
        $body .= '<li>' . __( 'IP (anonymisiert):', 'brainwerk-security-suite' ) . ' ' . esc_html( self::ip_anon() ) . '</li>';
        $body .= '<li>' . __( 'Gerät:', 'brainwerk-security-suite' ) . ' ' . esc_html( self::short_ua() ) . '</li>';
        $body .= '</ul>';
        $body .= '<p>' . __( '<strong>Waren Sie das?</strong> Dann ist alles in Ordnung. Sie können diese Mail ignorieren.', 'brainwerk-security-suite' ) . '</p>';
        $body .= '<p>' . __( '<strong>Waren Sie das nicht?</strong> Ändern Sie sofort Ihr Passwort und aktivieren Sie Zwei-Faktor-Authentifizierung (2FA). Verständigen Sie ggf. die Administration.', 'brainwerk-security-suite' ) . '</p>';
        wp_mail( $user->user_email, $subject, $body, array( 'Content-Type: text/html; charset=UTF-8' ) );
    }
}
