<?php
namespace Core\System\License;

class LicenseClient {
    protected string $verifyEndpoint   = 'https://license.ar-script.com/api/verify.php';
    protected string $pingEndpoint     = 'https://license.ar-script.com/api/ping.php';

    // ✅ NEW: Updates endpoint
    protected string $updatesEndpoint  = 'https://license.ar-script.com/api/updates_check.php';

    // ✅ NEW: Support endpoints
    protected string $supportCreateEndpoint   = 'https://license.ar-script.com/api/support/create_ticket.php';
    protected string $supportListEndpoint     = 'https://license.ar-script.com/api/support/list_tickets.php';
    protected string $supportMessagesEndpoint = 'https://license.ar-script.com/api/support/get_messages.php';
    protected string $supportReplyEndpoint    = 'https://license.ar-script.com/api/support/reply.php';
    protected string $supportUnreadEndpoint   = 'https://license.ar-script.com/api/support/unread_count.php';

    // ✅ NEW: Close ticket endpoint
    protected string $supportCloseEndpoint    = 'https://license.ar-script.com/api/support/close_ticket.php';

    /**
     * Public key embedded in client (no secrets in client).
     * Must match server private.pem.
     */
    protected function currentProduct(): string
    {
        if (defined('MTE_PRODUCT')) {
            return (string) constant('MTE_PRODUCT');
        }
        if (class_exists('\\Core\\System\\Version') && defined('\\Core\\System\\Version::PRODUCT')) {
            return (string) \Core\System\Version::PRODUCT;
        }
        return 'MTEngine';
    }

    protected string $publicKeyPem = <<<PEM
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs0Roys7vhPNqk60Uk+Ob
I/Epu0si4jm+xDTU+uzS0lnvRfzX3C9GyNlB3qkNFxi4bUqjjAq/M3bzYplO9wFS
zDQqu84LpFG1I2Pjeo7DB7dudEhGp9hDSFwkEFQuhE1F5DTDetsa7+WuhJrFZs56
uxIo0qyUNokj/3V+FrJs6B/r2lWjHvAvPzPqJlpLdajuaCGtXs1Q2jPwWzAg7zgm
/BeJkDrQHPIwCAUD7fwG3OwqBsLwAvRcO3qnTcED/dfAThQ6Aob2w+4ITmlt6VLx
gVcG+VjXUf1aI8pdrG5ljjWMmX03E4VOI4FlrUWXU7riNX/iMDoQevmS2MpTBgps
V3TgOsHsCiCzcoYEVZ2GDyR2Ku+qEcfh3Iq8uyEbJwBSdhG8u0942PHLA8mWhZ9c
+7q74L2OW1z7F36OhSFe5IGt0jB9pgFvZ4clOqF3F5I/G4K3ePXGSzXGtZwaAE/T
a5lyXl7yxM1Kk+WUcN1ohhtQSEUpvF2pAyO3Qlx7/i0OWfgHsAn9X06sgZnWY+T5
cvdxKASo9TDnkvfyUFGkRbMydFrLMm7OTfWT7asYLu57QvyJFbFaQEC68r2eJfxY
GlQkmM1h+aR/pxwCSfWz2azfdklSg8LU93ZozPw+2lcBCHVZDscbrRMPXXdzm+Pe
g9G16nv035J9c7vbe2/ISC8CAwEAAQ==
-----END PUBLIC KEY-----
PEM;

    /**
     * ✅ ثابت fingerprint للدعم فقط
     * (حتى لا يختفي ticket أو الرسائل بسبب تغيّر fingerprint)
     */
    protected function supportFingerprint(): string
    {
        if (session_status() === PHP_SESSION_NONE) {
            @session_start();
        }

        if (!empty($_SESSION['support_fp'])) {
            return (string)$_SESSION['support_fp'];
        }

        $_SESSION['support_fp'] = Fingerprint::generate();
        return (string)$_SESSION['support_fp'];
    }

    public function verify(string $licenseKey): array {
        $payload = [
            'license_key' => $licenseKey,
            'domain'      => $_SERVER['HTTP_HOST'] ?? '',
            'fingerprint' => Fingerprint::generate(),
            'product'     => $this->currentProduct(),
        ];

        $res = $this->postJson($this->verifyEndpoint, $payload);

        // Offline / network failure -> keep legacy behavior (grace handled by middleware)
        if ($res === []) {
            return [];
        }

        // Signature missing/invalid -> fail-closed (block)
        if (!$this->isSignedResponseValid($res)) {
            return [
                'status' => 'invalid',
                'action' => 'block',
                'type' => 'single_domain',
                'message' => 'invalid_signature',
                'expires' => null,
                'domain_bound' => null,
                'max_domains' => 0,
                'domains_used' => 0,
            ];
        }

        return $res;
    }

