<?php
// ============================================================
// CLIENTE DE LICENÇA — MonitorPing
// Valida a licença contra o servidor remoto (cPanel)
// ============================================================

define('LICENSE_SERVER_URL',  getenv('LICENSE_SERVER_URL') ?: 'https://key.monitorping.com.br/servidor-licenca/api.php');
define('LICENSE_API_SECRET',  getenv('LICENSE_API_SECRET') ?: '');
define('LICENSE_KEY_FILE',    '/opt/monitorping/.license_key');
define('LICENSE_CACHE_FILE',  '/opt/monitorping/.license_cache');
define('LICENSE_MACHINE_FILE','/opt/monitorping/.machine_id');
define('LICENSE_CACHE_TTL',   1800);
define('LICENSE_OFFLINE_MAX', 172800);

// Verifica integridade dos arquivos críticos
// Retorna false se algum arquivo foi modificado após o build da imagem
function _mp_env_ready(): bool {
    $manifest = '/var/.mp_manifest';
    if (!file_exists($manifest)) return true;
    $lines = @file($manifest, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    if (!is_array($lines)) return true; // sem permissão de leitura → entrypoint já valida
    foreach ($lines as $line) {
        $parts = preg_split('/\s+/', trim($line), 2);
        if (count($parts) < 2) continue;
        [$expected, $path] = $parts;
        if (!file_exists($path)) return false;
        if (@hash_file('sha256', $path) !== $expected) return false;
    }
    return true;
}

// Lê a chave: arquivo local tem prioridade sobre env var
function license_get_key(): string {
    if (file_exists(LICENSE_KEY_FILE)) {
        $raw = @file_get_contents(LICENSE_KEY_FILE);
        if ($raw !== false) {
            $key = trim($raw);
            if ($key) return $key;
        }
    }
    return getenv('LICENSE_KEY') ?: '';
}

// Salva a chave no arquivo persistente do volume
function license_save_key(string $key): bool {
    $key = strtoupper(trim($key));
    if (!preg_match('/^[A-Z2-9]{5}-[A-Z2-9]{5}-[A-Z2-9]{5}-[A-Z2-9]{5}$/', $key)) {
        return false;
    }
    $ok = @file_put_contents(LICENSE_KEY_FILE, $key, LOCK_EX) !== false;
    if ($ok) @chmod(LICENSE_KEY_FILE, 0644);
    return $ok;
}

// Constante para compatibilidade (usa a chave resolvida)
if (!defined('LICENSE_KEY')) {
    define('LICENSE_KEY', license_get_key());
}

// Gera ou lê o hardware_id permanente desta instalação
function license_hardware_id(): string {
    if (file_exists(LICENSE_MACHINE_FILE)) {
        $raw = @file_get_contents(LICENSE_MACHINE_FILE);
        if ($raw !== false) return trim($raw);
    }
    $id = hash('sha256', gethostname() . php_uname() . microtime(true) . random_bytes(16));
    @file_put_contents(LICENSE_MACHINE_FILE, $id);
    @chmod(LICENSE_MACHINE_FILE, 0644);
    return $id;
}

// Chama a API do servidor de licenças
function license_call_api(string $action): ?array {
    $payload = json_encode([
        'action'      => $action,
        'license_key' => license_get_key(),
        'hardware_id' => license_hardware_id(),
    ]);

    $sig = hash_hmac('sha256', $payload, LICENSE_API_SECRET);

    $ctx = stream_context_create(['http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/json\r\nX-Signature: $sig\r\n",
        'content' => $payload,
        'timeout' => 8,
        'ignore_errors' => true,
    ]]);

    $resp = @file_get_contents(LICENSE_SERVER_URL, false, $ctx);
    if (!$resp) return null;
    return json_decode($resp, true) ?: null;
}

// Salva cache local assinado com HMAC (impede falsificação do arquivo)
function license_save_cache(array $data): void {
    $data['cached_at'] = time();
    unset($data['_sig']);
    $payload        = json_encode($data);
    $sig            = hash_hmac('sha256', $payload, LICENSE_API_SECRET . LICENSE_KEY);
    $data['_sig']   = $sig;
    @file_put_contents(LICENSE_CACHE_FILE, json_encode($data), LOCK_EX);
    @chmod(LICENSE_CACHE_FILE, 0644);
}

