<?php
/**
 * Service de Notifications Push
 * Gestion des souscriptions et envoi de notifications push Web
 */

namespace App\Services;

use Core\Database;
use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;

class PushNotificationService
{
    private $db;
    private ?WebPush $webPush = null;
    
    // Clés VAPID (à configurer dans config/app.php)
    private string $publicKey;
    private string $privateKey;
    private string $subject;

    public function __construct()
    {
        $this->db = Database::getInstance();
        $this->publicKey = defined('VAPID_PUBLIC_KEY') ? VAPID_PUBLIC_KEY : '';
        $this->privateKey = defined('VAPID_PRIVATE_KEY') ? VAPID_PRIVATE_KEY : '';
        $this->subject = defined('VAPID_SUBJECT') ? VAPID_SUBJECT : 'mailto:contact@mysupport.com';
        
        $this->initWebPush();
    }
    
    /**
     * Initialise WebPush avec les clés VAPID
     */
    private function initWebPush(): void
    {
        if (empty($this->publicKey) || empty($this->privateKey)) {
            return;
        }
        
        try {
            $this->webPush = new WebPush([
                'VAPID' => [
                    'subject' => $this->subject,
                    'publicKey' => $this->publicKey,
                    'privateKey' => $this->privateKey
                ]
            ]);
        } catch (\Exception $e) {
            error_log("WebPush init error: " . $e->getMessage());
        }
    }

    /**
     * Récupère la clé publique VAPID
     */
    public function getPublicKey(): string
    {
        return $this->publicKey;
    }

    /**
     * Enregistre une souscription push
     */
    public function subscribe(int $userId, int $entrepriseId, array $subscription): bool
    {
        $endpoint = $subscription['endpoint'] ?? '';
        $p256dh = $subscription['keys']['p256dh'] ?? '';
        $auth = $subscription['keys']['auth'] ?? '';

        if (empty($endpoint) || empty($p256dh) || empty($auth)) {
            return false;
        }

        // Vérifier si la souscription existe déjà
        $existing = $this->db->fetch(
            "SELECT id FROM push_subscriptions WHERE user_id = :uid AND endpoint = :endpoint",
            ['uid' => $userId, 'endpoint' => $endpoint]
        );

        if ($existing) {
            // Mettre à jour
            $this->db->query(
                "UPDATE push_subscriptions SET p256dh = :p256dh, auth = :auth, is_active = TRUE, updated_at = NOW() 
                 WHERE id = :id",
                ['p256dh' => $p256dh, 'auth' => $auth, 'id' => $existing['id']]
            );
        } else {
            // Créer nouvelle souscription
            $this->db->insert('push_subscriptions', [
                'user_id' => $userId,
                'entreprise_id' => $entrepriseId,
                'endpoint' => $endpoint,
                'p256dh' => $p256dh,
                'auth' => $auth,
                'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
                'is_active' => true,
                'created_at' => date('Y-m-d H:i:s')
            ]);
        }

        return true;
    }

    /**
     * Supprime une souscription
     */
    public function unsubscribe(int $userId, string $endpoint): bool
    {
        $this->db->query(
            "DELETE FROM push_subscriptions WHERE user_id = :uid AND endpoint = :endpoint",
            ['uid' => $userId, 'endpoint' => $endpoint]
        );
        return true;
    }

    /**
     * Envoie une notification à un utilisateur
     */
    public function sendToUser(int $userId, array $payload): array
    {
        $subscriptions = $this->db->fetchAll(
            "SELECT * FROM push_subscriptions WHERE user_id = :uid AND is_active = TRUE",
            ['uid' => $userId]
        );

        $results = ['sent' => 0, 'failed' => 0];

        foreach ($subscriptions as $sub) {
            if ($this->sendNotification($sub, $payload)) {
                $results['sent']++;
            } else {
                $results['failed']++;
            }
        }

        return $results;
    }

    /**
     * Envoie une notification à tous les agents d'une entreprise
     */
    public function sendToEnterprise(int $entrepriseId, array $payload, ?string $role = null): array
    {
        $sql = "SELECT ps.* FROM push_subscriptions ps
                JOIN users u ON ps.user_id = u.id
                WHERE ps.entreprise_id = :eid AND ps.is_active = TRUE AND u.is_active = TRUE";
        $params = ['eid' => $entrepriseId];

        if ($role) {
            $sql .= " AND u.role = :role";
            $params['role'] = $role;
        }

        $subscriptions = $this->db->fetchAll($sql, $params);

        $results = ['sent' => 0, 'failed' => 0];

        foreach ($subscriptions as $sub) {
            if ($this->sendNotification($sub, $payload)) {
                $results['sent']++;
            } else {
                $results['failed']++;
            }
        }

        return $results;
    }