    public function ping(string $licenseKey, string $domain, string $fingerprint): array {
        $payload = [
            'license_key' => $licenseKey,
            'domain'      => $domain,
            'fingerprint' => $fingerprint,
            'product'     => $this->currentProduct(),
        ];

        $res = $this->postJson($this->pingEndpoint, $payload);

        // Offline / network failure -> keep legacy behavior (grace handled by middleware)
        if ($res === []) {
            return [];
        }

        // Signature missing/invalid -> fail-closed (block)
        if (!$this->isSignedResponseValid($res)) {
            return [
                'status' => 'invalid',
                'action' => 'block',
                'type' => 'single_domain',
                'message' => 'invalid_signature',
                'expires' => null,
                'domain_bound' => null,
                'max_domains' => 0,
                'domains_used' => 0,
            ];
        }

        return $res;
    }

    /**
     * ✅ NEW: Check updates from license server
     * Returns signed payload (or [] if offline)
     *
     * Expected response (examples):
     * - status: ok | no_update | error
     * - action: update | none | block
     * - latest_version, title, notes, download_url, update_available
     */
    public function checkUpdates(string $product, string $currentVersion, string $licenseKey = ''): array
    {
        $payload = [
            'product'         => $product,
            'current_version' => $currentVersion,
        ];

        // optional
        if ($licenseKey !== '') {
            $payload['license_key'] = $licenseKey;
        }

        $res = $this->postJson($this->updatesEndpoint, $payload);

        // Offline / network failure -> treat as no response
        if ($res === []) {
            return [];
        }

        // Signature missing/invalid -> fail-closed (block)
        if (!$this->isSignedResponseValid($res)) {
            return [
                'status' => 'error',
                'action' => 'block',
                'message' => 'invalid_signature',
            ];
        }

        return $res;
    }



    public function checkUpdateItem(string $product, string $currentVersion, string $licenseKey = '', ?string $pluginSlug = null): array {
        $payload = [
            'product'         => $product,
            'current_version' => $currentVersion,
        ];

        if ($licenseKey !== '') {
            $payload['license_key'] = $licenseKey;
        }

        if ($pluginSlug !== null && $pluginSlug !== '') {
            $payload['plugin_slug'] = $pluginSlug;
        }

        $res = $this->postJson($this->updatesEndpoint, $payload);

        if ($res === []) {
            return [];
        }

        if (!$this->isSignedResponseValid($res)) {
            return [
                'status' => 'error',
                'action' => 'block',
                'message' => 'invalid_signature',
            ];
        }

        return $res;
    }

    public function downloadToFile(string $url, string $targetPath): bool
    {
        $dir = dirname($targetPath);
        if (!is_dir($dir)) {
            @mkdir($dir, 0755, true);
        }

        $fp = @fopen($targetPath, 'wb');
        if ($fp === false) {
            return false;
        }

        if (!function_exists('curl_init')) {
            fclose($fp);
            return false;
        }

        $ch = curl_init($url);
        if ($ch === false) {
            fclose($fp);
            return false;
        }

        curl_setopt_array($ch, [
            CURLOPT_FILE => $fp,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 300,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_FAILONERROR => true,
        ]);

        $ok = curl_exec($ch);
        curl_close($ch);
        fclose($fp);

        return (bool)$ok && is_file($targetPath);
    }

    /**
     * ✅ NEW: Create support ticket (client -> server)
     */
    public function supportCreateTicket(string $licenseKey, string $subject, string $message, string $priority = 'normal', string $product = 'MTEngine'): array
    {
        $payload = [
            'license_key' => $licenseKey,
            'domain'      => $_SERVER['HTTP_HOST'] ?? '',
            'fingerprint' => $this->supportFingerprint(),
            'product'     => $product,
            'subject'     => $subject,
            'message'     => $message,
            'priority'    => $priority,
        ];

        $res = $this->postJson($this->supportCreateEndpoint, $payload);

        if ($res === []) {
            return [];
        }

        if (!$this->isSignedResponseValid($res)) {
            return [
                'ok' => false,
                'error' => 'invalid_signature',
            ];
        }

        return $res;
    }

    /**
     * ✅ NEW: List client tickets
     */
    public function supportListTickets(string $licenseKey, string $product = 'MTEngine'): array
    {
        $payload = [
            'license_key' => $licenseKey,
            'domain'      => $_SERVER['HTTP_HOST'] ?? '',
            'fingerprint' => $this->supportFingerprint(),
            'product'     => $product,
        ];

        $res = $this->postJson($this->supportListEndpoint, $payload);

        if ($res === []) {
            return [];
        }

        if (!$this->isSignedResponseValid($res)) {
            return [
                'ok' => false,
                'error' => 'invalid_signature',
            ];
        }

        return $res;
    }

