<?php

namespace Velis\Db;

use InvalidArgumentException;
use ReflectionException;
use Velis\Cache\CacheInterface;
use Velis\Model\Cacheable;
use Velis\Model\DataObject;

/**
 * @template T of DataObject
 */
class EntityCache
{
    /**
     * @var EntityRepository<T>
     */
    private EntityRepository $repository;

    /**
     * @param class-string<T> $entityClass
     * @throws InvalidArgumentException
     * @throws ReflectionException
     */
    public function __construct(Db $db, private readonly string $entityClass, private readonly CacheInterface $cache)
    {
        if (!is_a($this->entityClass, Cacheable::class, true)) {
            throw new InvalidArgumentException(sprintf('%s does not implement %s interface', $this->entityClass, Cacheable::class));
        }

        $this->repository = $db->getRepository($this->entityClass);
    }

    /**
     * @return T[]
     * @throws ReflectionException
     */
    public function getCachedList(): array
    {
        $cacheName = $this->getCacheName();

        if ($this->cache->has($cacheName)) {
            return $this->cache->get($cacheName);
        }

        $list = $this->repository->findAll();
        $this->cache->set($cacheName, $list);

        return $list;
    }

    private function getCacheName(): string
    {
        return sprintf('entities_%s', str_replace('\\', '_', $this->entityClass));
    }

    /**
     * @return T|null
     * @throws ReflectionException
     */
    public function get(int|string $id)
    {
        $list = $this->getCachedList();

        return $list[$id] ?? null;
    }

    public function unset(): void
    {
        $cacheName = $this->getCacheName();
        $this->cache->delete($cacheName);
    }
}
