<?php

declare(strict_types=1);

namespace SiteFort\Modules\Cloud\Services;

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

use SiteFort\Includes\RemoteUrlValidator;
use SiteFort\Modules\Cloud\SecureApi;
use SiteFort\Modules\Cloud\Service\CloudSettings;

/**
 * CloudScanner Service.
 *
 * Handles Cloud preflight, upload, reputation, and auxiliary intelligence calls
 * used by the scanner runtime.
 */
class CloudScanner {
    
    /**
     * Upload a file to S3 via presigned URL.
     * 
     * @param string $url Presigned PUT URL.
     * @param string $file_path Local file path (absolute).
     * @return bool|\WP_Error Success or Error.
     */
    public function upload_to_s3( string $url, string $file_path ) {
        if ( ! self::is_trusted_upload_host( $url ) ) {
            return new \WP_Error( 'invalid_upload_host', 'Presigned URL points to an untrusted host.' );
        }

        if ( ! file_exists( $file_path ) || ! is_readable( $file_path ) ) {
            return new \WP_Error( 'file_error', "File not found or not readable: $file_path" );
        }

        $content = @file_get_contents( $file_path );
        if ( $content === false ) {
            return new \WP_Error( 'file_error', "Failed to read file contents: $file_path" );
        }

	        $response = wp_remote_request( $url, [
	            'method'  => 'PUT',
	            'body'    => $content,
	            'headers' => [
	                'Content-Type' => 'application/octet-stream',
	            ],
	            'timeout' => 300, // 5 minutes for large files
	            'sslverify' => true,
	            'redirection' => 0,
	            'reject_unsafe_urls' => true,
	        ] );

        if ( is_wp_error( $response ) ) {
            return $response;
        }

        $code = (int) wp_remote_retrieve_response_code( $response );
        if ( $code < 200 || $code >= 300 ) {
            return new \WP_Error( 's3_upload_failed', "S3 Upload failed (HTTP $code)" );
        }

        return true;
    }

    /**
     * Bulk upload files to S3 using the WordPress HTTP API.
     *
     * This path intentionally reuses the single-file uploader instead of
     * maintaining a separate cURL transport.
     *
     * @param array $upload_jobs Array of ['path' => local_path, 'url' => presigned_url].
     * @return array Results: ['path' => true/WP_Error].
     */
    public function bulk_upload_to_s3( array $upload_jobs ): array {
        if ( empty( $upload_jobs ) ) {
            return [];
        }

        $results = [];
        foreach ( $upload_jobs as $job ) {
            $path = (string) ( $job['path'] ?? '' );
            $url  = (string) ( $job['url'] ?? '' );
            $results[ $path ] = $this->upload_to_s3( $url, $path );
        }

        return $results;
    }

    /**
     * Run preflight check to validate environment and get signature version.
     * 
     * @return array|\WP_Error Preflight result or error.
     */
    public function preflight_check() {
        $settings = CloudSettings::get_all();
        $api = new SecureApi( 
            $settings['license_key'] ?? '', 
            $settings['site_token'] ?? '',
            $settings['site_secret'] ?? ''
        );
        
        return $api->get( 'services/intelligence/scan/preflight' );
    }


    /**
     * Check network reputation (IP/Domain/External Links) via Cloud.
     *
     * @param string $ip Server IP.
     * @param string $domain Site Domain.
     * @param array  $ext_links External URLs found on the site.
     * @return array|\WP_Error Results or error.
     */
    public function check_reputation( string $ip, string $domain, array $ext_links = [] ) {
        $settings = CloudSettings::get_all();
        $api = new SecureApi(
            $settings['license_key'] ?? '',
            $settings['site_token'] ?? '',
            $settings['site_secret'] ?? ''
        );

        $body = [];
        if ( $ip !== '' ) {
            $body['ip'] = $ip;
        }
        if ( $domain !== '' ) {
            $body['domain'] = $domain;
        }
        if ( ! empty( $ext_links ) ) {
            $body['ext_links'] = array_values( $ext_links );
        }

        return $api->post( 'services/intelligence/reputation', $body );
    }

    /**
     * Get suspicious/malicious WordPress usernames from Cloud.
     * Used to detect backdoor accounts created by malware.
     * Cached for 24 hours.
     * 
     * @return array List of suspicious usernames/patterns.
     */
    public function get_user_patterns() {
        $cache_key = 'sitefort_suspicious_usernames';
        $cached = get_transient( $cache_key );
        if ( is_array( $cached ) && ! empty( $cached ) ) {
            return $cached;
        }

        $settings = CloudSettings::get_all();
        $api = new SecureApi( 
            $settings['license_key'] ?? '', 
            $settings['site_token'] ?? '',
            $settings['site_secret'] ?? ''
        );
        
        $response = $api->get( 'services/intelligence/suspicious-usernames' );
        
        if ( ! is_wp_error( $response ) && isset( $response['users'] ) ) {
            set_transient( $cache_key, $response['users'], DAY_IN_SECONDS );
            return $response['users'];
        }

        // Strict Mode: No fallback. Cloud is mandatory for new patterns.
        return is_wp_error( $response ) ? $response : new \WP_Error( 'cloud_failed', 'Failed to fetch user patterns from Cloud' );
    }

    /**
     * Get weak password dictionary from Cloud.
     * Cached for 1 day.
     * 
     * @return array List of passwords.
     */
    public function get_password_dictionary() {
        $cache_key = 'sitefort_password_dict';
        $cached = get_transient( $cache_key );
        if ( is_array( $cached ) && ! empty( $cached ) ) {
            return $cached;
        }

        $settings = CloudSettings::get_all();
        $api = new SecureApi( 
            $settings['license_key'] ?? '', 
            $settings['site_token'] ?? '',
            $settings['site_secret'] ?? ''
        );
        
        $response = $api->get( 'services/intelligence/dictionary' );
        
        if ( ! is_wp_error( $response ) && isset( $response['passwords'] ) ) {
            set_transient( $cache_key, $response['passwords'], DAY_IN_SECONDS );
            return $response['passwords'];
        }

        // Strict Mode: No fallback. Cloud is mandatory.
        return is_wp_error( $response ) ? $response : new \WP_Error( 'cloud_failed', 'Failed to fetch password dictionary from Cloud' );
    }

    /**
     * Check if a presigned URL points to a trusted S3/R2 host.
     *
     * @param string $url The presigned URL to validate.
     * @return bool True if the host is trusted.
     */
    private static function is_trusted_upload_host( string $url ): bool {
        return RemoteUrlValidator::is_trusted_https_url( $url, [], RemoteUrlValidator::STORAGE_HOST_SUFFIXES );
    }
}
