<?php

namespace UltraguardPro\modules\reputation_monitor;

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

use UltraguardPro\core\BaseController;
use UltraguardPro\Plugin;
use UltraguardPro\support\SecureRemoteTransport;

class ReputationCheckEngine extends BaseController {

    private const CACHE_OPTION = 'reputation_monitor_last_summary';

    public function __construct( ?Plugin $plugin = null ) {
        parent::__construct( $plugin );
    }

    public function run_all_checks(): array {
        $checks_table  = $this->getTable( 'blacklist_checks' );
        $history_table = $this->getTable( 'reputation_history' );
        $targets       = $this->get_targets();
        $results       = [];

        foreach ( $this->get_sources() as $source ) {
            if ( ! $this->is_source_enabled( $source['source_id'] ) ) {
                continue;
            }

            $target = 'ip' === $source['check_type'] ? $targets['ip'] : $targets['domain'];
            if ( empty( $target ) ) {
                continue;
            }

            $result = $this->run_source_check( $source, $target, $targets['site_url'] );
            if ( empty( $result ) ) {
                continue;
            }

            $previous = $checks_table && method_exists( $checks_table, 'get_by_source_target' )
                ? $checks_table->get_by_source_target( $source['source_id'], $target )
                : null;

            if ( $checks_table && method_exists( $checks_table, 'upsert_result' ) ) {
                $checks_table->upsert_result( $result );
            }

            if ( $history_table && method_exists( $history_table, 'log_transition' ) ) {
                $old_status = is_array( $previous ) ? (string) ( $previous['status'] ?? '' ) : '';
                if ( $old_status !== (string) $result['status'] ) {
                    $history_table->log_transition( [
                        'source_id'   => $result['source_id'],
                        'target'      => $result['target'],
                        'old_status'  => $old_status,
                        'new_status'  => $result['status'],
                        'threat_type' => $result['threat_type'],
                        'note'        => $result['details'],
                    ] );
                }
            }

            $results[] = $result;
        }

        $summary = [
            'overall_status'        => $this->get_overall_status(),
            'checked_at'            => current_time( 'mysql', true ),
            'results'               => $results,
            'blacklisted_sources'   => array_values( array_filter( $results, static function ( $row ) {
                return in_array( (string) ( $row['status'] ?? '' ), [ 'blacklisted', 'suspicious' ], true );
            } ) ),
            'sources_monitoring'    => count( $results ),
            'currently_blacklisted' => count( array_filter( $results, static function ( $row ) {
                return 'blacklisted' === ( $row['status'] ?? '' );
            } ) ),
        ];

        update_option( self::CACHE_OPTION, $summary, false );
        do_action( 'ultraguard_pro/reputation_monitor/check_complete', $summary );

        return $summary;
    }

    public function check_google_safe_browsing( string $api_key, string $url ): array {
        if ( empty( $api_key ) ) {
            return $this->make_result( 'google_safebrowsing', 'domain', $url, 'error', 'config', __( 'Google Safe Browsing API key not configured.', 'ultraguard-security-suite' ) );
        }

        $payload = [
            'client'     => [ 'clientId' => 'ultraguard-security-suite', 'clientVersion' => defined( 'ULTRAGUARD_PRO_VERSION' ) ? ULTRAGUARD_PRO_VERSION : '1.0.0' ],
            'threatInfo' => [
                'threatTypes'      => [ 'MALWARE', 'SOCIAL_ENGINEERING', 'UNWANTED_SOFTWARE' ],
                'platformTypes'    => [ 'ANY_PLATFORM' ],
                'threatEntryTypes' => [ 'URL' ],
                'threatEntries'    => [ [ 'url' => $url ] ],
            ],
        ];

        $response = wp_remote_post(
            'https://safebrowsing.googleapis.com/v4/threatMatches:find?key=' . rawurlencode( $api_key ),
            [
                'timeout' => 15,
                'headers' => [ 'Content-Type' => 'application/json' ],
                'body'    => wp_json_encode( $payload ),
            ]
        );

        if ( is_wp_error( $response ) ) {
            return $this->make_result( 'google_safebrowsing', 'domain', $url, 'error', 'request_error', $response->get_error_message() );
        }

        $body = json_decode( wp_remote_retrieve_body( $response ), true );
        if ( ! empty( $body['matches'][0]['threatType'] ) ) {
            return $this->make_result(
                'google_safebrowsing',
                'domain',
                $url,
                'blacklisted',
                sanitize_text_field( (string) $body['matches'][0]['threatType'] ),
                __( 'Google Safe Browsing reported a threat match for this URL.', 'ultraguard-security-suite' )
            );
        }

        return $this->make_result( 'google_safebrowsing', 'domain', $url, 'clean', '', __( 'No Google Safe Browsing matches detected.', 'ultraguard-security-suite' ) );
    }

