<?php
namespace App\Core;

use PDO;

class Notifier
{
    public static function normalizeUrl(?string $url): ?string
    {
        $url = trim((string)$url);
        if ($url === '') {
            return null;
        }

        if (preg_match('~^(?:https?:)?//~i', $url) || str_starts_with($url, '#')) {
            return $url;
        }

        return route_url($url);
    }

    public static function ensureDevicesTable(PDO $pdo): void
    {
        // Table de devices pour push mobile (FCM tokens)
        $pdo->exec("CREATE TABLE IF NOT EXISTS user_devices (
            id INT AUTO_INCREMENT PRIMARY KEY,
            user_id INT NOT NULL,
            platform VARCHAR(20) NULL,
            device_id VARCHAR(120) NULL,
            fcm_token VARCHAR(255) NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            last_seen_at DATETIME NULL,
            UNIQUE KEY uniq_user_token (user_id, fcm_token),
            INDEX(user_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    }

    public static function ensureTables(PDO $pdo): void
    {
        $pdo->exec("CREATE TABLE IF NOT EXISTS notifications (
            id INT AUTO_INCREMENT PRIMARY KEY,
            user_id INT NOT NULL,
            title VARCHAR(200) NOT NULL,
            body TEXT NULL,
            url VARCHAR(300) NULL,
            is_read TINYINT(1) NOT NULL DEFAULT 0,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (user_id) REFERENCES users(id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    }

    public static function ensurePublicClientNotificationsTable(PDO $pdo): void
    {
        $pdo->exec("CREATE TABLE IF NOT EXISTS public_mobile_notifications (
            id INT AUTO_INCREMENT PRIMARY KEY,
            public_client_id INT NOT NULL,
            title VARCHAR(200) NOT NULL,
            body TEXT NULL,
            url VARCHAR(300) NULL,
            is_read TINYINT(1) NOT NULL DEFAULT 0,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_public_client_notifications_client (public_client_id),
            INDEX idx_public_client_notifications_read (public_client_id, is_read)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    }

    /**
     * Crée des notifications in-app pour plusieurs utilisateurs.
     */
    public static function notifyUsers(PDO $pdo, array $userIds, string $title, string $body, ?string $url = null): void
    {
        if (empty($userIds)) { return; }
        self::ensureTables($pdo);
        $url = self::normalizeUrl($url);
        $stmt = $pdo->prepare('INSERT INTO notifications(user_id,title,body,url,is_read,created_at) VALUES (?,?,?,?,0,NOW())');
        foreach (array_unique(array_map('intval', $userIds)) as $uid) {
            $stmt->execute([$uid, $title, $body, $url]);
        }
    }

    /**
     * Envoi push FCM (optionnel): no-op si non configuré.
     * Note: nécessite la clé serveur (legacy) via Config::get('fcm_server_key').
     */
    public static function pushUsers(PDO $pdo, array $userIds, string $title, string $body, ?string $url = null): void
    {
        if (empty($userIds)) { return; }
        $url = self::normalizeUrl($url);
        $serverKey = (string)Config::get('fcm_server_key', '');
        if (trim($serverKey) === '') { return; }

        try {
            self::ensureDevicesTable($pdo);
            self::ensureTables($pdo);

            $uids = array_values(array_unique(array_map('intval', $userIds)));
            $in = implode(',', array_fill(0, count($uids), '?'));
            $st = $pdo->prepare("SELECT user_id, fcm_token FROM user_devices WHERE user_id IN ($in)");
            $st->execute($uids);
            $rows = $st->fetchAll(PDO::FETCH_ASSOC);
            if (empty($rows)) { return; }

            // Regrouper tokens par user pour calculer badge/unread
            $tokens = [];
            $byUser = [];
            foreach ($rows as $r) {
                $t = trim((string)($r['fcm_token'] ?? ''));
                $uid = (int)($r['user_id'] ?? 0);
                if ($t === '' || $uid <= 0) { continue; }
                $tokens[] = $t;
                if (!isset($byUser[$uid])) { $byUser[$uid] = []; }
                $byUser[$uid][] = $t;
            }
            if (empty($tokens)) { return; }

            // Unread count (approx) : si plusieurs users, on ne peut pas mettre un badge distinct par token avec un seul call.
            // On envoie donc le badge global côté app via refresh API.
            $payload = [
                'registration_ids' => array_values(array_unique($tokens)),
                'priority' => 'high',
                'notification' => [
                    'title' => $title,
                    'body' => $body,
                ],
                'data' => [
                    'url' => $url ?: '',
                    'type' => 'in_app_notification',
                ],
            ];

            $ch = curl_init('https://fcm.googleapis.com/fcm/send');
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: key=' . $serverKey,
                'Content-Type: application/json',
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 6);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload, JSON_UNESCAPED_UNICODE));
            $resp = curl_exec($ch);
            curl_close($ch);
        } catch (\Throwable $e) {
            // ignorer
        }
    }

    /**
     * Envoie des emails à une liste d’utilisateurs (par id).
     */
    public static function emailUsers(PDO $pdo, array $userIds, string $subject, string $htmlBody): void
    {
        if (empty($userIds)) { return; }
        $in  = implode(',', array_fill(0, count($userIds), '?'));
        $st = $pdo->prepare("SELECT id,name,email FROM users WHERE id IN ($in) AND active=1");
        $st->execute(array_values(array_unique(array_map('intval', $userIds))));
        $rows = $st->fetchAll();
        foreach ($rows as $u) {
            if (!empty($u['email'])) {
                Mailer::send($u['email'], $u['name'] ?: 'Utilisateur', $subject, $htmlBody, $pdo);
            }
        }
    }

    public static function notifyPublicClients(PDO $pdo, array $clientIds, string $title, string $body, ?string $url = null): void
    {
        if (empty($clientIds)) { return; }
        self::ensurePublicClientNotificationsTable($pdo);
        $url = self::normalizeUrl($url);
        $stmt = $pdo->prepare('INSERT INTO public_mobile_notifications(public_client_id,title,body,url,is_read,created_at) VALUES (?,?,?,?,0,NOW())');
        foreach (array_unique(array_map('intval', $clientIds)) as $clientId) {
            if ($clientId <= 0) {
                continue;
            }
            $stmt->execute([$clientId, $title, $body, $url]);
        }
    }
}
