<?php

namespace PulseRadar;

class PulseRadar
{
    private string  $apiKey;
    private string  $ingestUrl;
    private string  $source;
    private string  $host;
    private ?string $serverId;
    private array   $queue = [];
    private int     $batchSize;
    private bool    $async;

    public function __construct(array $options)
    {
        if (empty($options['api_key'])) {
            throw new \InvalidArgumentException('api_key is required');
        }
        $this->apiKey    = $options['api_key'];
        $this->serverId  = $options['server_id'] ?? null;
        $this->ingestUrl = rtrim($options['ingest_url'] ?? 'https://ingest.pulseradar.cloud', '/') . '/v1/logs';
        $this->source    = $options['source'] ?? 'php';
        $this->host      = $options['host'] ?? gethostname();
        $this->batchSize = $options['batch_size'] ?? 50;
        $this->async     = $options['async'] ?? false;
    }

    public function debug(string $message, array $fields = []): void
    {
        $this->log('debug', $message, $fields);
    }

    public function info(string $message, array $fields = []): void
    {
        $this->log('info', $message, $fields);
    }

    public function warning(string $message, array $fields = []): void
    {
        $this->log('warning', $message, $fields);
    }

    public function error(string $message, array $fields = []): void
    {
        $this->log('error', $message, $fields);
    }

    public function critical(string $message, array $fields = []): void
    {
        $this->log('critical', $message, $fields);
    }

    /**
     * Capture a Throwable and send it as an error log with type, file, line and stack trace.
     */
    public function captureException(\Throwable $e, array $fields = []): void
    {
        $this->error($e->getMessage(), array_merge($fields, [
            'exception_type' => get_class($e),
            'exception_file' => $e->getFile() . ':' . $e->getLine(),
            'stack'          => implode(' | ', array_slice(explode("\n", $e->getTraceAsString()), 0, 5)),
        ]));
    }

    public function log(string $level, string $message, array $fields = []): void
    {
        $entry = [
            'level'     => $level,
            'message'   => $message,
            'timestamp' => (new \DateTimeImmutable())->format(\DateTimeInterface::RFC3339),
            'source'    => $this->source,
            'host'      => $this->host,
            'fields'    => array_map('strval', $fields),
        ];

        if ($this->async) {
            $this->queue[] = $entry;
            if (count($this->queue) >= $this->batchSize) {
                $this->flush();
            }
        } else {
            $this->send([$entry]);
        }
    }

    public function flush(): void
    {
        if (empty($this->queue)) {
            return;
        }
        $this->send($this->queue);
        $this->queue = [];
    }

    private function send(array $entries): void
    {
        $payload = json_encode($entries, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

        $headers = [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->apiKey,
            'User-Agent: pulseradar-php/1.0',
        ];
        if ($this->serverId !== null) {
            $headers[] = 'X-Server-Id: ' . $this->serverId;
        }

        $ctx = stream_context_create([
            'http' => [
                'method'        => 'POST',
                'header'        => implode("\r\n", $headers),
                'content'       => $payload,
                'timeout'       => 3,
                'ignore_errors' => true,
            ],
        ]);

        @file_get_contents($this->ingestUrl, false, $ctx);
    }

    public function __destruct()
    {
        $this->flush();
    }
}
