<?php

namespace WtbFirewall\AutoProtect;

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

/**
 * Denne klassen brukes til å håndtere loggen for Auto Protect delen.
 * Dvs tabellen wtb_firewall_events
 */
class AutoProtectLog {

    /**
     * Sletter alle registrerte mislykkete autentiseringer for oppgitt ip.
     * 
     * @param string $ip
     */
    public function authenticateClear(string $ip) {
        global $wpdb;

        $table = $wpdb->prefix . 'wtb_firewall_events';

        if (\WtbFirewall\Helpers\IpHelper::isValidIpv4($ip)) {
            $wpdb->query(
                    $wpdb->prepare("DELETE FROM {$table} WHERE ipv4 = %d AND event_type IN (%d, %d)",
                            (int) ip2long($ip),
                            (int) \WtbFirewall\Firewall\EventType::WPLOGIN_AUTH_FAILED->value,
                            (int) \WtbFirewall\Firewall\EventType::XMLRPC_AUTH_FAILED->value
                    )
            );
        } else if (\WtbFirewall\Helpers\IpHelper::isValidIpv6($ip)) {
            $wpdb->query(
                    $wpdb->prepare("DELETE FROM {$table} WHERE ipv6 = %s AND event_type IN (%d, %d)",
                            (int) inet_pton($ip),
                            (int) \WtbFirewall\Firewall\EventType::WPLOGIN_AUTH_FAILED->value,
                            (int) \WtbFirewall\Firewall\EventType::XMLRPC_AUTH_FAILED->value
                    )
            );
        }
    }

    /**
     * Registrerer en mislykket autentisering for oppgitt type.
     * 
     * @param string $ip IP dette gjedler for.
     * @param string $authType Type autentisering 'wp-login', 'xmlrpc'
     */
    public function authenticateRegisterFailed(string $ip, string $authType) {
        $eventType = 0;

        if ($authType == 'wp-login') {
            $eventType = (int) \WtbFirewall\Firewall\EventType::WPLOGIN_AUTH_FAILED->value;
        } else if ($authType == 'xmlrpc') {
            $eventType = (int) \WtbFirewall\Firewall\EventType::XMLRPC_AUTH_FAILED->value;
        } else {
            return;
        }

        global $wpdb;

        $table = $wpdb->prefix . 'wtb_firewall_events';

        if (\WtbFirewall\Helpers\IpHelper::isValidIpv4($ip)) {
            $wpdb->insert(
                    $table,
                    [
                        'ipv4' => ip2long($ip),
                        'event_type' => $eventType,
                        'event_time' => gmdate('Y-m-d H:i:s'), // UTC+0
                    ],
                    [
                        '%d',
                        '%d',
                        '%s',
                    ]
            );
        } else if (\WtbFirewall\Helpers\IpHelper::isValidIpv6($ip)) {
            $wpdb->insert(
                    $table,
                    [
                        'ipv6' => inet_pton($ip),
                        'event_type' => $eventType,
                        'event_time' => gmdate('Y-m-d H:i:s'), // UTC+0
                    ],
                    [
                        '%s',
                        '%d',
                        '%s',
                    ]
            );
        } else {
            //Ugyldig IP.
            return;
        }
    }

