<?php

namespace Teknisa\Libs\Util;

use Psr\SimpleCache\CacheInterface; // PSR-16
use Zeedhi\Framework\Cache\Type\MongoImpl;
use Teknisa\Libs\Exception\Token as TokenException;
use MongoDB\BSON\UTCDateTime as MongoDate;

class MongoImplCustom extends MongoImpl implements CacheInterface
{
    protected const collectionAccess = 'OperadorAcesso';

    /**
     * Busca um token no MongoDB com regras de expiração customizadas.
     * (não sobrescreve get() do PSR-16, é um helper específico)
     */
    public function fetchToken(string $key, int $lifeTime = 0, bool $keepConnected = false): mixed {
        $documents = $this->mongo->find($this->getCollectionName(), ['_id' => $key]);
        $document = array_shift($documents);

        if ($document === null) {
            TokenException::invalidToken($key);
        }

        if ($this->isExpired($document) && !$keepConnected) {
            $this->delete($key);
            TokenException::expiredToken($key);
        }

        $docParams = $document[self::DATA_FIELD] ?? null;
        $docParams = $docParams ? unserialize($docParams->getData()) : null;

        // Renova o TTL
        $this->save($key, $docParams, $lifeTime);

        return $docParams;
    }

    /**
     * Check if the document is expired.
     */
    protected function isExpired(array $document): bool {
        return isset($document[self::EXPIRATION_FIELD]) &&
            $document[self::EXPIRATION_FIELD] instanceof MongoDate &&
            intval($document[self::EXPIRATION_FIELD]->toDateTime()->format('U')) < time();
    }

    public function findAccess(array $criteria): ?array {
        $documents = $this->mongo->find(self::collectionAccess, $criteria);
        return empty($documents) ? null : $documents[0];
    }

    public function saveAccess(array $concurrentAccess): void {
        if (empty($concurrentAccess['_id'])) {
            $this->mongo->insert(self::collectionAccess, $concurrentAccess);
        } else {
            $criteria = ['_id' => $concurrentAccess['_id']];
            unset($concurrentAccess['_id']);
            $this->mongo
                ->getCollection(self::collectionAccess)
                ->replaceOne($criteria, $concurrentAccess);
        }
    }

    public function deleteAccess(string $user, int $project, string $hash, int $organizationId): void {
        $criteria = [
            "nrProdutoId"   => $project,
            "cdOperador"    => $user,
            "dsChaveUltAcesso" => $hash,
            "nrOrg"         => $organizationId
        ];
        $this->mongo->getCollection(self::collectionAccess)->deleteOne($criteria);
    }
}
