<?php

namespace CleantalkSP\SpbctWP\Firewall;

use CleantalkSP\SpbctWP\DTO\ReactDataDTO;
use CleantalkSP\Variables\Post;

class View
{
    /**
     * Get React data
     * @param array $data
     * @return array
     * @psalm-suppress PossiblyUnusedParam
     */
    public static function getReactData($data)
    {
        global $spbc;

        $data = ReactDataDTO::getDefaultArray();

        $data['objects']['rows'] = self::getFirewallRows();
        $data['objects']['fw_settings'] = self::getFwSettings();
        $data['objects']['user_token'] = $spbc->user_token;
        $data['objects']['service_id'] = $spbc->service_id;

        $data['flags']['is_key_ok'] = $spbc->key_is_ok;
        $data['flags']['showMoreButton'] = self::getFirewallRowsCount() > SPBC_LAST_ACTIONS_TO_VIEW;
        $data['flags']['is_traffic_control_enabled'] = isset($spbc->settings['traffic_control__enabled']) && $spbc->settings['traffic_control__enabled'] == true;
        $data['flags']['is_waf_enabled'] = isset($spbc->settings['waf__enabled']) && $spbc->settings['waf__enabled'] == true;

        return $data;
    }

    /**
     * Get firewall settings
     * @return array
     */
    private static function getFwSettings()
    {
        global $spbc;

        $autoblock_amount = isset($spbc->settings['traffic_control__autoblock_amount']) ? (int)$spbc->settings['traffic_control__autoblock_amount'] : 1000;
        $autoblock_timeframe = 5;
        if (isset($spbc->settings['traffic_control__autoblock_timeframe'])) {
            $autoblock_timeframe = (int)$spbc->settings['traffic_control__autoblock_timeframe'] / 60;
        }

        return array(
            'autoblock_amount' => $autoblock_amount,
            'autoblock_timeframe' => $autoblock_timeframe,
        );
    }

    /**
     * Get firewall rows count
     * @return int
     */
    private static function getFirewallRowsCount()
    {
        global $wpdb;
        return $wpdb->get_var("SELECT COUNT(*) FROM " . SPBC_TBL_FIREWALL_LOG);
    }

    /**
     * Get firewall rows
     * @param int $limit
     * @param int $offset
     * @return array
     */
    private static function getFirewallRows($limit = SPBC_LAST_ACTIONS_TO_VIEW, $offset = 0)
    {
        global $wpdb;

        $sql = $wpdb->prepare(
            "SELECT 
                logs.*,
                (SELECT MAX(personal_lists_v4.status) 
                 FROM " . SPBC_TBL_FIREWALL_DATA__IPS_V4 . " personal_lists_v4
                 WHERE personal_lists_v4.network = logs.network
                       AND personal_lists_v4.mask = logs.mask
                ) as personal_status
            FROM " . SPBC_TBL_FIREWALL_LOG . " logs
            ORDER BY logs.entry_timestamp DESC 
            LIMIT %d OFFSET %d",
            $limit,
            $offset
        );

        $rows = $wpdb->get_results($sql, ARRAY_A);

        $ip_countries = array();
        foreach ($rows as $row) {
            $ip_countries[] = $row['ip_entry'];
        }
        $ip_countries = spbc_get_countries_by_ips(implode(',', $ip_countries));

        $data = array();
        foreach ($rows as $row) {
            $status = self::formatStatus($row);

            $data[] = array(
                'ip_entry' => $row['ip_entry'],
                'country' => isset($ip_countries[$row['ip_entry']]) ? $ip_countries[$row['ip_entry']] : '',
                'entry_timestamp' => $row['entry_timestamp'],
                'status' => $status['status'],
                'statusColor' => $status['color'],
                'requests' => $row['requests'],
                'requests_per' => $status['requests_per'],
                'page_url' => $row['page_url'],
                'http_user_agent' => $row['http_user_agent'],
                'is_personal' => $row['is_personal'],
                'personal_status' => $row['personal_status'],
            );
        }

        return $data;
    }

