<?php
/**
 * SqlLogQueue - Framework-agnostic SQL-based queue implementation
 * Delegates database operations to a LogRepositoryInterface implementation
 */

namespace CloudXM\SDK\Queue;

use CloudXM\SDK\Support\HasLogger;

class SqlLogQueue implements LogQueueInterface
{
    use HasLogger;

    private LogRepositoryInterface $repository;
    private string $table;

    public function __construct(LogRepositoryInterface $repository, string $table = 'cloudxm_log_buffer')
    {
        $this->repository = $repository;
        $this->table = $table;
    }

    /**
     * Queue a log payload for later shipping
     */
    public function enqueue(array $payload): bool
    {
        // Handle different payload formats
        if (isset($payload['labels']) && isset($payload['entries'])) {
            // This is LokiRecordFormatter output - extract data from entries
            $rawMessage = isset($payload['entries'][0][1]) ? $payload['entries'][0][1] : '';
            $logData = json_decode($rawMessage, true);

            if (is_array($logData)) {
                // Extract individual fields for database storage
                $message = $logData['message'] ?? '';
                $level = $logData['level'] ?? $payload['labels']['level'] ?? 'INFO';
                $correlation_id = $logData['correlation_id'] ?? $logData['extra']['correlation_id'] ?? null;

                // Store original Loki payload in context for reference
                $context = json_encode($payload);
            } else {
                // Fallback if JSON parsing fails
                $message = $rawMessage;
                $level = $payload['labels']['level'] ?? 'INFO';
                $correlation_id = null;
                $context = json_encode($payload);
            }
        } else {
            // Direct log data - extract message and store in both fields for compatibility
            $message = $payload['message'] ?? '';

            // Also store full payload in context for admin display
            $context = json_encode(array_merge($payload['context'] ?? [], ['_full_payload' => $payload]));
            $level = $payload['level'] ?? 'INFO';
            $correlation_id = $payload['correlation_id'] ?? null;
        }

        $data = [
            'ts_ns' => (int)(microtime(true) * 1_000_000_000),
            'level' => $level,
            'message' => $message,
            'context' => $context,
            'correlation_id' => $correlation_id,
            'status' => 'pending',
            'attempts' => 0,
            'created_at' => current_time('mysql'),
        ];

        return $this->repository->insert($this->table, $data);
    }

    /**
     * Claim a batch of queued logs for processing
     */
    public function claimBatch(int $limit = 100, int $minId = 0): array
    {
        $rows = $this->repository->selectBatch($this->table, $limit, $minId);

        // Update attempts for claimed rows
        if (!empty($rows)) {
            $ids = array_column($rows, 'id');
            $this->repository->updateAttempts($this->table, $ids);
        }

        return $rows;
    }

    /**
     * Delete successfully processed logs
     */
    public function deleteMany(array $ids): bool
    {
        if (empty($ids)) {
            return true;
        }
        return $this->repository->delete($this->table, $ids);
    }

    /**
     * Bump retry attempts for failed logs
     */
    public function bumpAttempts(array $ids): bool
    {
        if (empty($ids)) {
            return true;
        }
        return $this->repository->bumpAttempts($this->table, $ids);
    }

    /**
     * Get queue stats
     */
    public function getStats(): array
    {
        return $this->repository->getStats($this->table);
    }

    /**
     * Clear all logs from the queue (reset for fresh start)
     */
    public function clearAll(): bool
    {
        return $this->repository->clearAll($this->table);
    }

    /**
     * Purge very old failed logs (older than max age)
     */
    public function purgeOld(int $maxAgeSeconds = 600): int
    {
        return $this->repository->purgeOld($this->table, $maxAgeSeconds);
    }

    /**
     * Log shipper events (for debugging API calls)
     */
    public function logShipperEvent(string $event, array $context = []): void
    {
        $this->log()->info("shipper.{$event}", $context);
    }
}