<?php

/**
 * Драйвер кешу в пам'яті
 *
 * @package Flowaxy\Infrastructure\Cache\Drivers
 * @version 1.0.0
 */

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Cache\Drivers;

use Flowaxy\Infrastructure\Cache\CacheDriverInterface;
use Flowaxy\Support\Facades\Log;
use Throwable;

final class MemoryCacheDriver implements CacheDriverInterface
{
    /**
     * @var array<string, array{value: mixed, expires: int}>
     */
    private array $cache = [];

    /**
     * {@inheritDoc}
     */
    public function get(string $key, mixed $default = null): mixed
    {
        try {
            Log::Debug('MemoryCacheDriver::get: Retrieving from memory cache', ['key' => $key]);
        } catch (Throwable $e) {
            // Ignore logging errors
        }

        if (!isset($this->cache[$key])) {
            try {
                Log::Debug('MemoryCacheDriver::get: Key not found in memory cache', ['key' => $key]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return $default;
        }

        $item = $this->cache[$key];

        // Перевіряємо термін дії
        if ($item['expires'] > 0 && $item['expires'] < time()) {
            unset($this->cache[$key]);
            try {
                Log::Debug('MemoryCacheDriver::get: Key expired', ['key' => $key]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return $default;
        }

        try {
            Log::Debug('MemoryCacheDriver::get: Retrieved from memory cache', ['key' => $key]);
        } catch (Throwable $e) {
            // Ignore logging errors
        }

        return $item['value'];
    }

    /**
     * {@inheritDoc}
     */
    public function set(string $key, mixed $value, ?int $ttl = null): bool
    {
        try {
            Log::Debug('MemoryCacheDriver::set: Setting value in memory cache', ['key' => $key, 'ttl' => $ttl]);
        } catch (Throwable $e) {
            // Ignore logging errors
        }

        $expires = $ttl !== null ? time() + $ttl : 0;

        $this->cache[$key] = [
            'value' => $value,
            'expires' => $expires,
        ];

        try {
            Log::Info('MemoryCacheDriver::set: Value set in memory cache', ['key' => $key]);
        } catch (Throwable $e) {
            // Ignore logging errors
        }

        return true;
    }

    /**
     * {@inheritDoc}
     */
    public function delete(string $key): bool
    {
        try {
            Log::Debug('MemoryCacheDriver::delete: Deleting from memory cache', ['key' => $key]);
        } catch (Throwable $e) {
            // Ignore logging errors
        }

        if (isset($this->cache[$key])) {
            unset($this->cache[$key]);
            try {
                Log::Info('MemoryCacheDriver::delete: Deleted from memory cache', ['key' => $key]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return true;
        }

        try {
            Log::Debug('MemoryCacheDriver::delete: Key not found in memory cache', ['key' => $key]);
        } catch (Throwable $e) {
            // Ignore logging errors
        }

        return false;
    }

    /**
     * {@inheritDoc}
     */
    public function has(string $key): bool
    {
        if (!isset($this->cache[$key])) {
            return false;
        }

        $item = $this->cache[$key];

        // Перевіряємо термін дії
        if ($item['expires'] > 0 && $item['expires'] < time()) {
            unset($this->cache[$key]);
            return false;
        }

        return true;
    }

    /**
     * {@inheritDoc}
     */
    public function clear(): bool
    {
        try {
            Log::Debug('MemoryCacheDriver::clear: Clearing memory cache');
        } catch (Throwable $e) {
            // Ignore logging errors
        }

        $this->cache = [];

        try {
            Log::Info('MemoryCacheDriver::clear: Memory cache cleared');
        } catch (Throwable $e) {
            // Ignore logging errors
        }

        return true;
    }
}