    /**
     * Format status
     * @param array $row
     * @return array
     */
    private static function formatStatus($row)
    {
        $is_personal_text = $row['is_personal']
            ? esc_html__('by personal lists.', 'security-malware-firewall')
            : esc_html__('by common lists.', 'security-malware-firewall');
        $passed_text = esc_html__('Passed', 'security-malware-firewall') . ' ' . $is_personal_text;
        $blocked_text = esc_html__('Blocked', 'security-malware-firewall') . ' ' . $is_personal_text;

        $color = 'spbcRed';
        switch ($row['status']) {
            case 'PASS':
                $status = $passed_text;
                $color = 'spbcGreen';
                break;
            case 'PASS_BY_TRUSTED_NETWORK':
                $status = $passed_text . ' ' . __('Trusted network. Click on IP for details.', 'security-malware-firewall');
                $color = 'spbcGreen';
                break;
            case 'PASS_BY_WHITELIST':
                $status = $passed_text . ' ' . __('Whitelisted.', 'security-malware-firewall');
                $color = 'spbcGreen';
                break;
            case 'DENY':
                $status = $blocked_text . ' ' . __('Blacklisted.', 'security-malware-firewall');
                break;
            case 'DENY_BY_NETWORK':
                $status = $blocked_text . ' ' . __('Hazardous network.', 'security-malware-firewall');
                break;
            case 'DENY_BY_DOS':
                $status = __('Blocked by Traffic control', 'security-malware-firewall');
                break;
            case 'DENY_BY_SEC_FW':
                $status = __('Blocked. Hazardous network. Security source.', 'security-malware-firewall');
                break;
            case 'DENY_BY_SPAM_FW':
                $status = __('Blocked. Hazardous network. SFW source', 'security-malware-firewall');
                break;
            case 'DENY_BY_BFP':
                $status = __('Blocked by BruteForce protection system', 'security-malware-firewall');
                break;
            // WAF
            case 'DENY_BY_WAF_XSS':
                $status = __('Blocked by Web Application Firewall: XSS attack detected.', 'security-malware-firewall');
                break;
            case 'DENY_BY_WAF_SQL':
                $status = __('Blocked by Web Application Firewall: SQL-injection detected.', 'security-malware-firewall');
                break;
            case 'DENY_BY_WAF_FILE':
                $status = __('Blocked by Upload Checker module: ', 'security-malware-firewall')
                    . __('Malicious files upload.', 'security-malware-firewall')
                    . __('Reason: ', 'security-malware-firewall') . $row['pattern'];
                break;
            case 'DENY_BY_WAF_EXPLOIT':
                $status = __('Blocked by Web Application Firewall: Exploit detected.', 'security-malware-firewall');
                break;
            case 'DENY_BY_WAF_BLOCKER':
                $status = __('Blocked for 24 hours by Web Application Firewall: several attacks detected in a row', 'security-malware-firewall');
                break;
            default:
                $status = __('Unknown', 'security-malware-firewall');
                break;
        }

        $requests_per = self::getRequestsPer($row['ip_entry'], $row['status']);

        return array(
            'status' => $status,
            'color' => $color,
            'requests_per' => $requests_per,
        );
    }

    /**
     * Get requests per
     * @param string $ip
     * @param string $status
     * @return string
     */
    private static function getRequestsPer($ip = null, $status = null)
    {
        global $wpdb;

        if (is_null($ip) || is_null($status)) {
            return '-';
        }

        $log_type = 0;
        if (strpos($status, 'BFP')) {
            $log_type = 1;
        }
        if (strpos($status, 'WAF')) {
            $log_type = 2;
        }

        $c = $wpdb->get_results(
            'SELECT entries FROM ' . SPBC_TBL_TC_LOG
            . ' WHERE ip = "' . $ip . '"'
            . ' AND log_type = ' . $log_type
            . ' ORDER BY block_end_on DESC'
            . ' LIMIT 1',
            ARRAY_A
        );

        if (isset($c[0]) && isset($c[0]['entries'])) {
            $entries = (int)$c[0]['entries'];

            return (string)$entries;
        }

        return '-';
    }

    /**
     * Show more firewall logs
     * @return void
     */
    public static function showMoreFirewallLogs()
    {
        spbc_check_ajax_referer('spbc_secret_nonce', 'security');

        $amount = Post::getInt('amount') ?: SPBC_LAST_ACTIONS_TO_VIEW;

        $data = ReactDataDTO::getDefaultArray();
        $data['objects']['rows'] = self::getFirewallRows(SPBC_LAST_ACTIONS_TO_VIEW, $amount);

        wp_send_json($data);
    }
}
