<?php

namespace App\Helpers;

use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class VulnerabilityScannerApiUtils
{
    protected int $timeout = 120;

    protected int $retryTimes = 1;

    public function timeout(int $seconds): self
    {
        $this->timeout = $seconds;

        return $this;
    }

    public function retryTimes(int $times): self
    {
        $this->retryTimes = $times;

        return $this;
    }

    public function checkport_public($host, $port, $protocol): array
    {
        return $this->post('/checkport', [
            'host' => $host,
            'port' => $port,
            'protocol' => $protocol
        ]);
    }

    public function discover_public(string $domain): array
    {
        $json = $this->post('/discover', array_merge(
            [
                'domain' => $domain,
            ]
        ));
        if (isset($json['subdomains'])) {
            $json['subdomains'] = collect($json['subdomains'])
                ->filter(fn(string $subdomain) => !empty($subdomain))
                ->toArray();
        }
        return $json;
    }

    public function screenshot_public(string $domain): array
    {
        return $this->post('/screenshot', array_merge(
            [
                'url' => $domain,
            ]
        ));
    }

    public function start_scan_public($asset, $ip, $port, $protocol): array
    {
        return $this->post('/start_scan', array_merge(
            [
                'hostname' => $asset,
                'ip' => $ip,
                'port' => $port,
                'protocol' => $protocol,
                'client' => null,
                'tags' => [],
                'tests' => [],
            ]
        ));
    }

    public function task_masscan_public(string $host): array
    {
        return $this->post('/task-masscan', [
            'input' => [
                $host
            ]
        ]);
    }

    public function task_nmap_public(string $host): array
    {
        return $this->post('/task-nmap', [
            'input' => [
                $host
            ]
        ]);
    }

    public function task_status_public(string $id): array
    {
        return $this->get('/task_status/' . $id);
    }

    public function task_result_public(string $id): array
    {
        return $this->get('/task_result/' . $id);
    }

    public function task_start_scan_public($hostname, $ip, $port, $protocol, $tags): array
    {
        return $this->post('/start_scan', [
            "hostname" => $hostname,
            "ip" => $ip,
            "port" => $port,
            "protocol" => $protocol,
            "client" => "",
            "tags" => $tags
        ]);
    }

    public function task_get_scan_public(string $scanId): array
    {
        return $this->get('/get_scan/' . $scanId);
    }

    public function ip_geoloc_public(string $ip): array
    {
        return $this->post('/ipgeoloc', [
            'input' => $ip
        ]);
    }

    public function ip_whois_public(string $ip): array
    {
        return [];
        /*
        return $this->post('/ipwhois', [
            'input' => $ip
        ]);
        */
    }

    public function task_discover_full_public(array $urls): array
    {
        return $this->post('/discover-full-task', [
            'input' => $urls
        ]);
    }

    public function discover_from_ip_public(string $ip): array
    {
        return $this->post('/rapid_reverse_ip', [
            'input' => $ip
        ]);
    }

    public function external_ips(): array
    {
        // ../.. to remove /api/v1/ to go back to root
        return $this->get('/../../sentinel_external_ips');
    }

    public function matched_cves(): array
    {
        // ../.. to remove /api/v1/ to go back to root
        return $this->get('/../../cves-list');
    }

    public function hello_mongo(): array
    {
        // ../.. to remove /api/v1/ to go back to root
        return $this->get('/../../hellomongo');
    }

    public function celery(): array
    {
        // ../.. to remove /api/v1/ to go back to root
        return $this->get('/../../celery');
    }

    private function get($endpoint): array
    {
        $url = Config::get('towerify.adversarymeter.api') . $endpoint;

        try {
            $response = Http::withBasicAuth(
                config('towerify.adversarymeter.api_username'),
                config('towerify.adversarymeter.api_password')
            )->timeout($this->timeout)
                ->retry($this->retryTimes)
                ->withHeaders([
                    'Accept' => 'application/json',
                ])->get($url);
        } catch (ConnectionException $e) {
            Log::error($e->getMessage());
            return [];
        }

        if ($response->successful()) {
            $json = $response->json();
            // Log::debug($json);
            return $json ?: [];
        }
        Log::error($response->body());
        return [];
    }

    private function post($endpoint, $json): array
    {
        $url = Config::get('towerify.adversarymeter.api') . $endpoint;

        try {
            $response = Http::withBasicAuth(
                config('towerify.adversarymeter.api_username'),
                config('towerify.adversarymeter.api_password')
            )
                ->timeout($this->timeout)
                ->retry($this->retryTimes)
                ->withHeaders([
                    'Accept' => 'application/json',
                ])
                ->post($url, $json);
        } catch (ConnectionException $e) {
            Log::error($e->getMessage());
            return [];
        }

        if ($response->successful()) {
            $json = $response->json();
            // Log::debug($json);
            return $json ?: [];
        }
        Log::error($response->body());
        return [];
    }
}
