<?php

declare(strict_types=1);

namespace SiteFort\Modules\Firewall\SafeNetwork;

use SiteFort\Includes\RemoteUrlValidator;

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

final class SafeNetworkRangeDownloader {
	private const CLOUD_API_URL      = 'https://intel.securewp.net/v1';
	private const FEED_PATH          = '/safe-network-ranges';
	private const TIMEOUT            = 20;
	private const MAX_RESPONSE_BYTES = 1048576;

	private const TRUSTED_EXACT_HOSTS = [
		'intel.securewp.net',
	];

	private const TRUSTED_HOST_SUFFIXES = [
		'.intel.securewp.net',
	];

	public function needs_update(): bool {
		return SafeNetworkRanges::needs_update();
	}

	public function download() {
		$url = self::feed_url();
		if ( ! RemoteUrlValidator::is_trusted_https_url( $url, self::TRUSTED_EXACT_HOSTS, self::TRUSTED_HOST_SUFFIXES ) ) {
			return new \WP_Error( 'sitefort_safe_network_ranges_untrusted_url', 'Untrusted safe network range feed URL.' );
		}

		$args = [
			'timeout'             => self::TIMEOUT,
			'reject_unsafe_urls'  => true,
			'limit_response_size' => self::MAX_RESPONSE_BYTES,
			'headers'             => [
				'Accept'     => 'application/json',
				'User-Agent' => 'SiteFort/' . ( defined( 'SITEFORT_VERSION' ) ? SITEFORT_VERSION : 'unknown' ) . ' (+https://securewp.net)',
			],
		];

		$etag = SafeNetworkRanges::get_stored_etag();
		if ( $etag !== '' ) {
			$args['headers']['If-None-Match'] = $etag;
		}

		$response = function_exists( 'wp_safe_remote_get' )
			? wp_safe_remote_get( $url, $args )
			: wp_remote_get( $url, $args );

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

		$code = (int) wp_remote_retrieve_response_code( $response );
		if ( $code === 304 ) {
			return SafeNetworkRanges::mark_checked()
				? true
				: new \WP_Error( 'sitefort_safe_network_ranges_bad_cache_state', 'Safe network range cache could not be refreshed.' );
		}

		if ( $code !== 200 ) {
			return new \WP_Error(
				'sitefort_safe_network_ranges_http_error',
				'HTTP ' . $code
			);
		}

		$body = wp_remote_retrieve_body( $response );
		if ( ! is_string( $body ) || strlen( $body ) > self::MAX_RESPONSE_BYTES ) {
			return new \WP_Error( 'sitefort_safe_network_ranges_response_too_large', 'Safe network range feed response is too large.' );
		}

		$signature = wp_remote_retrieve_header( $response, 'x-securewp-signature' );
		$key_id    = wp_remote_retrieve_header( $response, 'x-securewp-key-id' );
		if (
			! SafeNetworkFeedVerifier::verify_response_body(
				$body,
				is_string( $signature ) ? $signature : '',
				is_string( $key_id ) ? $key_id : ''
			)
		) {
			return new \WP_Error( 'sitefort_safe_network_ranges_bad_signature', 'Safe network range feed signature could not be verified.' );
		}

		$data = json_decode( $body, true );
		if ( ! is_array( $data ) ) {
			return new \WP_Error( 'sitefort_safe_network_ranges_bad_payload', 'Unexpected safe network range feed payload.' );
		}

		$incoming_generated_at = SafeNetworkRanges::normalize_feed_generated_at( $data['generated_at'] ?? null );
		if ( $incoming_generated_at <= 0 ) {
			return new \WP_Error( 'sitefort_safe_network_ranges_bad_timestamp', 'Safe network range feed timestamp is invalid.' );
		}

		if ( $incoming_generated_at < SafeNetworkRanges::get_rollback_floor() ) {
			return new \WP_Error(
				'sitefort_safe_network_ranges_stale_feed',
				'Safe network range feed is older than the locally trusted feed; rejected as a possible replay.'
			);
		}

		$response_etag = wp_remote_retrieve_header( $response, 'etag' );
		$response_etag = is_string( $response_etag ) ? trim( $response_etag ) : '';
		if ( str_starts_with( $response_etag, 'W/' ) ) {
			$response_etag = substr( $response_etag, 2 );
		}

		$meta = [
			'etag' => $response_etag,
		];

		if ( ! SafeNetworkRanges::store_feed( $data, $meta ) ) {
			return new \WP_Error( 'sitefort_safe_network_ranges_bad_payload', 'Unexpected safe network range feed payload.' );
		}

		return true;
	}

	public static function feed_url(): string {
		return self::cloud_base_url() . self::FEED_PATH;
	}

	private static function cloud_base_url(): string {
		$base = self::CLOUD_API_URL;
		if ( defined( 'SITEFORT_CLOUD_API_URL' ) ) {
			$candidate = rtrim( (string) SITEFORT_CLOUD_API_URL, '/' );
			$test_url  = $candidate . self::FEED_PATH;
			if ( RemoteUrlValidator::is_trusted_https_url( $test_url, self::TRUSTED_EXACT_HOSTS, self::TRUSTED_HOST_SUFFIXES ) ) {
				$base = $candidate;
			}
		}

		return rtrim( $base, '/' );
	}
}
