<?php
declare(strict_types=1);

namespace FreshCloud\Mail\Log;

use FreshCloud\Mail\PocketBaseAdapter\PocketBaseAdapter;

final class InMemoryLogger implements Logger
{
    private array $buffer = [];
    private int $bufferSize = 10000;
    private array $drivers = [];
    private array $metrics = [
        'freshcloud_mail_log_writes_total' => [
            'levels' => ['debug' => 0, 'info' => 0, 'warning' => 0, 'error' => 0, 'critical' => 0],
            'statuses' => ['success' => 0, 'failure' => 0]
        ]
    ];

    public function __construct(
        private ?PocketBaseAdapter $pb = null,
        array $drivers = []
    ) {
        foreach ($drivers as $driver) {
            $this->addDriver($driver);
        }
    }

    public function write(LogType $level, string $message, array $context = []): void
    {
        $entry = LogEntry::create(
            level: $level,
            message: $message,
            context: $context,
            user_id: $context['user_id'] ?? null,
            account_id: $context['account_id'] ?? null,
            source: 'in_memory'
        );

        $this->metrics['freshcloud_mail_log_writes_total']['levels'][strtolower($level->name)]++;

        if ($level === LogType::Critical) {
            $this->writeToDrivers($entry);
        } else {
            $this->addToBuffer($entry);
        }
    }

    public function audit(string $action, array $context = []): void
    {
        if (!isset($context['user_id'])) {
            throw new AuthBoundaryViolation('Audit action requires user_id in context');
        }

        $entry = LogEntry::create(
            level: LogType::Info,
            message: "Audit action: {$action}",
            context: $context,
            user_id: $context['user_id'],
            account_id: $context['account_id'] ?? null,
            action: $action,
            source: 'audit'
        );

        $this->writeToDrivers($entry);
    }

    public function flush(): void
    {
        foreach ($this->buffer as $entry) {
            $this->writeToDrivers($entry);
        }
        $this->buffer = [];
    }

    public function getRecentActivity(string $userId, int $limit = 50): array
    {
        $filtered = array_filter($this->buffer, fn($e) => $e->user_id === $userId);
        $sorted = array_reverse($filtered);
        return array_slice($sorted, 0, $limit);
    }

    public function getRecentErrors(string $userId, \DateTimeInterface $since): array
    {
        $levels = [LogType::Error, LogType::Critical];
        $filtered = array_filter($this->buffer, function($e) use ($userId, $since, $levels) {
            return $e->user_id === $userId && 
                   in_array($e->level, $levels, true) && 
                   $e->timestamp > $since;
        });
        return array_reverse($filtered);
    }

    public function addDriver(Driver $driver): void
    {
        $this->drivers[] = $driver;
    }

    public function getMetrics(): array
    {
        return $this->metrics;
    }

    public function log(string $event, array $context = []): void
    {
        $this->write(LogType::Info, $event, $context);
    }

    private function addToBuffer(LogEntry $entry): void
    {
        if (count($this->buffer) >= $this->bufferSize) {
            array_shift($this->buffer);
        }
        $this->buffer[] = $entry;
    }

    private function writeToDrivers(LogEntry $entry): void
    {
        foreach ($this->drivers as $driver) {
            try {
                $driver->write($entry);
                $this->metrics['freshcloud_mail_log_writes_total']['statuses']['success']++;
            } catch (\Throwable $e) {
                $this->metrics['freshcloud_mail_log_writes_total']['statuses']['failure']++;
                // Log but don't propagate - in-memory handles failures
            }
        }
    }
}