<?php

declare(strict_types=1);

namespace App\Framework\Process\Services;

/**
 * TCP Port Check Service
 *
 * Simple service to check if a TCP port is open without external dependencies.
 * Uses PHP's native fsockopen() with proper error suppression.
 */
final readonly class TcpPortCheckService
{
    private const DEFAULT_TIMEOUT = 2;

    /**
     * Check if a TCP port is open on a given host
     *
     * @param string $host Hostname or IP address
     * @param int $port Port number
     * @param int $timeout Timeout in seconds
     */
    public function isPortOpen(string $host, int $port, int $timeout = self::DEFAULT_TIMEOUT): bool
    {
        // Temporarily disable error handler to prevent warnings
        set_error_handler(function () {}, E_ALL);

        try {
            $errno = 0;
            $errstr = '';

            $socket = @fsockopen(
                $host,
                $port,
                $errno,
                $errstr,
                $timeout
            );

            if ($socket === false) {
                return false;
            }

            fclose($socket);

            return true;
        } finally {
            restore_error_handler();
        }
    }

    /**
     * Check if an SSL/TLS port is open
     *
     * @param string $host Hostname or IP address
     * @param int $port Port number (typically 443)
     * @param int $timeout Timeout in seconds
     */
    public function isSslPortOpen(string $host, int $port, int $timeout = self::DEFAULT_TIMEOUT): bool
    {
        // Temporarily disable error handler to prevent warnings
        set_error_handler(function () {}, E_ALL);

        try {
            $errno = 0;
            $errstr = '';

            $context = stream_context_create([
                'ssl' => [
                    'verify_peer' => false,
                    'verify_peer_name' => false,
                ],
            ]);

            $socket = @stream_socket_client(
                "ssl://{$host}:{$port}",
                $errno,
                $errstr,
                $timeout,
                STREAM_CLIENT_CONNECT,
                $context
            );

            if ($socket === false) {
                return false;
            }

            fclose($socket);

            return true;
        } finally {
            restore_error_handler();
        }
    }

    /**
     * Check multiple ports on a host
     *
     * @param string $host Hostname or IP address
     * @param array<int> $ports Array of port numbers
     * @return array<int, bool> Port => isOpen mapping
     */
    public function checkPorts(string $host, array $ports): array
    {
        $results = [];

        foreach ($ports as $port) {
            $results[$port] = $this->isPortOpen($host, $port);
        }

        return $results;
    }
}
