<?php
/**
 * license-php/api/activate.php
 * POST /api/license/activate
 * Client License Activation Endpoint.
 */

require_once __DIR__ . '/../lib/Response.php';
require_once __DIR__ . '/../lib/Database.php';
require_once __DIR__ . '/../lib/LicenseCrypto.php';
require_once __DIR__ . '/../lib/Entitlements.php';
require_once __DIR__ . '/../lib/AuditLogger.php';
require_once __DIR__ . '/../lib/LicenseRepository.php';

Response::handleCors();

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
}

$config = require __DIR__ . '/../config/config.php';
$pdo = Database::getConnection($config);
$repo = new LicenseRepository($pdo);
$audit = new AuditLogger($pdo);

$body = Response::getJsonBody();
$rawKey = strtoupper(trim((string)($body['license_key'] ?? '')));
$domain = LicenseCrypto::cleanDomain($body['domain'] ?? '');
$product = trim((string)($body['product'] ?? $config['product_name']));
$appVersion = trim((string)($body['app_version'] ?? '1.0.0'));

if (!$rawKey) {
    Response::json(400, [
        'success' => false,
        'status' => 'invalid',
        'message' => 'License key is required'
    ]);
}

if (!$domain) {
    Response::json(400, [
        'success' => false,
        'status' => 'invalid',
        'message' => 'Domain name is required for activation'
    ]);
}

$lic = $repo->findByKeyOrHash($rawKey);

if (!$lic) {
    $audit->log(null, 'ACTIVATION_FAILED', $domain, ['reason' => 'License key not found', 'key' => $rawKey]);
    Response::json(404, [
        'success' => false,
        'status' => 'invalid',
        'message' => 'Kunci lisensi tidak valid atau tidak ditemukan'
    ]);
}

// Status check: Revoked
if ($lic['status'] === 'revoked') {
    $audit->log($lic['id'], 'ACTIVATION_FAILED_REVOKED', $domain);
    Response::json(403, [
        'success' => false,
        'status' => 'revoked',
        'message' => 'License has been revoked by the administrator'
    ]);
}

// Status check: Suspended
if ($lic['status'] === 'suspended') {
    $audit->log($lic['id'], 'ACTIVATION_FAILED_SUSPENDED', $domain);
    Response::json(403, [
        'success' => false,
        'status' => 'suspended',
        'message' => 'License is currently suspended'
    ]);
}

// Status check: Expired
if (!empty($lic['expires_at'])) {
    $expTime = strtotime($lic['expires_at']);
    if ($expTime !== false && time() > $expTime) {
        $repo->updateStatus($lic['id'], 'expired');
        $audit->log($lic['id'], 'ACTIVATION_FAILED_EXPIRED', $domain);
        Response::json(403, [
            'success' => false,
            'status' => 'expired',
            'message' => 'License has expired'
        ]);
    }
}

// Product check
if (!empty($lic['product']) && $product && strtolower($lic['product']) !== strtolower($product)) {
    $audit->log($lic['id'], 'ACTIVATION_FAILED_PRODUCT_MISMATCH', $domain, ['expected' => $lic['product'], 'got' => $product]);
    Response::json(400, [
        'success' => false,
        'status' => 'invalid',
        'message' => "License product mismatch (Expected: {$lic['product']})"
    ]);
}

// Domain Binding Logic
if (empty($lic['domain'])) {
    // First-use activation locks the domain!
    $repo->activateDomain($lic['id'], $domain, ((int)($lic['activation_count'] ?? 0)) + 1);
    $lic['domain'] = $domain;
    $lic['status'] = 'active';
} else {
    $lockedDomain = LicenseCrypto::cleanDomain($lic['domain']);
    if ($lockedDomain !== $domain) {
        $audit->log($lic['id'], 'DOMAIN_MISMATCH', $domain, ['lockedDomain' => $lockedDomain]);
        Response::json(403, [
            'success' => false,
            'status' => 'domain_mismatch',
            'message' => 'License is already bound to another domain'
        ]);
    }

    $maxAct = (int)($lic['max_activation'] ?? 1);
    if ((int)$lic['activation_count'] >= $maxAct && empty($lic['activated_at'])) {
        $audit->log($lic['id'], 'ACTIVATION_LIMIT_REACHED', $domain);
        Response::json(403, [
            'success' => false,
            'status' => 'activation_limit',
            'message' => 'Maximum activation limit reached'
        ]);
    }

    $repo->updateLastVerified($lic['id']);
}

// Entitlements & Token Signing
$planName = $lic['plan'] ?: ($lic['license_type'] === 'Enterprise' ? 'ENTERPRISE' : ($lic['license_type'] === 'Trial' ? 'BASIC' : 'PRO'));
$entitlements = Entitlements::getPlanEntitlements($planName, $lic['license_type']);

$tokenPayload = [
    'license_id'   => $lic['id'],
    'product'      => $lic['product'],
    'domain'       => $lic['domain'],
    'plan'         => $planName,
    'customer'     => $lic['customer_name'],
    'status'       => 'active',
    'license_type' => $lic['license_type'],
    'entitlements' => $entitlements,
    'issued_at'    => gmdate('Y-m-d\TH:i:s.v\Z'),
    'expires_at'   => $lic['expires_at'] ?? null,
    'app_version'  => $appVersion
];

$privKeyPath = $config['keys']['private'] ?? '';
if (!file_exists($privKeyPath)) {
    $candidates = [
        dirname(__DIR__, 2) . '/keys/license_private.key',
        dirname(__DIR__, 1) . '/keys/license_private.key',
        dirname(__DIR__, 2) . '/private/license-private.pem',
        __DIR__ . '/../../keys/license_private.key',
        __DIR__ . '/../keys/license_private.key'
    ];
    foreach ($candidates as $cand) {
        if (file_exists($cand)) {
            $privKeyPath = $cand;
            break;
        }
    }
}
if (!file_exists($privKeyPath)) {
    Response::json(500, ['success' => false, 'message' => 'Private key not configured on server.']);
}
$privateKeyPem = file_get_contents($privKeyPath);
$signedToken = LicenseCrypto::signToken($tokenPayload, $privateKeyPem);

$audit->log($lic['id'], 'LICENSE_ACTIVATED', $domain, ['token_issued' => true, 'plan' => $planName]);

Response::json(200, [
    'success' => true,
    'status'  => 'active',
    'message' => 'License activated successfully',
    'license' => [
        'product'       => $lic['product'],
        'domain'        => $lic['domain'],
        'plan'          => $planName,
        'customer_name' => $lic['customer_name'],
        'license_type'  => $lic['license_type'],
        'entitlements'  => $entitlements,
        'expires_at'    => $lic['expires_at']
    ],
    'token'   => $signedToken
]);
