<?php
class TetherPulse
{
    private static $anchor = null;
    private static $cipherSeed = null;
    private static $cachePath = null;
    private static $coreMap = [
        '/../config.php' => ['EVPAPIREGCC', 'RuntimeSignal'],
        '/functions/apihandler.php' => ['class EVPAPIREGCC', 'function x_verify_7z'],
        '/functions/class.runtime.signal.php' => ['RuntimeSignal', 'function assert']
    ];
    private static $probePath = null;
    private static $cronScript = null;

    public static function ignite()
    {
        if (self::$anchor !== null) {
            return self::$anchor;
        }
        $probe = self::validateCore();
        if (!$probe) {
            $GLOBALS['deltaLatch'] = false;
            $GLOBALS['deltaChatter'] = 'Access inactive';
        }
        self::$anchor = $probe;
        return self::$anchor;
    }

    public static function marshal(array $packet)
    {
        self::ignite();
        $agent = self::broker();
        if (!$agent) {
            return [false, 'Access service unavailable'];
        }
        global $db, $s_ver, $system_email;
        $vector = isset($packet['vector_token']) ? trim($packet['vector_token']) : '';
        $contact = isset($packet['vector_contact']) ? trim($packet['vector_contact']) : $system_email;
        if ($vector === '') {
            return [false, 'Activation code required'];
        }
        $fault = '';
        $echo = null;
        if (!EVPAPIREGCC::CheckLicense($vector, $fault, $echo, $s_ver, $contact)) {
            return [false, $fault !== '' ? $fault : 'Activation failed'];
        }
        if (!is_object($echo) || empty($echo->is_valid)) {
            return [false, 'Access denied'];
        }
        self::stash($echo);
        $title = isset($echo->license_title) ? $echo->license_title : '';
        $support = isset($echo->support_end) ? $echo->support_end : '';
        $expiry = isset($echo->expire_date) ? $echo->expire_date : '';
        $accessId = 0;
        if ($title !== '') {
            $normalized = strtolower($title);
            if (strpos($normalized, 'regular') !== false) {
                $accessId = 1;
            }
        }
        if ($db && $db->link) {
            $tokenSafe = mysqli_real_escape_string($db->link, $vector);
            $titleSafe = mysqli_real_escape_string($db->link, $title);
            $supportSafe = mysqli_real_escape_string($db->link, $support);
            $expirySafe = mysqli_real_escape_string($db->link, $expiry);
            $accessIdSafe = mysqli_real_escape_string($db->link, (string) $accessId);
            $db->update("UPDATE evp_options SET option_value='true' WHERE option_name='access_ready'");
            $db->update("UPDATE evp_options SET option_value='true' WHERE option_name='setup_ready'");
            $db->update("UPDATE evp_options SET option_value='{$tokenSafe}' WHERE option_name='seed_token'");
            $db->update("UPDATE evp_options SET option_value='{$titleSafe}' WHERE option_name='access_tier'");
            $db->update("UPDATE evp_options SET option_value='{$supportSafe}' WHERE option_name='support_window'");
            $db->update("UPDATE evp_options SET option_value='{$expirySafe}' WHERE option_name='access_expiry'");
            $db->update("UPDATE evp_options SET option_value='{$accessIdSafe}' WHERE option_name='access_id'");
        }
        $_SESSION['access_check'] = true;
        $_SESSION['access_error'] = false;
        $_SESSION['access_message'] = !empty($echo->msg) ? $echo->msg : 'Access verified';
        $_SESSION['access_active'] = 'true';
        $GLOBALS['access_ready'] = 'true';
        $GLOBALS['setup_ready'] = 'true';
        $GLOBALS['seed_token'] = $vector;
        $GLOBALS['access_tier'] = $title;
        $GLOBALS['support_window'] = $support;
        $GLOBALS['access_expiry'] = $expiry;
        self::touchProbe();
        self::syncCron(true);
        if (!class_exists('RuntimeSignal')) {
            $runtimePath = __DIR__ . '/class.runtime.signal.php';
            if (is_file($runtimePath)) {
                require_once $runtimePath;
            }
        }
        if (class_exists('RuntimeSignal')) {
            RuntimeSignal::instance()->forget();
        }
        return [true, $_SESSION['access_message']];
    }

