<?php
namespace EasyChat\Controller;

use EasyChat\Library\CentralGatewayClient;
use EasyChat\Model\Setting;

class Webpush extends Base {

    protected $layouts = '';

    public function index() {
        $this->jsonError('endpoint_not_found', 404);
    }

    public function manifest() {
        header('Content-Type: application/manifest+json; charset=utf-8');
        echo json_encode([
            'name' => 'EasyChat Operator',
            'short_name' => 'EasyChat',
            'id' => './',
            'description' => 'EasyChat operator panel for chats and notifications',
            'start_url' => 'index.php?route=index',
            'scope' => './',
            'display' => 'standalone',
            'background_color' => '#f8fafc',
            'theme_color' => '#6366f1',
            'icons' => [
                [
                    'src' => 'images/icon-192.png',
                    'sizes' => '192x192',
                    'type' => 'image/png',
                    'purpose' => 'any',
                ],
                [
                    'src' => 'images/icon-512.png',
                    'sizes' => '512x512',
                    'type' => 'image/png',
                    'purpose' => 'any maskable',
                ],
                [
                    'src' => 'images/icon.png',
                    'sizes' => '32x32',
                    'type' => 'image/png',
                    'purpose' => 'any',
                ],
            ],
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }

    public function serviceWorker() {
        header('Content-Type: application/javascript; charset=utf-8');
        header('Service-Worker-Allowed: ./');
        header('Cache-Control: no-cache, no-store, must-revalidate');
        echo <<<'JS'
self.addEventListener('push', function(event) {
    var payload = {};
    if (event.data) {
        try {
            payload = event.data.json();
        } catch (e) {
            payload = { body: event.data.text() };
        }
    }
    var title = payload.title || 'EasyChat';
    var chatId = String(payload.chat_id || '');
    var targetUrl = payload.url || (chatId ? 'index.php?route=index&chat_id=' + encodeURIComponent(chatId) : 'index.php?route=index');
    var options = {
        body: payload.body || payload.preview || 'Новое сообщение',
        icon: 'images/icon-192.png',
        badge: 'images/icon-192.png',
        tag: (payload.type === 'new_message' || payload.type === 'chat_assigned') && payload.chat_id ? 'easychat-chat-' + payload.chat_id : 'easychat-push',
        renotify: true,
        data: {
            url: targetUrl,
            chat_id: chatId
        }
    };
    event.waitUntil(self.registration.showNotification(title, options));
});

self.addEventListener('notificationclick', function(event) {
    event.notification.close();
    var url = (event.notification.data && event.notification.data.url) || 'index.php?route=index';
    event.waitUntil(clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function(clientList) {
        for (var i = 0; i < clientList.length; i++) {
            var client = clientList[i];
            if ('focus' in client) {
                client.navigate(url);
                return client.focus();
            }
        }
        if (clients.openWindow) {
            return clients.openWindow(url);
        }
    }));
});
JS;
        exit;
    }

    public function config() {
        header('Content-Type: application/json; charset=utf-8');
        $this->requireOperator();

        if (empty(\EasyChat\Library\RequestContext::session()['easychat_webpush_nonce'])) {
            \EasyChat\Library\RequestContext::session()['easychat_webpush_nonce'] = bin2hex(random_bytes(16));
        }

        $model_setting = new Setting($this->registry);
        $central_api = CentralGatewayClient::normalizeBaseUrl($model_setting->get('chat_central_api'));
        if ($central_api === '') {
            $this->jsonOut([
                'success' => 1,
                'enabled' => false,
                'code' => 'central_api_empty',
                'nonce' => \EasyChat\Library\RequestContext::session()['easychat_webpush_nonce'],
            ]);
        }

        $body = CentralGatewayClient::buildSignedInstallBody($model_setting, $this->domain());
        $result = CentralGatewayClient::postJson($central_api, '/api/v1/auth/domain-status', $body, 5, $this->registry);
        $json = is_array($result['json'] ?? null) ? $result['json'] : [];
        $feature = [];
        if (isset($json['features']) && is_array($json['features']) && isset($json['features']['webpush']) && is_array($json['features']['webpush'])) {
            $feature = $json['features']['webpush'];
        }

        $this->jsonOut([
            'success' => 1,
            'enabled' => !empty($feature['enabled']),
            'paid_required' => !empty($feature['paid_required']),
            'code' => !empty($feature['enabled']) ? '' : (string)($json['code'] ?? 'webpush_unavailable'),
            'vapid_key_id' => (string)($feature['vapid_key_id'] ?? ''),
            'vapid_public_key' => (string)($feature['vapid_public_key'] ?? ''),
            'service_worker_url' => 'index.php?route=webpush/serviceWorker',
            'nonce' => \EasyChat\Library\RequestContext::session()['easychat_webpush_nonce'],
        ]);
    }

    public function subscribe() {
        header('Content-Type: application/json; charset=utf-8');
        $this->requireOperator();
        $input = $this->readJsonInput();
        $this->verifyNonce((string)($input['nonce'] ?? ''));

        $subscription = isset($input['subscription']) && is_array($input['subscription']) ? $input['subscription'] : [];
        if (empty($subscription['endpoint'])) {
            $this->jsonError('missing_webpush_subscription', 422);
        }

        $model_setting = new Setting($this->registry);
        $central_api = CentralGatewayClient::normalizeBaseUrl($model_setting->get('chat_central_api'));
        if ($central_api === '') {
            $this->jsonError('central_api_empty', 422);
        }

        $payload = [
            'domain' => $this->domain(),
            'channel' => 'webpush',
            'action' => 'upsert',
            'audience' => 'operator',
            'vapid_key_id' => (string)($input['vapid_key_id'] ?? ''),
            'subscription' => $subscription,
            'operator_ref_hash' => hash('sha256', CentralGatewayClient::ensureInstallId($model_setting) . ':' . (int)\EasyChat\Library\RequestContext::session()['manager_id']),
            'client' => [
                'app' => 'operator_web',
                'platform' => $this->platform(),
                'browser' => $this->browser(),
            ],
        ];
        $body = $this->signedBody($model_setting, $payload);
        $result = CentralGatewayClient::postJson($central_api, '/api/v1/push/tokens', $body, 5, $this->registry);
        if ((int)$result['status'] !== 200) {
            $this->jsonError((string)($result['error_code'] ?: 'webpush_registration_failed'), (int)$result['status'] ?: 502);
        }

        $this->jsonOut(['success' => 1]);
    }

    public function unsubscribe() {
        header('Content-Type: application/json; charset=utf-8');
        $this->requireOperator();
        $input = $this->readJsonInput();
        $this->verifyNonce((string)($input['nonce'] ?? ''));

        $endpoint = trim((string)($input['endpoint'] ?? ''));
        if ($endpoint === '') {
            $this->jsonError('missing_webpush_endpoint', 422);
        }

        $model_setting = new Setting($this->registry);
        $central_api = CentralGatewayClient::normalizeBaseUrl($model_setting->get('chat_central_api'));
        if ($central_api === '') {
            $this->jsonError('central_api_empty', 422);
        }

        $payload = [
            'domain' => $this->domain(),
            'channel' => 'webpush',
            'action' => 'deactivate',
            'audience' => 'operator',
            'endpoint' => $endpoint,
        ];
        $body = $this->signedBody($model_setting, $payload);
        CentralGatewayClient::postJson($central_api, '/api/v1/push/tokens', $body, 5, $this->registry);

        $this->jsonOut(['success' => 1]);
    }

    private function requireOperator() {
        if ((defined('EASYCHAT_SESSION_AVAILABLE') && !EASYCHAT_SESSION_AVAILABLE)
            || !\EasyChat\Library\SessionBootstrap::isAvailable()
            || empty(\EasyChat\Library\RequestContext::session()['manager_id'])
            || !empty(\EasyChat\Library\RequestContext::session()['cms_handoff_pending_claim'])
        ) {
            $this->jsonError('unauthorized', 401);
        }
        $db = $this->registry->get('db');
        if (!$db) {
            $this->jsonError('unauthorized', 401);
        }

        $manager_id = (int)\EasyChat\Library\RequestContext::session()['manager_id'];
        $prefix = easychat_db_prefix();
        $query = $db->query("SELECT `password`, `status` FROM `{$prefix}managers` WHERE `id` = " . $manager_id . " LIMIT 1");
        $session_hash = (string)(\EasyChat\Library\RequestContext::session()['manager_pass_hash'] ?? '');
        if (!$query || !$query->row || (int)$query->row['status'] !== 1 || !hash_equals($session_hash, md5($query->row['password']))) {
            \EasyChat\Library\SessionBootstrap::destroy();
            $this->jsonError('unauthorized', 401);
        }
    }

    private function verifyNonce($nonce) {
        if (empty(\EasyChat\Library\RequestContext::session()['easychat_webpush_nonce']) || !hash_equals((string)\EasyChat\Library\RequestContext::session()['easychat_webpush_nonce'], (string)$nonce)) {
            $this->jsonError('invalid_nonce', 403);
        }
    }

    private function signedBody($model_setting, array $payload) {
        $payload = CentralGatewayClient::withBaseDomain($model_setting, $payload);
        $license = trim((string)$model_setting->get('chat_license'));
        $install_id = CentralGatewayClient::ensureInstallId($model_setting);
        if ($license !== '') {
            return CentralGatewayClient::signedBody($license, $install_id, $payload);
        }

        return CentralGatewayClient::signedUnlicensedBody(
            CentralGatewayClient::ensureInstallSecret($model_setting),
            $install_id,
            $payload
        );
    }

    private function readJsonInput() {
        $raw = file_get_contents('php://input');
        $decoded = json_decode(is_string($raw) ? $raw : '', true);
        return is_array($decoded) ? $decoded : [];
    }

    private function domain() {
        $domain = \EasyChat\Library\RequestContext::server()['HTTP_HOST'] ?? '';
        if ($domain !== '' && function_exists('easychat_public_host')) {
            $domain = easychat_public_host($domain);
        }
        return $domain !== '' ? $domain : 'localhost';
    }

    private function platform() {
        $ua = strtolower((string)(\EasyChat\Library\RequestContext::server()['HTTP_USER_AGENT'] ?? ''));
        if (strpos($ua, 'iphone') !== false || strpos($ua, 'ipad') !== false) return 'ios';
        if (strpos($ua, 'android') !== false) return 'android';
        if (strpos($ua, 'windows') !== false) return 'windows';
        if (strpos($ua, 'mac os') !== false) return 'macos';
        return 'desktop';
    }

    private function browser() {
        $ua = strtolower((string)(\EasyChat\Library\RequestContext::server()['HTTP_USER_AGENT'] ?? ''));
        if (strpos($ua, 'edg/') !== false) return 'edge';
        if (strpos($ua, 'firefox/') !== false) return 'firefox';
        if (strpos($ua, 'chrome/') !== false || strpos($ua, 'crios/') !== false) return 'chrome';
        if (strpos($ua, 'safari/') !== false) return 'safari';
        return 'other';
    }

    private function jsonOut(array $payload, $status = 200) {
        http_response_code((int)$status);
        echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }

    private function jsonError($code, $status = 400) {
        $this->jsonOut(['success' => 0, 'error' => (string)$code, 'code' => (string)$code], $status);
    }
}
