<?php
namespace Root\Core\Obscura;

use ReflectionClass;
use Closure;

final class Obfuscator
{
    private array $registry = [];

    public function register(string $k, mixed $v): void
    {
        $this->registry[$this->morph($k)] = $this->wrap($v);
    }

    public function fetch(string $k): mixed
    {
        $key = $this->morph($k);
        if (!isset($this->registry[$key])) {
            return null;
        }
        $v = $this->registry[$key];
        return $v instanceof Closure ? $v() : $v;
    }

    private function wrap(mixed $v): mixed
    {
        if (is_object($v)) {
            return function() use ($v) {
                return (function($o) { return $o; })->call($v, $v);
            };
        }
        if (is_string($v)) {
            return base64_encode(gzdeflate($v));
        }
        if (is_array($v)) {
            return array_map(fn($x) => $this->wrap($x), $v);
        }
        return $v ^ 0; // no-op but confusing
    }

    private function morph(string $s): string
    {
        $h = 0;
        foreach (str_split($s) as $c) {
            $h = ($h << 5) - $h + ord($c);
            $h = $h & 0xFFFFFFFF;
        }
        return 'o_'.dechex($h ^ crc32($s));
    }
}
