<?php
/**
 * PWAManager - Progressive Web App Management Utility
 * 
 * Handles PWA-related operations like sending notifications,
 * managing push subscriptions, and tracking sync operations
 */

class PWAManager
{
    private $db;
    private $settings;

    public function __construct(Database $db = null, Settings $settings = null)
    {
        $this->db = $db ?? new Database();
        $this->settings = $settings ?? new Settings();
    }

    /**
     * Send a notification to a user
     */
    public function sendNotification($userId, $title, $message, $type = 'info', $options = [])
    {
        try {
            $data = $options['data'] ?? null;
            $icon = $options['icon'] ?? '/invcount/assets/images/icons/icon-192x192.png';
            $tag = $options['tag'] ?? null;

            $this->db->execute(
                "INSERT INTO notifications (user_id, title, message, type, icon, tag, data, created_at)
                 VALUES (?, ?, ?, ?, ?, ?, ?, NOW())",
                [
                    $userId,
                    $title,
                    $message,
                    $type,
                    $icon,
                    $tag,
                    json_encode($data),
                ]
            );

            // If push is enabled and user has subscription, send push notification
            if ($options['push'] ?? false) {
                $this->sendPushNotification($userId, $title, $message, $options);
            }

            return true;
        } catch (Exception $e) {
            error_log('[PWAManager] Error sending notification: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Send a push notification via Web Push
     */
    public function sendPushNotification($userId, $title, $message, $options = [])
    {
        try {
            // Get user's push subscription
            $subscription = $this->db->fetchOne(
                "SELECT * FROM push_subscriptions WHERE user_id = ?",
                [$userId]
            );

            if (!$subscription) {
                error_log('[PWAManager] No push subscription found for user ' . $userId);
                return false;
            }

            // Check if web-push library is available
            if (!class_exists('Minishlink\WebPush\WebPush')) {
                error_log('[PWAManager] web-push library not installed');
                return false;
            }

            // Get VAPID keys
            $publicKey = $this->settings->get('push_vapid_public_key') ?? 
                        define('VAPID_PUBLIC_KEY') ? VAPID_PUBLIC_KEY : null;
            $privateKey = $this->settings->get('push_vapid_private_key') ?? 
                         defined('VAPID_PRIVATE_KEY') ? VAPID_PRIVATE_KEY : null;

            if (!$publicKey || !$privateKey) {
                error_log('[PWAManager] VAPID keys not configured');
                return false;
            }

            // Prepare push payload
            $payload = [
                'title' => $title,
                'body' => $message,
                'icon' => $options['icon'] ?? '/invcount/assets/images/icons/icon-192x192.png',
                'badge' => '/invcount/assets/images/icons/badge-72x72.png',
                'tag' => $options['tag'] ?? null,
                'data' => $options['data'] ?? [],
            ];

            // Create WebPush instance
            $webPush = new \Minishlink\WebPush\WebPush(
                [
                    'VAPID' => [
                        'subject' => defined('APP_URL') ? APP_URL : 'https://example.com',
                        'publicKey' => $publicKey,
                        'privateKey' => $privateKey,
                    ],
                ]
            );

            // Send push notification
            $res = $webPush->sendOneNotification(
                $subscription['endpoint'],
                json_encode($payload),
                [
                    'TTL' => 24 * 60 * 60, // 24 hours
                ]
            );

            return true;
        } catch (Exception $e) {
            error_log('[PWAManager] Error sending push notification: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Broadcast notification to multiple users
     */
    public function broadcastNotification($userIds, $title, $message, $type = 'info', $options = [])
    {
        $sent = 0;
        foreach ($userIds as $userId) {
            if ($this->sendNotification($userId, $title, $message, $type, $options)) {
                $sent++;
            }
        }
        return $sent;
    }

    /**
     * Send notification to all users with a role
     */
    public function notifyRole($role, $title, $message, $type = 'info', $options = [])
    {
        try {
            $users = $this->db->fetchAll(
                "SELECT id FROM users WHERE role = ?",
                [$role]
            );

            $userIds = array_column($users, 'id');
            return $this->broadcastNotification($userIds, $title, $message, $type, $options);
        } catch (Exception $e) {
            error_log('[PWAManager] Error notifying role: ' . $e->getMessage());
            return 0;
        }
    }

    /**
     * Log a sync operation
     */
    public function logSync($userId, $operation, $tableName, $recordId = null, $status = 'pending', $error = null)
    {
        try {
            $this->db->execute(
                "INSERT INTO sync_logs (user_id, operation, table_name, record_id, status, error_message, created_at)
                 VALUES (?, ?, ?, ?, ?, ?, NOW())",
                [$userId, $operation, $tableName, $recordId, $status, $error]
            );

            return true;
        } catch (Exception $e) {
            error_log('[PWAManager] Error logging sync: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Mark sync as completed
     */
    public function markSyncComplete($syncId)
    {
        try {
            $this->db->execute(
                "UPDATE sync_logs SET status = 'synced', synced_at = NOW() WHERE id = ?",
                [$syncId]
            );

            return true;
        } catch (Exception $e) {
            error_log('[PWAManager] Error marking sync complete: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Get pending syncs for a user
     */
    public function getPendingSyncs($userId, $limit = 100)
    {
        try {
            return $this->db->fetchAll(
                "SELECT * FROM sync_logs WHERE user_id = ? AND status = 'pending' ORDER BY created_at LIMIT ?",
                [$userId, $limit]
            );
        } catch (Exception $e) {
            error_log('[PWAManager] Error getting pending syncs: ' . $e->getMessage());
            return [];
        }
    }

    /**
     * Get sync status for a user
     */
    public function getSyncStatus($userId)
    {
        try {
            $pending = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM sync_logs WHERE user_id = ? AND status = 'pending'",
                [$userId]
            );

            $synced = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM sync_logs WHERE user_id = ? AND status = 'synced'",
                [$userId]
            );

            $failed = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM sync_logs WHERE user_id = ? AND status = 'failed'",
                [$userId]
            );

            $lastSync = $this->db->fetchOne(
                "SELECT MAX(synced_at) as last_sync FROM sync_logs WHERE user_id = ? AND status = 'synced'",
                [$userId]
            );

            return [
                'pending' => $pending['count'] ?? 0,
                'synced' => $synced['count'] ?? 0,
                'failed' => $failed['count'] ?? 0,
                'last_sync' => $lastSync['last_sync'] ?? null,
            ];
        } catch (Exception $e) {
            error_log('[PWAManager] Error getting sync status: ' . $e->getMessage());
            return [];
        }
    }

    /**
     * Check if user has push enabled
     */
    public function hasPushEnabled($userId)
    {
        try {
            $sub = $this->db->fetchOne(
                "SELECT id FROM push_subscriptions WHERE user_id = ?",
                [$userId]
            );

            return !empty($sub);
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Get user's offline settings
     */
    public function getOfflineSettings($userId)
    {
        try {
            $settings = $this->db->fetchOne(
                "SELECT * FROM offline_settings WHERE user_id = ?",
                [$userId]
            );

            if (!$settings) {
                // Create default settings
                $this->db->execute(
                    "INSERT INTO offline_settings (user_id, auto_sync_enabled, push_enabled)
                     VALUES (?, ?, ?)",
                    [$userId, true, false]
                );

                $settings = $this->db->fetchOne(
                    "SELECT * FROM offline_settings WHERE user_id = ?",
                    [$userId]
                );
            }

            return $settings;
        } catch (Exception $e) {
            error_log('[PWAManager] Error getting offline settings: ' . $e->getMessage());
            return null;
        }
    }

    /**
     * Update user's offline settings
     */
    public function updateOfflineSettings($userId, $settings)
    {
        try {
            $updates = [];
            $params = [];

            foreach ($settings as $key => $value) {
                $updates[] = "`{$key}` = ?";
                $params[] = $value;
            }

            $params[] = $userId;

            if (!empty($updates)) {
                $this->db->execute(
                    "UPDATE offline_settings SET " . implode(', ', $updates) . " WHERE user_id = ?",
                    $params
                );
            }

            return true;
        } catch (Exception $e) {
            error_log('[PWAManager] Error updating offline settings: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Cleanup old sync logs (older than X days)
     */
    public function cleanupSyncLogs($daysOld = 30)
    {
        try {
            $this->db->execute(
                "DELETE FROM sync_logs WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)",
                [$daysOld]
            );

            return true;
        } catch (Exception $e) {
            error_log('[PWAManager] Error cleaning up sync logs: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Cleanup old read notifications (older than X days)
     */
    public function cleanupNotifications($daysOld = 30)
    {
        try {
            $this->db->execute(
                "DELETE FROM notifications WHERE read_at IS NOT NULL AND read_at < DATE_SUB(NOW(), INTERVAL ? DAY)",
                [$daysOld]
            );

            return true;
        } catch (Exception $e) {
            error_log('[PWAManager] Error cleaning up notifications: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Get PWA statistics
     */
    public function getStats()
    {
        try {
            $totalUsers = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM users"
            );

            $usersWithPush = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM push_subscriptions"
            );

            $pendingSyncs = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM sync_logs WHERE status = 'pending'"
            );

            $failedSyncs = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM sync_logs WHERE status = 'failed'"
            );

            $totalNotifications = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM notifications"
            );

            $unreadNotifications = $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM notifications WHERE read_at IS NULL"
            );

            return [
                'total_users' => $totalUsers['count'] ?? 0,
                'users_with_push' => $usersWithPush['count'] ?? 0,
                'pending_syncs' => $pendingSyncs['count'] ?? 0,
                'failed_syncs' => $failedSyncs['count'] ?? 0,
                'total_notifications' => $totalNotifications['count'] ?? 0,
                'unread_notifications' => $unreadNotifications['count'] ?? 0,
            ];
        } catch (Exception $e) {
            error_log('[PWAManager] Error getting stats: ' . $e->getMessage());
            return [];
        }
    }

    /**
     * Test push notification (for debugging)
     */
    public function sendTestNotification($userId)
    {
        return $this->sendNotification(
            $userId,
            'Test Notification',
            'This is a test push notification from your PWA',
            'info',
            ['push' => true, 'tag' => 'test-notification']
        );
    }

    /**
     * Verify VAPID keys are configured
     */
    public function isConfigured()
    {
        $publicKey = $this->settings->get('push_vapid_public_key') ?? 
                    (defined('VAPID_PUBLIC_KEY') ? VAPID_PUBLIC_KEY : null);
        $privateKey = $this->settings->get('push_vapid_private_key') ?? 
                     (defined('VAPID_PRIVATE_KEY') ? VAPID_PRIVATE_KEY : null);

        return !empty($publicKey) && !empty($privateKey);
    }

    /**
     * Get configuration status
     */
    public function getStatus()
    {
        return [
            'vapid_configured' => $this->isConfigured(),
            'database_ready' => !empty($this->db),
            'tables_exist' => $this->checkTablesExist(),
        ];
    }

    /**
     * Check if required tables exist
     */
    private function checkTablesExist()
    {
        try {
            $tables = $this->db->fetchAll(
                "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE()
                 AND TABLE_NAME IN ('notifications', 'push_subscriptions', 'sync_logs', 'offline_settings')"
            );

            return count($tables) === 4;
        } catch (Exception $e) {
            return false;
        }
    }
}
