<?php
namespace EasyChat\Library;

use EasyChat\Model\Session;
use EasyChat\Model\MessageContext;
use EasyChat\Model\Setting;







class CustomerWebPushNotifier {
    private $registry;
    private $settings;
    private $logger;

    public function __construct($registry) {
        $this->registry = $registry;
        $this->settings = new Setting($registry);
        $this->logger = $this->settings->get('chat_fcm_logging', '0') === '1'
            ? new Log('fcm')
            : new class { public function write($message) {} };
    }

    public function notifyReply(int $chat_id, string $reply_source = 'operator'): array {
        if ($chat_id <= 0) {
            return ['success' => true, 'sent' => 0, 'skipped' => 'invalid_chat'];
        }

        $session_model = new Session($this->registry);
        $chat = $session_model->getSessionById($chat_id);
        if (!$chat) {
            return ['success' => true, 'sent' => 0, 'skipped' => 'chat_not_found'];
        }

        $source_provider = strtolower(trim((string)($chat['source_provider'] ?? 'widget')));
        if ($source_provider !== '' && $source_provider !== 'widget') {
            return ['success' => true, 'sent' => 0, 'skipped' => 'not_widget_chat'];
        }

        $session_id = (string)($chat['session_id'] ?? '');
        if ($session_id === '') {
            return ['success' => true, 'sent' => 0, 'skipped' => 'session_missing'];
        }

        $central_api = CentralGatewayClient::normalizeBaseUrl($this->settings->get('chat_central_api'));
        if ($central_api === '') {
            return ['success' => true, 'sent' => 0, 'skipped' => 'central_api_empty'];
        }

        $domain = $this->domainForChat($chat_id);
        $install_id = CentralGatewayClient::ensureInstallId($this->settings);
        $chat_ref_hash = self::chatRefHash($install_id, $chat_id, $session_id);
        $body_text = $this->notificationBody($domain);

        $payload = CentralGatewayClient::withBaseDomain($this->settings, [
            'domain' => $domain,
            'audience' => 'customer',
            'target' => 'customer_chat',
            'channels' => ['webpush'],
            'chat_ref_hash' => $chat_ref_hash,
            'event_id' => 'customer_reply:' . $chat_ref_hash . ':' . time(),
            'data' => [
                'type' => 'customer_reply',
                'audience' => 'customer',
                'chat_ref_hash' => $chat_ref_hash,
                'title' => $this->notificationTitle(),
                'body' => $body_text,
                'preview' => $body_text,
                'domain' => $domain,
                'source_provider' => $this->safeSource($reply_source),
            ],
        ]);

        $body = $this->signedBody($payload);
        $result = CentralGatewayClient::postJson($central_api, '/api/v1/push/messages', $body, 5, $this->registry);
        $json = is_array($result['json'] ?? null) ? $result['json'] : [];
        $fanout = is_array($json['fanout'] ?? null) ? $json['fanout'] : [];
        $delivered = (int)($fanout['delivered'] ?? 0);
        $failed = (int)($fanout['failed'] ?? 0);
        $status = (int)($result['status'] ?? 0);
        $error_code = (string)($result['error_code'] ?? '');

        if ($status === 200) {
            $this->logger->write('[CustomerWebPushNotifier] fanout success chat_hash=' . substr($chat_ref_hash, 0, 16) . ', delivered=' . $delivered . ', failed=' . $failed);
            return [
                'success' => $failed === 0 || $delivered > 0,
                'sent' => $delivered,
                'failed' => $failed,
                'fanout' => 1,
            ];
        }

        if ($status === 402 && $error_code === 'webpush_paid_required') {
            return ['success' => true, 'sent' => 0, 'skipped' => 'webpush_paid_required'];
        }

        $this->logger->write('[CustomerWebPushNotifier] failed chat_hash=' . substr($chat_ref_hash, 0, 16) . ', http_status=' . $status . ', error_code=' . $error_code);
        return ['success' => false, 'sent' => 0, 'failed' => 1, 'error_code' => $error_code !== '' ? $error_code : 'customer_webpush_failed'];
    }

    public static function chatRefHash(string $install_id, int $chat_id, string $session_id): string {
        return hash('sha256', $install_id . ':customer:' . (int)$chat_id . ':' . $session_id);
    }

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

        return CentralGatewayClient::signedUnlicensedBody(
            CentralGatewayClient::ensureInstallSecret($this->settings),
            $install_id,
            $payload
        );
    }

    private function notificationTitle(): string {
        $locale = $this->notificationLocale();
        return I18n::translate('widget.push_notification_title', [], $locale);
    }

    private function notificationBody(string $domain): string {
        $locale = $this->notificationLocale();
        return I18n::translate('widget.push_notification_body', ['domain' => $domain], $locale);
    }

    private function notificationLocale(): string {
        $locale = (string)$this->settings->get('chat_widget_locale', 'ru');
        return I18n::normalizeLocale($locale);
    }

    private function safeSource(string $source): string {
        $source = strtolower(trim($source));
        $source = preg_replace('/[^a-z0-9_-]/', '', $source);
        return $source !== '' ? $source : 'operator';
    }

    private function domainForChat(int $chat_id): string {
        $context_domain = $this->domainFromCurrentSiteContext($chat_id);
        return $context_domain !== '' ? $context_domain : $this->domain();
    }

    private function domainFromCurrentSiteContext(int $chat_id): string {
        if ($chat_id <= 0) {
            return '';
        }

        try {
            $context = (new MessageContext($this->registry))->getCurrentSiteContext($chat_id);
        } catch (\Throwable $e) {
            return '';
        }

        $domain = $this->domainFromAllowedUrl((string)($context['url'] ?? ''));
        if ($domain !== '') {
            return $domain;
        }

        return $this->domainFromAllowedUrl((string)($context['canonical_url'] ?? ''));
    }

    private function domainFromAllowedUrl(string $url): string {
        $url = trim($url);
        if ($url === '') {
            return '';
        }

        $host = (string)(parse_url($url, PHP_URL_HOST) ?: '');
        $host = WidgetDomainPolicy::normalizeHost($host);
        if ($host === '') {
            return '';
        }

        $policy = WidgetDomainPolicy::fromSettings($this->settings);
        return $policy->isHostAllowed($host) ? $host : '';
    }

    private function domain(): string {
        $domain = \EasyChat\Library\RequestContext::server()['HTTP_HOST'] ?? '';
        if ($domain !== '' && $domain !== 'localhost') {
            if (function_exists('easychat_public_host')) {
                $domain = easychat_public_host($domain);
            }
            if ($domain !== '' && $domain !== 'localhost') {
                $this->settings->set('chat_last_known_domain', $domain);
                return $domain;
            }
        }

        return (string)$this->settings->get('chat_last_known_domain', 'localhost');
    }
}