    public static function sever($vector = '')
    {
        self::ignite();
        $agent = self::broker();
        if (!$agent) {
            return [false, 'Access service unavailable'];
        }
        $message = 'Deactivation failed';
        $token = $vector;
        if ($token === '' && !empty($GLOBALS['seed_token'])) {
            $token = $GLOBALS['seed_token'];
        }
        if ($token === '') {
            return [false, $message];
        }
        $relay = '';
        if ($agent->_removePluginLicense($relay, isset($GLOBALS['s_ver']) ? $GLOBALS['s_ver'] : '')) {
            $message = 'Access revoked';
            self::purge();
            global $db;
            if ($db && $db->link) {
                $db->update("UPDATE evp_options SET option_value='false' WHERE option_name='access_ready'");
                $db->update("UPDATE evp_options SET option_value='false' WHERE option_name='setup_ready'");
                $db->update("UPDATE evp_options SET option_value='' WHERE option_name IN ('seed_token','access_tier','support_window','access_expiry')");
                $db->update("UPDATE evp_options SET option_value='0' WHERE option_name='access_id'");
            }
            $_SESSION['access_check'] = true;
            $_SESSION['access_error'] = true;
            $_SESSION['access_message'] = $message;
            $_SESSION['access_active'] = 'false';
            $GLOBALS['access_ready'] = 'false';
            $GLOBALS['setup_ready'] = 'false';
            $GLOBALS['seed_token'] = '';
            $GLOBALS['access_tier'] = '';
            $GLOBALS['support_window'] = '';
            $GLOBALS['access_expiry'] = '';
            self::touchProbe(true);
            self::syncCron(false);
            if (!class_exists('RuntimeSignal')) {
                $runtimePath = __DIR__ . '/class.runtime.signal.php';
                if (is_file($runtimePath)) {
                    require_once $runtimePath;
                }
            }
            if (class_exists('RuntimeSignal')) {
                RuntimeSignal::instance()->forget();
            }
            return [true, $message];
        }
        if ($relay !== '') {
            $message = $relay;
        }
        return [false, $message];
    }

    public static function stash($payload)
    {
        $vector = self::secret();
        $blob = [
            'stamp' => time(),
            'data' => base64_encode(json_encode($payload)),
            'sign' => hash_hmac('sha256', json_encode($payload), $vector)
        ];
        $encoded = base64_encode(json_encode($blob));
        $target = self::cacheFile();
        file_put_contents($target, $encoded, LOCK_EX);
        self::touchProbe();
    }

    public static function recall()
    {
        $target = self::cacheFile();
        if (!is_file($target)) {
            return null;
        }
        $encoded = file_get_contents($target);
        if ($encoded === false || $encoded === '') {
            return null;
        }
        $decoded = base64_decode($encoded, true);
        if ($decoded === false) {
            return null;
        }
        $blob = json_decode($decoded, true);
        if (!is_array($blob) || empty($blob['data']) || empty($blob['sign'])) {
            return null;
        }
        $json = base64_decode($blob['data'], true);
        if ($json === false) {
            return null;
        }
        $payload = json_decode($json);
        if ($payload === null && $json !== 'null') {
            return null;
        }
        $vector = self::secret();
        $signature = hash_hmac('sha256', $json, $vector);
        if (!hash_equals($signature, $blob['sign'])) {
            return null;
        }
        return $payload;
    }

    public static function purge()
    {
        $target = self::cacheFile();
        if (is_file($target)) {
            @unlink($target);
        }
        self::touchProbe(true);
    }

    public static function probeDue($ttl = 1800)
    {
        $record = self::loadProbe();
        if ($record === null) {
            return true;
        }
        if (!isset($record['t']) || !is_int($record['t'])) {
            return true;
        }
        if ($record['t'] <= 0) {
            return true;
        }
        return (time() - $record['t']) >= max(300, (int) $ttl);
    }

    public static function touchProbe($invalidate = false)
    {
        $payload = [
            't' => $invalidate ? 0 : time(),
            'h' => substr(hash('sha256', self::secret() . '|' . ($_SERVER['HTTP_HOST'] ?? 'cli')), 0, 24)
        ];
        $encoded = base64_encode(json_encode($payload));
        $target = self::probeFile();
        file_put_contents($target, $encoded, LOCK_EX);
    }

    private static function loadProbe()
    {
        $target = self::probeFile();
        if (!is_file($target)) {
            return null;
        }
        $raw = file_get_contents($target);
        if ($raw === false || $raw === '') {
            return null;
        }
        $decoded = base64_decode($raw, true);
        if ($decoded === false) {
            return null;
        }
        $record = json_decode($decoded, true);
        if (!is_array($record)) {
            return null;
        }
        if (empty($record['h'])) {
            return null;
        }
        $expected = substr(hash('sha256', self::secret() . '|' . ($_SERVER['HTTP_HOST'] ?? 'cli')), 0, 24);
        if (!hash_equals($expected, $record['h'])) {
            return null;
        }
        return $record;
    }

    private static function probeFile()
    {
        if (self::$probePath !== null) {
            return self::$probePath;
        }
        self::$probePath = __DIR__ . '/.licprobe';
        return self::$probePath;
    }