// Lê cache local e valida assinatura HMAC
function license_read_cache(): ?array {
    if (!file_exists(LICENSE_CACHE_FILE)) return null;
    $raw  = @file_get_contents(LICENSE_CACHE_FILE);
    $data = json_decode($raw, true);
    if (!is_array($data) || empty($data['_sig'])) return null;

    $sig = $data['_sig'];
    unset($data['_sig']);
    $expected = hash_hmac('sha256', json_encode($data), LICENSE_API_SECRET . LICENSE_KEY);

    // Cache adulterado → ignora e força nova validação online
    if (!hash_equals($expected, $sig)) return null;

    return $data;
}

// ── FUNÇÃO PRINCIPAL ─────────────────────────────────────────
// Retorna array com:
//   status  => 'ok' | 'warning' | 'blocked' | 'offline_warning'
//   message => string (exibir para o usuário se não for 'ok')
//   expires_at, customer_name
function license_check(): array {
    if (!_mp_env_ready()) {
        return ['status' => 'blocked', 'message' => 'Falha de integridade do sistema. Reinstale o MonitorPing.'];
    }

    $key = license_get_key();
    if (empty($key) || !preg_match('/^[A-Z2-9]{5}-[A-Z2-9]{5}-[A-Z2-9]{5}-[A-Z2-9]{5}$/', $key)) {
        return ['status' => 'no_key', 'message' => 'Nenhuma chave de licença configurada.'];
    }

    $cache = license_read_cache();
    $now   = time();

    // Cache ainda válido — retorna sem chamar o servidor
    if ($cache && isset($cache['cached_at']) && ($now - $cache['cached_at']) < LICENSE_CACHE_TTL) {
        return $cache;
    }

    // Tenta chamar o servidor
    $resp = license_call_api('validate');

    if ($resp === null) {
        // Servidor inacessível — usa cache antigo com tolerância offline
        if ($cache && isset($cache['cached_at'])) {
            $age = $now - $cache['cached_at'];
            if ($age < LICENSE_OFFLINE_MAX) {
                $cache['status']  = 'ok';
                $cache['message'] = '';
                return $cache;
            }
            // Passou de 48h offline → aviso, mas não bloqueia ainda
            $cache['status']  = 'offline_warning';
            $cache['message'] = 'Servidor de licenças inacessível há mais de 48h. Verifique sua conexão.';
            return $cache;
        }
        return ['status' => 'blocked', 'message' => 'Não foi possível validar a licença e não há cache local. Verifique sua conexão de internet.'];
    }

    // Monta resultado
    $result = [
        'customer_name' => $resp['customer_name'] ?? '',
        'expires_at'    => $resp['expires_at'] ?? '',
        'grace_days'    => $resp['grace_days'] ?? 7,
    ];

    if (!($resp['valid'] ?? false)) {
        $error = $resp['error'] ?? 'invalid';
        $result['status']  = 'blocked';
        if ($error === 'revoked')                $result['message'] = 'Sua licença foi revogada. Entre em contato com o suporte.';
        elseif ($error === 'hardware_mismatch') $result['message'] = 'Esta licença está ativada em outra máquina. Entre em contato com o suporte.';
        elseif ($error === 'invalid_key')       $result['message'] = 'Chave de licença inválida. Verifique o .env.';
        else                                    $result['message'] = 'Licença bloqueada. Entre em contato com o suporte.';
        license_save_cache($result);
        return $result;
    }

    if ($resp['in_grace'] ?? false) {
        $result['status']  = 'warning';
        $result['message'] = 'Sua licença venceu em ' . date('d/m/Y', strtotime($resp['expires_at'])) . '. Você tem ' . ($resp['grace_days'] ?? 7) . ' dias de carência. Renove em monitorping.com.br.';
    } elseif ($resp['blocked'] ?? false) {
        $result['status']  = 'blocked';
        $result['message'] = 'Licença expirada e período de carência encerrado. Renove em monitorping.com.br.';
    } else {
        $result['status']  = 'ok';
        $result['message'] = '';
    }

    license_save_cache($result);
    return $result;
}

// Primeira ativação (chamada pelo instalador)
function license_activate(): array {
    $resp = license_call_api('activate');
    if (!$resp) return ['success' => false, 'message' => 'Servidor de licenças inacessível.'];
    if (!($resp['valid'] ?? false)) {
        return ['success' => false, 'message' => $resp['error'] ?? 'Erro na ativação.'];
    }
    $result = [
        'status'        => 'ok',
        'message'       => '',
        'customer_name' => $resp['customer_name'] ?? '',
        'expires_at'    => $resp['expires_at'] ?? '',
        'grace_days'    => $resp['grace_days'] ?? 7,
    ];
    license_save_cache($result);
    return ['success' => true, 'message' => 'Licença ativada com sucesso.'];
}
