<?php

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Cache\Drivers;

use Flowaxy\Contracts\Cache\CacheInterface;

// @phpstan-ignore-next-line - APCu functions are PHP extensions
use function apcu_clear_cache;
// @phpstan-ignore-next-line - APCu functions are PHP extensions
use function apcu_dec;
// @phpstan-ignore-next-line - APCu functions are PHP extensions
use function apcu_delete;
// @phpstan-ignore-next-line - APCu functions are PHP extensions
use function apcu_exists;
// @phpstan-ignore-next-line - APCu functions are PHP extensions
use function apcu_fetch;
// @phpstan-ignore-next-line - APCu functions are PHP extensions
use function apcu_inc;
// @phpstan-ignore-next-line - APCu functions are PHP extensions
use function apcu_store;

/**
 * APCu драйвер для кеша
 *
 * @package Flowaxy\Infrastructure\Cache\Drivers
 */
final class ApcuCacheDriver implements CacheInterface
{
    private string $prefix = 'flowaxy:';

    public function __construct(string $prefix = 'flowaxy:')
    {
        $this->prefix = $prefix;
    }

    /**
     * Получить ключ с префиксом
     *
     * @param string $key
     * @return string
     */
    private function getKey(string $key): string
    {
        return $this->prefix . $key;
    }

    public function get(string $key, mixed $default = null): mixed
    {
        if (!function_exists('apcu_fetch')) {
            return $default;
        }

        $success = false;
        $value = apcu_fetch($this->getKey($key), $success);
        return $success ? $value : $default;
    }

    public function set(string $key, mixed $value, ?int $ttl = null): bool
    {
        if (!function_exists('apcu_store')) {
            return false;
        }

        $ttl = $ttl ?? 3600;
        return apcu_store($this->getKey($key), $value, $ttl);
    }

    public function has(string $key): bool
    {
        if (!function_exists('apcu_exists')) {
            return false;
        }

        return apcu_exists($this->getKey($key));
    }

    public function delete(string $key): bool
    {
        if (!function_exists('apcu_delete')) {
            return false;
        }

        return apcu_delete($this->getKey($key));
    }

    public function clear(): bool
    {
        if (!function_exists('apcu_clear_cache')) {
            return false;
        }

        return apcu_clear_cache();
    }

    public function pull(string $key, mixed $default = null): mixed
    {
        $value = $this->get($key, $default);
        if ($value !== $default) {
            $this->delete($key);
        }
        return $value;
    }

    public function forget(string $key): bool
    {
        return $this->delete($key);
    }

    public function increment(string $key, int $value = 1): int
    {
        if (!function_exists('apcu_inc')) {
            return 0;
        }

        $success = false;
        $result = apcu_inc($this->getKey($key), $value, $success);
        return $success ? $result : 0;
    }

    public function decrement(string $key, int $value = 1): int
    {
        if (!function_exists('apcu_dec')) {
            return 0;
        }

        $success = false;
        $result = apcu_dec($this->getKey($key), $value, $success);
        return $success ? $result : 0;
    }

    public function remember(string $key, callable $callback, ?int $ttl = null): mixed
    {
        $value = $this->get($key);
        if ($value !== null) {
            return $value;
        }

        $value = $callback();
        $this->set($key, $value, $ttl);
        return $value;
    }
}