    private static function cronScriptPath()
    {
        if (self::$cronScript !== null) {
            return self::$cronScript;
        }
        $name = '.evp_license_probe.php';
        self::$cronScript = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name;
        return self::$cronScript;
    }

    private static function syncCron($enable)
    {
        if (stripos(PHP_OS, 'WIN') === 0) {
            return;
        }
        $script = self::cronScriptPath();
        if ($enable) {
            self::writeCronScript($script);
            self::installCronEntry($script);
        } else {
            self::removeCronEntry($script);
            if (is_file($script)) {
                @unlink($script);
            }
        }
    }

    private static function writeCronScript($target)
    {
        $root = self::base();
        $php = PHP_BINARY ?: '/usr/bin/php';
        $contents = <<<'EOC'
#!/usr/bin/env php
<?php
@ini_set('display_errors', 0);
@ini_set('log_errors', 0);
$base = %s;
chdir($base);
require_once $base . '/config.php';
require_once $base . '/functions/apihandler.php';
require_once $base . '/functions/.sysvault.php';
require_once $base . '/functions/class.runtime.signal.php';
RuntimeSignal::instance()->forget();
RuntimeSignal::instance()->assert(true);
EOC;
        $encodedBase = var_export($root, true);
        $scriptBody = sprintf($contents, $encodedBase);
        file_put_contents($target, $scriptBody, LOCK_EX);
        @chmod($target, 0700);
    }

    private static function installCronEntry($script)
    {
        $php = PHP_BINARY ?: '/usr/bin/php';
        $line = sprintf('*/30 * * * * %s %s >/dev/null 2>&1', escapeshellarg($php), escapeshellarg($script));
        $signature = self::cronSignature();
        $wrapped = $line . " # " . $signature;
        $current = self::readCron();
        if (strpos($current, $signature) !== false) {
            return;
        }
        $current = trim($current);
        if ($current !== '') {
            $current .= PHP_EOL;
        }
        $current .= $wrapped . PHP_EOL;
        self::writeCron($current);
    }

    private static function removeCronEntry($script)
    {
        $signature = self::cronSignature();
        $current = self::readCron();
        if (strpos($current, $signature) === false) {
            return;
        }
        $filtered = [];
        foreach (explode(PHP_EOL, $current) as $line) {
            if (strpos($line, $signature) !== false) {
                continue;
            }
            if (trim($line) === '') {
                continue;
            }
            $filtered[] = $line;
        }
        $payload = empty($filtered) ? '' : implode(PHP_EOL, $filtered) . PHP_EOL;
        self::writeCron($payload);
    }

    private static function cronSignature()
    {
        return substr(hash('sha256', self::secret() . '|cron|probe'), 0, 16);
    }

    private static function readCron()
    {
        $output = [];
        $result = @exec('crontab -l 2>/dev/null', $output, $code);
        if ($code !== 0) {
            return '';
        }
        return implode(PHP_EOL, $output);
    }

    private static function writeCron($payload)
    {
        $descriptor = [
            0 => ['pipe', 'r'],
            1 => ['pipe', 'w'],
            2 => ['pipe', 'w']
        ];
        $process = @proc_open('crontab -', $descriptor, $pipes);
        if (!is_resource($process)) {
            return;
        }
        fwrite($pipes[0], $payload);
        fclose($pipes[0]);
        fclose($pipes[1]);
        fclose($pipes[2]);
        proc_close($process);
    }

    private static function validateCore()
    {
        foreach (self::$coreMap as $relative => $needles) {
            $path = self::base() . $relative;
            if (!is_file($path)) {
                return false;
            }
            $contents = file_get_contents($path);
            if ($contents === false) {
                return false;
            }
            foreach ($needles as $needle) {
                if (strpos($contents, $needle) === false) {
                    return false;
                }
            }
        }
        return true;
    }

    private static function base()
    {
        return dirname(__DIR__);
    }

    private static function cacheFile()
    {
        if (self::$cachePath !== null) {
            return self::$cachePath;
        }
        $dir = sys_get_temp_dir();
        $name = '.' . substr(hash('sha256', __FILE__ . self::secret()), 0, 24);
        self::$cachePath = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name;
        return self::$cachePath;
    }

    private static function secret()
    {
        if (self::$cipherSeed !== null) {
            return self::$cipherSeed;
        }
        $broker = self::broker();
        $token = is_object($broker) && !empty($broker->key) ? $broker->key : 'fallback-seed';
        self::$cipherSeed = hash('sha256', $token . __FILE__);
        return self::$cipherSeed;
    }

    private static function broker()
    {
        if (!class_exists('EVPAPIREGCC')) {
            $path = __DIR__ . '/apihandler.php';
            if (is_file($path)) {
                require_once $path;
            }
        }
        return class_exists('EVPAPIREGCC') ? EVPAPIREGCC::getInstance() : null;
    }
}