    /**
     * Envoie notification pour nouveau message
     */
    public function notifyNewMessage(int $entrepriseId, array $messageData): array
    {
        $payload = [
            'title' => 'Nouveau message',
            'body' => substr($messageData['content'] ?? 'Message reçu', 0, 100),
            'icon' => '/assets/icons/icon-192x192.png',
            'tag' => 'message-' . ($messageData['conversation_id'] ?? ''),
            'data' => [
                'type' => 'new_message',
                'conversation_id' => $messageData['conversation_id'] ?? null,
                'url' => '/agent/conversation/' . ($messageData['conversation_id'] ?? '')
            ],
            'actions' => [
                ['action' => 'open', 'title' => 'Voir'],
                ['action' => 'dismiss', 'title' => 'Ignorer']
            ]
        ];

        return $this->sendToEnterprise($entrepriseId, $payload, 'agent');
    }

    /**
     * Envoie notification pour nouveau ticket
     */
    public function notifyNewTicket(int $entrepriseId, array $ticketData): array
    {
        $payload = [
            'title' => '🎫 Nouveau ticket #' . ($ticketData['ticket_number'] ?? ''),
            'body' => substr($ticketData['sujet'] ?? 'Nouveau ticket créé', 0, 100),
            'icon' => '/assets/icons/icon-192x192.png',
            'tag' => 'ticket-' . ($ticketData['ticket_id'] ?? ''),
            'requireInteraction' => true,
            'data' => [
                'type' => 'new_ticket',
                'ticket_id' => $ticketData['ticket_id'] ?? null,
                'url' => '/agent/tickets'
            ]
        ];

        return $this->sendToEnterprise($entrepriseId, $payload, 'agent');
    }

    /**
     * Envoie notification pour demande de chat live
     */
    public function notifyLiveChatRequest(int $entrepriseId, array $requestData): array
    {
        $payload = [
            'title' => '💬 Demande de chat en direct',
            'body' => 'Un client attend pour parler avec un agent',
            'icon' => '/assets/icons/icon-192x192.png',
            'tag' => 'live-chat-' . ($requestData['request_id'] ?? ''),
            'requireInteraction' => true,
            'vibrate' => [200, 100, 200, 100, 200],
            'data' => [
                'type' => 'live_chat_request',
                'request_id' => $requestData['request_id'] ?? null,
                'url' => '/agent'
            ]
        ];

        return $this->sendToEnterprise($entrepriseId, $payload, 'agent');
    }

    /**
     * Envoie la notification push (implémentation Web Push)
     */
    private function sendNotification(array $subscription, array $payload): bool
    {
        if (!$this->webPush) {
            error_log("Push: WebPush not initialized (VAPID keys missing?)");
            return false;
        }

        try {
            $sub = Subscription::create([
                'endpoint' => $subscription['endpoint'],
                'publicKey' => $subscription['p256dh'],
                'authToken' => $subscription['auth']
            ]);

            $payloadJson = json_encode($payload);
            
            $report = $this->webPush->sendOneNotification($sub, $payloadJson);
            
            if ($report->isSuccess()) {
                return true;
            }
            
            error_log("Push failed: " . $report->getReason());
            
            // Marquer la souscription comme inactive si endpoint invalide
            if ($report->isSubscriptionExpired()) {
                $this->db->query(
                    "UPDATE push_subscriptions SET is_active = FALSE WHERE id = :id",
                    ['id' => $subscription['id']]
                );
            }
            
            return false;

        } catch (\Exception $e) {
            error_log("Push Error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Récupère les souscriptions d'un utilisateur
     */
    public function getUserSubscriptions(int $userId): array
    {
        return $this->db->fetchAll(
            "SELECT id, endpoint, user_agent, is_active, created_at 
             FROM push_subscriptions WHERE user_id = :uid ORDER BY created_at DESC",
            ['uid' => $userId]
        );
    }

    /**
     * Nettoie les souscriptions inactives
     */
    public function cleanupInactive(): int
    {
        $result = $this->db->query(
            "DELETE FROM push_subscriptions WHERE is_active = FALSE OR updated_at < DATE_SUB(NOW(), INTERVAL 30 DAY)"
        );
        return $result->rowCount();
    }
}
