<?php
namespace nulib\cache;

use nulib\app\app;
use nulib\db\CapacitorStorage;
use nulib\db\sqlite\SqliteStorage;
use nulib\ext\utils;

class cache {
  protected static ?string $dbfile = null;

  protected static function dbfile(): ?string {
    return self::$dbfile ??= app::get()->getVarfile("cache.db");
  }

  protected static ?CapacitorStorage $storage = null;

  static function storage(): CapacitorStorage {
    return self::$storage ??= new SqliteStorage(self::dbfile());
  }

  static function set_storage(CapacitorStorage $storage): CapacitorStorage {
    return self::$storage = $storage;
  }

  protected static ?CacheManager $manager = null;

  static function manager(): CacheManager {
    return self::$manager ??= new CacheManager();
  }

  static function set_manager(CacheManager $manager): CacheManager {
    return self::$manager = $manager;
  }

  static function nc(bool $noCache=true, bool $reset=false): void {
    self::manager()->setNoCache($noCache, $reset);
  }

  protected static function should_cache(string $id, ?string $groupId=null, bool $reset=true): bool {
    return self::manager()->shouldCache($id, $groupId, $reset);
  }

  static function verifix_id(&$cacheId): void {
    $cacheId ??= utils::uuidgen();
    if (is_array($cacheId)) {
      $keys = array_keys($cacheId);
      if (array_key_exists("id", $cacheId)) $idKey = "id";
      else $idKey = $keys[0] ?? null;
      $id = strval($cacheId[$idKey] ?? "");
      if (array_key_exists("group_id", $cacheId)) $groupIdKey = "group_id";
      else $groupIdKey = $keys[1] ?? null;
      $groupId = strval($cacheId[$groupIdKey] ?? "");
    } else {
      $id = strval($cacheId);
      $groupId = "";
    }
    # si le groupe ou le nom sont trop grand, en faire un hash
    if (strlen($groupId) > 32) $groupId = md5($groupId);
    if (strlen($id) > 128) $id = substr($id, 0, 128 - 32).md5($id);
    $cacheId = ["group_id" => $groupId, "id" => $id];
  }

  static function get(callable $compute, $dataId=null, ?string $file=null) {
    self::verifix_id($dataId);
    $file ??= "{$dataId["group_id"]}_{$dataId["id"]}";
    $noCache = !self::should_cache($dataId["id"], $dataId["group_id"]);
    return CacheFile::with($compute, $file)->get(null, $noCache);
  }

  static function all(?iterable $rows, $cursorId=null, ?string $file=null): iterable {
    self::verifix_id($cursorId);
    $file ??= "{$cursorId["group_id"]}_{$cursorId["id"]}_rows";
    $ccursorId = new CacheFile($file, function() use ($rows, $cursorId) {
      CursorChannel::with($cursorId, null)->rechargeAll($rows);
      return $cursorId;
    });
    $noCache = !self::should_cache($cursorId["id"], $cursorId["group_id"]);
    return CursorChannel::with($ccursorId->get(null, $noCache));
  }
}