    /**
     * ✅ NEW: Get messages for a ticket
     */
    public function supportGetMessages(string $licenseKey, int $ticketId, string $product = 'MTEngine'): array
    {
        $payload = [
            'license_key' => $licenseKey,
            'domain'      => $_SERVER['HTTP_HOST'] ?? '',
            'fingerprint' => $this->supportFingerprint(),
            'product'     => $product,
            'ticket_id'   => $ticketId,
        ];

        $res = $this->postJson($this->supportMessagesEndpoint, $payload);

        if ($res === []) {
            return [];
        }

        if (!$this->isSignedResponseValid($res)) {
            return [
                'ok' => false,
                'error' => 'invalid_signature',
            ];
        }

        return $res;
    }

    /**
     * ✅ NEW: Reply to a ticket (client -> server)
     */
    public function supportReply(string $licenseKey, int $ticketId, string $message, string $product = 'MTEngine'): array
    {
        $payload = [
            'license_key' => $licenseKey,
            'domain'      => $_SERVER['HTTP_HOST'] ?? '',
            'fingerprint' => $this->supportFingerprint(),
            'product'     => $product,
            'ticket_id'   => $ticketId,
            'message'     => $message,
        ];

        $res = $this->postJson($this->supportReplyEndpoint, $payload);

        if ($res === []) {
            return [];
        }

        if (!$this->isSignedResponseValid($res)) {
            return [
                'ok' => false,
                'error' => 'invalid_signature',
            ];
        }

        return $res;
    }

    /**
     * ✅ NEW: Unread count for client
     */
    public function supportUnreadCount(string $licenseKey, string $product = 'MTEngine'): array
    {
        $payload = [
            'license_key' => $licenseKey,
            'domain'      => $_SERVER['HTTP_HOST'] ?? '',
            'fingerprint' => $this->supportFingerprint(),
            'product'     => $product,
        ];

        $res = $this->postJson($this->supportUnreadEndpoint, $payload);

        if ($res === []) {
            return [];
        }

        if (!$this->isSignedResponseValid($res)) {
            return [
                'ok' => false,
                'error' => 'invalid_signature',
            ];
        }

        return $res;
    }

    /**
     * ✅ NEW: Close ticket (client -> server)
     */
    public function supportCloseTicket(string $licenseKey, int $ticketId, string $product = 'MTEngine'): array
    {
        $payload = [
            'license_key' => $licenseKey,
            'domain'      => $_SERVER['HTTP_HOST'] ?? '',
            'fingerprint' => $this->supportFingerprint(),
            'product'     => $product,
            'ticket_id'   => $ticketId,
        ];

        $res = $this->postJson($this->supportCloseEndpoint, $payload);

        if ($res === []) {
            return [];
        }

        if (!$this->isSignedResponseValid($res)) {
            return [
                'ok' => false,
                'error' => 'invalid_signature',
            ];
        }

        return $res;
    }

    protected function postJson(string $url, array $payload): array {
        $ch = curl_init($url);
        if (!$ch) {
            return [];
        }

        $json = json_encode($payload, JSON_UNESCAPED_UNICODE);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Accept: application/json',
        ]);

        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

        $resp = curl_exec($ch);
        $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);

        curl_close($ch);

        // Network / server errors treated as offline
        if ($resp === false || $code <= 0 || $code >= 500) {
            return [];
        }

        $data = json_decode((string)$resp, true);
        if (!is_array($data)) {
            return [];
        }

        return $data;
    }

    /**
     * Verify signed response using RSA SHA256 (no secrets in client).
     * Server signs canonical JSON encoding of payload WITHOUT 'sig'.
     */
    protected function isSignedResponseValid(array $response): bool
    {
        if (!isset($response['sig']) || !is_string($response['sig']) || trim($response['sig']) === '') {
            return false;
        }

        $sigBase64 = $response['sig'];
        unset($response['sig']);

        // Canonicalize JSON same as server: recursive sort keys for associative arrays
        $payload = $this->canonicalizeForSigning($response);

        $json = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        if ($json === false) {
            return false;
        }

        $sigRaw = base64_decode($sigBase64, true);
        if ($sigRaw === false) {
            return false;
        }

        $pubKey = openssl_pkey_get_public($this->publicKeyPem);
        if ($pubKey === false) {
            return false;
        }

        $ok = openssl_verify($json, $sigRaw, $pubKey, OPENSSL_ALGO_SHA256);

        return $ok === 1;
    }

    /**
     * Canonicalize array for stable signing:
     * - Sort associative keys recursively
     */
    protected function canonicalizeForSigning(mixed $data): mixed
    {
        if (is_array($data)) {
            $isAssoc = array_keys($data) !== range(0, count($data) - 1);

            if ($isAssoc) {
                ksort($data);
            }

            foreach ($data as $k => $v) {
                $data[$k] = $this->canonicalizeForSigning($v);
            }
        }

        return $data;
    }
}
