<?php

declare(strict_types=1);

namespace XBotControl;

use Psr\Http\Message\ServerRequestInterface;
use Clue\React\SQLite\DatabaseInterface;
use Clue\React\SQLite\Result;
use React\Promise\PromiseInterface;
use React\Promise\Promise;

class Request

{

    const METHOD = [
        'GET' => 1,
        'HEAD' => 2,
        'OPTIONS' => 3,
        'TRACE' => 4,
        'PUT' => 5,
        'DELETE' => 6,
        'POST' => 7,
        'PATCH' => 8,
        'CONNECT' => 9
    ];




    public static function save(ServerRequestInterface $request): PromiseInterface
    {
        $realIp = self::getRealIP($request);
        $userAgent = $request->getHeaderLine('User-Agent') ?: 'Unknown';
        $headers = json_encode($request->getHeaders(), JSON_UNESCAPED_UNICODE);
        $uri = $request->getUri();
        $storage = Storage::getInstance();

        // Use parallel promises for ID generation to avoid waiting for each in sequence
        $idPromises = [
            'id_ip' => $storage::getId('ip', $realIp),
            'id_domain' => $storage::getId('domain', $uri->getHost()),
            'id_path' => $storage::getId('path', $uri->getPath()),
            'id_useragent' => $storage::getId('useragent', $userAgent),
            'id_headers' => $storage::getId('headers', md5($headers)),
        ];

        return \React\Promise\all($idPromises)
            ->then(function ($resolvedValues) use ($request, $storage) {
                // Set resolved values efficiently
                $resolvedValues['id_method'] = self::METHOD[$request->getMethod()] ?? 0;
                $resolvedValues['timestamp'] = time();

                // Directly save data asynchronously
                return $storage::insert('request', $resolvedValues);
            })
            ->then(function () {
                return \React\Http\Message\Response::plaintext('');
            });
    }

    public static function getRealIP(ServerRequestInterface $request): string
    {
        $cfConnectingIp = $request->getHeaderLine('CF-Connecting-IP');
        if (!empty($cfConnectingIp)) {
            return $cfConnectingIp;
        }

        $xForwardedFor = $request->getHeaderLine('X-Forwarded-For');
        if (!empty($xForwardedFor)) {
            return explode(',', $xForwardedFor)[0];
        }

        $remoteAddr = $request->getServerParams()['REMOTE_ADDR'] ?? '0.0.0.0';
        return $remoteAddr;
    }
}