    public function check_spamhaus_dnsbl( string $domain_or_ip ): array {
        if ( filter_var( $domain_or_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
            $lookup = implode( '.', array_reverse( explode( '.', $domain_or_ip ) ) ) . '.zen.spamhaus.org';
            $listed = checkdnsrr( $lookup, 'A' );

            return $listed
                ? $this->make_result( 'spamhaus', 'ip', $domain_or_ip, 'blacklisted', 'dnsbl', __( 'Spamhaus DNSBL returned a positive listing for this IP.', 'ultraguard-security-suite' ) )
                : $this->make_result( 'spamhaus', 'ip', $domain_or_ip, 'clean', '', __( 'No Spamhaus DNSBL listing detected for this IP.', 'ultraguard-security-suite' ) );
        }

        $host = wp_parse_url( $domain_or_ip, PHP_URL_HOST );
        $host = $host ? $host : $domain_or_ip;
        $ip   = gethostbyname( $host );

        if ( empty( $ip ) || $ip === $host ) {
            return $this->make_result( 'spamhaus', 'domain', $host, 'error', 'resolve_failed', __( 'Unable to resolve domain to an IPv4 address for Spamhaus lookup.', 'ultraguard-security-suite' ) );
        }

        $result               = $this->check_spamhaus_dnsbl( $ip );
        $result['target']     = $host;
        $result['check_type'] = 'domain';

        return $result;
    }

    public function check_mxtoolbox( string $domain ): array {
        $api_key = trim( (string) $this->plugin->settings->get_option( 'reputation_monitor_mxtoolbox_api_key', '' ) );
        if ( empty( $api_key ) ) {
            return $this->make_result( 'mxtoolbox', 'domain', $domain, 'error', 'config', __( 'MXToolBox API key not configured.', 'ultraguard-security-suite' ) );
        }

        $response = wp_remote_get(
            'https://api.mxtoolbox.com/api/v1/Lookup/blacklist/?argument=' . rawurlencode( $domain ),
            [
                'timeout' => 15,
                'headers' => [ 'Authorization' => $api_key ],
            ]
        );

        if ( is_wp_error( $response ) ) {
            return $this->make_result( 'mxtoolbox', 'domain', $domain, 'error', 'request_error', $response->get_error_message() );
        }

        $body  = json_decode( wp_remote_retrieve_body( $response ), true );
        $found = false;
        if ( ! empty( $body['Failed'] ) || ! empty( $body['Information'][0]['Blacklist'] ) ) {
            $found = true;
        }

        return $found
            ? $this->make_result( 'mxtoolbox', 'domain', $domain, 'blacklisted', 'blacklist', __( 'MXToolBox reported this domain or IP on one or more blocklists.', 'ultraguard-security-suite' ) )
            : $this->make_result( 'mxtoolbox', 'domain', $domain, 'clean', '', __( 'MXToolBox did not report any active blacklist listing.', 'ultraguard-security-suite' ) );
    }

    public function check_site_clean_api( string $site_url ): array {
        $response = wp_remote_get(
            'https://api.wordpress.org/core/site-health/1.0/?url=' . rawurlencode( $site_url ),
            [ 'timeout' => 12 ]
        );

        if ( is_wp_error( $response ) ) {
            return $this->make_result( 'ultraguard_network', 'domain', $site_url, 'error', 'request_error', $response->get_error_message() );
        }

        $code = (int) wp_remote_retrieve_response_code( $response );
        if ( $code >= 400 ) {
            return $this->make_result( 'ultraguard_network', 'domain', $site_url, 'suspicious', 'unreachable', __( 'The remote reputation fallback endpoint could not validate this site right now.', 'ultraguard-security-suite' ) );
        }

        return $this->make_result( 'ultraguard_network', 'domain', $site_url, 'clean', '', __( 'No blacklist signal detected by the reputation fallback check.', 'ultraguard-security-suite' ) );
    }

    public function get_overall_status(): string {
        $table = $this->getTable( 'blacklist_checks' );
        if ( ! $table || ! method_exists( $table, 'get_summary' ) ) {
            return 'warning';
        }

        $status = 'clean';
        foreach ( (array) $table->get_summary() as $row ) {
            if ( 'blacklisted' === ( $row['status'] ?? '' ) ) {
                return 'danger';
            }
            if ( in_array( ( $row['status'] ?? '' ), [ 'suspicious', 'error' ], true ) ) {
                $status = 'warning';
            }
        }

        return $status;
    }

    public function get_delisting_url( string $source_id ): string {
        $map = [
            'google_safebrowsing' => 'https://search.google.com/search-console/security-issues',
            'spamhaus'            => 'https://www.spamhaus.org/resource-hub/ip-and-domain-reputation-checker/spamhaus-reputation-checker-troubleshoot-your-listing/',
            'mcafee'              => 'https://trustedsource.org/',
            'norton'              => 'https://submit.norton.com/?type=URL',
            'bing'                => 'https://www.bing.com/webmasters/help/webpage-malware-reexamination-cb51d7a7',
            'mxtoolbox'           => 'https://mxtoolbox.com/problem/blacklist.aspx',
            'ultraguard_network'  => self_admin_url( 'admin.php?page=ultraguard-security-suite-dashboard&ug_page=support' ),
        ];

        return esc_url_raw( $map[ $source_id ] ?? self_admin_url( 'admin.php?page=ultraguard-security-suite-dashboard&ug_page=support' ) );
    }

    public function get_check_summary(): array {
        $table = $this->getTable( 'blacklist_checks' );
        return $table && method_exists( $table, 'get_summary' ) ? (array) $table->get_summary() : [];
    }

    public function get_history( int $limit = 50 ): array {
        $table = $this->getTable( 'reputation_history' );
        return $table && method_exists( $table, 'get_recent_history' ) ? (array) $table->get_recent_history( $limit ) : [];
    }

    public function get_stats(): array {
        $history = $this->getTable( 'reputation_history' );
        return $history && method_exists( $history, 'get_chart_stats' ) ? (array) $history->get_chart_stats( 90 ) : [
            'labels'      => [],
            'clean'       => [],
            'blacklisted' => [],
        ];
    }

    public function run_quick_summary(): array {
        $summary      = get_option( self::CACHE_OPTION, [] );
        $check_table  = $this->getTable( 'blacklist_checks' );
        $history      = $this->getTable( 'reputation_history' );
        $clean_since  = $history && method_exists( $history, 'get_last_blacklist_clear_date' ) ? (string) $history->get_last_blacklist_clear_date() : '';
        $total_checks = $check_table && method_exists( $check_table, 'count_all_checks' ) ? (int) $check_table->count_all_checks() : 0;

        return [
            'overall_status'        => ! empty( $summary['overall_status'] ) ? (string) $summary['overall_status'] : $this->get_overall_status(),
            'sources_monitoring'    => $check_table && method_exists( $check_table, 'count_sources_monitoring' ) ? (int) $check_table->count_sources_monitoring() : count( $this->get_check_summary() ),
            'currently_blacklisted' => $check_table && method_exists( $check_table, 'count_by_status' ) ? (int) $check_table->count_by_status( 'blacklisted' ) : 0,
            'clean_since'           => $clean_since,
            'total_checks_run'      => $total_checks,
        ];
    }

    private function get_targets(): array {
        $site_url = home_url();
        $domain   = wp_parse_url( $site_url, PHP_URL_HOST );
        $ip       = '';

        if ( $domain ) {
            $resolved = gethostbyname( $domain );
            if ( $resolved && $resolved !== $domain && filter_var( $resolved, FILTER_VALIDATE_IP ) ) {
                $ip = $resolved;
            }
        }

        return [
            'site_url' => $site_url,
            'domain'   => (string) $domain,
            'ip'       => $ip,
        ];
    }

    private function get_sources(): array {
        return [
            [ 'source_id' => 'google_safebrowsing', 'source_name' => 'Google Safe Browsing', 'check_type' => 'domain' ],
            [ 'source_id' => 'spamhaus', 'source_name' => 'Spamhaus', 'check_type' => 'ip' ],
            [ 'source_id' => 'mcafee', 'source_name' => 'McAfee WebAdvisor', 'check_type' => 'domain' ],
            [ 'source_id' => 'norton', 'source_name' => 'Norton Safe Web', 'check_type' => 'domain' ],
            [ 'source_id' => 'bing', 'source_name' => 'Bing Webmaster', 'check_type' => 'domain' ],
            [ 'source_id' => 'mxtoolbox', 'source_name' => 'MXToolBox', 'check_type' => 'domain' ],
            [ 'source_id' => 'ultraguard_network', 'source_name' => 'UltraGuard Network', 'check_type' => 'domain' ],
        ];
    }

    private function is_source_enabled( string $source_id ): bool {
        switch ( $source_id ) {
            case 'google_safebrowsing':
                return ! empty( $this->plugin->settings->get_option( 'reputation_monitor_google_api_key', '' ) );
            case 'spamhaus':
                return (bool) $this->plugin->settings->get_option( 'reputation_monitor_enable_spamhaus', true );
            case 'mxtoolbox':
                return (bool) $this->plugin->settings->get_option( 'reputation_monitor_enable_mxtoolbox', false );
            case 'mcafee':
                return (bool) $this->plugin->settings->get_option( 'reputation_monitor_enable_mcafee', true );
            case 'norton':
                return (bool) $this->plugin->settings->get_option( 'reputation_monitor_enable_norton', true );
            case 'bing':
                return (bool) $this->plugin->settings->get_option( 'reputation_monitor_enable_bing', true );
            default:
                return true;
        }
    }

    private function run_source_check( array $source, string $target, string $site_url ): array {
        switch ( $source['source_id'] ) {
            case 'google_safebrowsing':
                return $this->check_google_safe_browsing( (string) $this->plugin->settings->get_option( 'reputation_monitor_google_api_key', '' ), $site_url );
            case 'spamhaus':
                return $this->check_spamhaus_dnsbl( $target );
            case 'mxtoolbox':
                return $this->check_mxtoolbox( $target );
            case 'ultraguard_network':
                return $this->check_site_clean_api( $site_url );
            case 'mcafee':
                return $this->check_mcafee_webadvisor( $target );
            case 'norton':
                return $this->check_norton_safe_web( $target );
            case 'bing':
                return $this->check_bing_site_safety( $target );
            default:
                return [];
        }
    }

    private function check_mcafee_webadvisor( string $target ): array {
        return $this->check_vendor_lookup_page(
            'mcafee',
            'domain',
            $target,
            'https://www.trustedsource.org/en/feedback/url?action=checksingle&url=' . rawurlencode( $target ),
            [
                'blacklisted' => [ 'unsafe', 'dangerous', 'malware', 'phishing', 'poor reputation', 'risky' ],
                'clean'       => [ 'minimal risk', 'safe', 'no known issues', 'appears safe', 'trusted' ],
            ],
            __( 'McAfee TrustedSource lookup did not return a clear blacklist verdict for this target.', 'ultraguard-security-suite' )
        );
    }

    private function check_norton_safe_web( string $target ): array {
        return $this->check_vendor_lookup_page(
            'norton',
            'domain',
            $target,
            'https://safeweb.norton.com/report/show?url=' . rawurlencode( $target ),
            [
                'blacklisted' => [ 'warning', 'unsafe', 'malicious', 'threat', 'caution', 'suspicious' ],
                'clean'       => [ 'no threats detected', 'safe', 'ok', 'no unsafe content found', 'currently safe' ],
            ],
            __( 'Norton Safe Web returned an inconclusive response for this target.', 'ultraguard-security-suite' )
        );
    }

    private function check_bing_site_safety( string $target ): array {
        return $this->check_vendor_lookup_page(
            'bing',
            'domain',
            $target,
            'https://www.bing.com/webmasters/urlinspection?url=' . rawurlencode( 'https://' . ltrim( $target, '/' ) ),
            [
                'blacklisted' => [ 'unsafe', 'malware', 'phishing', 'blocked', 'issue found', 'security issue' ],
                'clean'       => [ 'no issues found', 'safe', 'passed', 'accessible', 'healthy' ],
            ],
            __( 'Bing safety inspection did not expose a public blacklist verdict for this target.', 'ultraguard-security-suite' )
        );
    }

    private function check_vendor_lookup_page( string $source_id, string $check_type, string $target, string $url, array $markers, string $fallback_message ): array {
        $response = SecureRemoteTransport::request( 'GET', $url, [
            'timeout'   => 15,
            'sslverify' => true,
            'headers'   => [
                'Accept' => 'text/html,application/xhtml+xml',
            ],
        ] );

        if ( is_wp_error( $response ) ) {
            return $this->make_result( $source_id, $check_type, $target, 'error', 'request_error', $response->get_error_message() );
        }

        $code = (int) wp_remote_retrieve_response_code( $response );
        if ( $code < 200 || $code >= 300 ) {
            return $this->make_result(
                $source_id,
                $check_type,
                $target,
                'error',
                'http_' . $code,
                /* translators: %d: integer */
                sprintf( __( 'The remote source returned HTTP %d during the reputation lookup.', 'ultraguard-security-suite' ), $code )
            );
        }

        $body = strtolower( wp_strip_all_tags( (string) wp_remote_retrieve_body( $response ) ) );

        foreach ( (array) ( $markers['blacklisted'] ?? [] ) as $marker ) {
            if ( '' !== $marker && false !== strpos( $body, strtolower( (string) $marker ) ) ) {
                return $this->make_result(
                    $source_id,
                    $check_type,
                    $target,
                    'blacklisted',
                    'vendor_listing',
                    __( 'The vendor reputation page reported a blacklist or security warning for this target.', 'ultraguard-security-suite' )
                );
            }
        }

        foreach ( (array) ( $markers['clean'] ?? [] ) as $marker ) {
            if ( '' !== $marker && false !== strpos( $body, strtolower( (string) $marker ) ) ) {
                return $this->make_result(
                    $source_id,
                    $check_type,
                    $target,
                    'clean',
                    '',
                    __( 'The vendor reputation page did not report an active blacklist or safety issue for this target.', 'ultraguard-security-suite' )
                );
            }
        }

        return $this->make_result( $source_id, $check_type, $target, 'suspicious', 'inconclusive', $fallback_message );
    }

    private function make_result( string $source_id, string $check_type, string $target, string $status, string $threat_type, string $details ): array {
        $source = [
            'google_safebrowsing' => 'Google Safe Browsing',
            'spamhaus'            => 'Spamhaus',
            'mcafee'              => 'McAfee WebAdvisor',
            'norton'              => 'Norton Safe Web',
            'bing'                => 'Bing Webmaster',
            'mxtoolbox'           => 'MXToolBox',
            'ultraguard_network'  => 'UltraGuard Network',
        ];

        $frequency = (string) $this->plugin->settings->get_option( 'reputation_monitor_frequency', 'hourly' );
        $next_time = time() + $this->interval_seconds( $frequency );

        return [
            'source_id'       => $source_id,
            'source_name'     => $source[ $source_id ] ?? $source_id,
            'check_type'      => $check_type,
            'target'          => $target,
            'status'          => $status,
            'threat_type'     => $threat_type,
            'details'         => $details,
            'last_checked_at' => current_time( 'mysql', true ),
            'next_check_at'   => gmdate( 'Y-m-d H:i:s', $next_time ),
        ];
    }

    private function interval_seconds( string $schedule ): int {
        switch ( $schedule ) {
            case 'every_30_minutes':
                return 30 * MINUTE_IN_SECONDS;
            case 'every_3_hours':
                return 3 * HOUR_IN_SECONDS;
            case 'every_6_hours':
                return 6 * HOUR_IN_SECONDS;
            case 'every_12_hours':
                return 12 * HOUR_IN_SECONDS;
            case 'daily':
                return DAY_IN_SECONDS;
            default:
                return HOUR_IN_SECONDS;
        }
    }
}
