<?php

declare(strict_types=1);

namespace SiteFort\Modules\Firewall\WHOIS;

// If this file is called directly, abort.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * WHOIS Lookup via RDAP protocol.
 *
 * Performs IP address WHOIS lookups using the modern REST-based RDAP protocol,
 * with fallback from RIPE to ARIN registries.
 *
 */
class WHOISLookup {

    /**
     * Perform WHOIS lookup for an IP address.
     * Uses the RDAP protocol (modern REST-based WHOIS).
     *
     * @param string $ip The IP address to look up.
     * @return array|\WP_Error WHOIS result array on success, WP_Error on failure.
     */
    public function lookup( string $ip ) {
        if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
            return new \WP_Error( 'invalid_ip', 'Invalid IP address.' );
        }

        // Check cache first
        $cache_key = 'sitefort_whois_' . md5( $ip );
        $cached    = get_transient( $cache_key );
        if ( $cached !== false ) {
            return $cached;
        }

        // Use RDAP (REST-based WHOIS replacement)
        $url      = 'https://rdap.db.ripe.net/ip/' . $ip;
        $response = wp_remote_get( $url, [ 'timeout' => 5 ] );

        $result = [
            'ip'            => $ip,
            'network'       => '',
            'name'          => '',
            'description'   => '',
            'country'       => '',
            'abuse_contact' => '',
            'start_address' => '',
            'end_address'   => '',
            'raw'           => '',
        ];

        if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
            $body = json_decode( wp_remote_retrieve_body( $response ), true );
            if ( $body ) {
                $result['network']       = $body['handle'] ?? '';
                $result['name']          = $body['name'] ?? '';
                $result['country']       = $body['country'] ?? '';
                $result['start_address'] = $body['startAddress'] ?? '';
                $result['end_address']   = $body['endAddress'] ?? '';

                // Extract abuse contact
                if ( ! empty( $body['entities'] ) ) {
                    foreach ( $body['entities'] as $entity ) {
                        $roles = $entity['roles'] ?? [];
                        if ( in_array( 'abuse', $roles, true ) ) {
                            $vcards = $entity['vcardArray'] ?? [];
                            if ( ! empty( $vcards[1] ) && is_array( $vcards[1] ) ) {
                                foreach ( $vcards[1] as $vcard ) {
                                    if ( is_array( $vcard ) && isset( $vcard[0] ) && $vcard[0] === 'email' ) {
                                        $result['abuse_contact'] = $vcard[3] ?? '';
                                    }
                                }
                            }
                        }
                    }
                }

                // Description from remarks
                if ( ! empty( $body['remarks'] ) ) {
                    foreach ( $body['remarks'] as $remark ) {
                        if ( ! empty( $remark['description'] ) ) {
                            $result['description'] = implode( "\n", $remark['description'] );
                            break;
                        }
                    }
                }
            }
        } else {
            // Fallback to ARIN RDAP
            $url2      = 'https://rdap.arin.net/registry/ip/' . $ip;
            $response2 = wp_remote_get( $url2, [ 'timeout' => 5 ] );

            if ( ! is_wp_error( $response2 ) && wp_remote_retrieve_response_code( $response2 ) === 200 ) {
                $body = json_decode( wp_remote_retrieve_body( $response2 ), true );
                if ( $body ) {
                    $result['network']       = $body['handle'] ?? '';
                    $result['name']          = $body['name'] ?? '';
                    $result['country']       = $body['country'] ?? '';
                    $result['start_address'] = $body['startAddress'] ?? '';
                    $result['end_address']   = $body['endAddress'] ?? '';
                }
            }
        }

        // Cache for 1 hour
        set_transient( $cache_key, $result, HOUR_IN_SECONDS );

        return $result;
    }
}