    /**
     * Sjekker om oppgitt IP har fått nok mislykkete autentisering innenfor tidsrammen
     * til å skulle blokkeres.
     * 
     * @param string $ip IP vi skal sjekke.
     * @return bool TRUE dersom IP skal blokkeres, FALSE hvis ikke.
     */
    public function authenticateCheckBlock(string $ip): bool {

        //Beregn tidsrammen vi skal sjekke innenfor
        $time = (int) \WtbFirewall\Config\FirewallConfig::$autoProtectAuth['timeSpan'];
        $timeUnit = 1;

        if (\WtbFirewall\Config\FirewallConfig::$autoProtectAuth['timeSpanUnit'] == 'hours') {
            $timeUnit = 60;
        } else if (\WtbFirewall\Config\FirewallConfig::$autoProtectAuth['timeSpanUnit'] == 'days') {
            $timeUnit = 24 * 60;
        }

        $time *= $timeUnit;

        $dt = new \DateTime('now', new \DateTimeZone('UTC'));
        $dt->modify("-{$time} minutes");

        //Hvor langt tilbake i tid vi skal sjekke for mislykkete autentiseringer.
        $pastTime = $dt->format('Y-m-d H:i:s');

        //Avgjør om vi skal telle wp-login, xmlrpc
        $eventType = array();

        if (\WtbFirewall\Config\FirewallConfig::$autoProtectAuth['wpLogin'] === true) {
            $eventType[] = \WtbFirewall\Firewall\EventType::WPLOGIN_AUTH_FAILED->value;
        }

        if (\WtbFirewall\Config\FirewallConfig::$autoProtectAuth['XMLRPC'] === true) {
            $eventType[] = \WtbFirewall\Firewall\EventType::XMLRPC_AUTH_FAILED->value;
        }

        if (empty($eventType)) {
            //Ingenting å telle.
            return false;
        }

        $eventTypePlaceHolders = implode(', ', array_fill(0, count($eventType), '%d'));

        //Lag SQL query.
        global $wpdb;

        $table = $wpdb->prefix . 'wtb_firewall_events';

        if (\WtbFirewall\Helpers\IpHelper::isValidIpv4($ip)) {
            $sql = $wpdb->prepare("SELECT COUNT(*) FROM {$table} WHERE event_time > %s AND event_type IN ($eventTypePlaceHolders) AND ipv4 = %d",
                    array_merge([$pastTime], $eventType, [ip2long($ip)]));
        } else if (\WtbFirewall\Helpers\IpHelper::isValidIpv6($ip)) {
            $sql = $wpdb->prepare("SELECT COUNT(*) FROM {$table} WHERE event_time > %s AND event_type IN ($eventTypePlaceHolders) AND ipv6 = %s",
                    array_merge([$pastTime], $eventType, [inet_pton($ip)]));
        } else {
            //Ugyldig IP
            return false;
        }

        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query already prepared above.
        $count = (int) $wpdb->get_var($sql);

        //Sjekk om mislykkete autentiserings forsøk er over grensen.
        return $count >= \WtbFirewall\Config\FirewallConfig::$autoProtectAuth['attempts'];
    }

    /**
     * Tømmer event loggen for gamle mislykkete authentication events.
     * 
     */
    public function authenticateClearLog() {

        //Beregn hvor langt tilbake i tid vi skal beholde log entries for.
        $time = (int) \WtbFirewall\Config\FirewallConfig::$autoProtectAuth['timeSpan'];
        $timeUnit = 1;

        if (\WtbFirewall\Config\FirewallConfig::$autoProtectAuth['timeSpanUnit'] == 'hours') {
            $timeUnit = 60;
        } else if (\WtbFirewall\Config\FirewallConfig::$autoProtectAuth['timeSpanUnit'] == 'days') {
            $timeUnit = 24 * 60;
        }

        $time *= $timeUnit;

        $dt = new \DateTime('now', new \DateTimeZone('UTC'));
        $dt->modify("-{$time} minutes");

        //Mislykket autentiserings log entries eldre enn $pastTime er gått ut på dato og slettes.
        $pastTime = $dt->format('Y-m-d H:i:s');

        global $wpdb;

        $table = $wpdb->prefix . 'wtb_firewall_events';

        $wpLoginFailed = (int) \WtbFirewall\Firewall\EventType::WPLOGIN_AUTH_FAILED->value;
        $xmlrpcFailed = (int) \WtbFirewall\Firewall\EventType::XMLRPC_AUTH_FAILED->value;
        
        $wpdb->query("DELETE FROM {$table} WHERE event_time < '{$pastTime}' AND event_type IN ({$wpLoginFailed}, {$xmlrpcFailed})");
    }
}
