<?php

declare(strict_types=1);

namespace ServerManager\Models;

use ServerManager\Core\Database;

class Notification
{
    private Database $db;

    public function __construct()
    {
        $this->db = Database::getInstance();
    }

    public function create(array $data): int
    {
        $data['created_at'] = date('Y-m-d H:i:s');
        return $this->db->insert('notifications', $data);
    }

    public function findById(int $id): ?array
    {
        return $this->db->fetch('SELECT * FROM notifications WHERE id = ?', [$id]);
    }

    public function getForUser(int $userId, int $page = 1, int $perPage = 20): array
    {
        $offset = ($page - 1) * $perPage;

        $total = $this->db->fetch(
            "SELECT COUNT(*) as total FROM notifications n
             WHERE (n.user_id IS NULL OR n.user_id = ?)",
            [$userId]
        );

        $items = $this->db->fetchAll(
            "SELECT n.*,
                    CASE
                        WHEN nr.id IS NOT NULL THEN 1
                        ELSE 0
                    END as is_read,
                    nr.read_at as read_at,
                    (SELECT COUNT(*) FROM notification_reads WHERE notification_id = n.id) as total_reads,
                    (SELECT COUNT(*) FROM users WHERE status = 'active') as total_users
             FROM notifications n
             LEFT JOIN notification_reads nr ON nr.notification_id = n.id AND nr.user_id = ?
             WHERE n.user_id IS NULL OR n.user_id = ?
             ORDER BY n.created_at DESC LIMIT ? OFFSET ?",
            [$userId, $userId, $perPage, $offset]
        );

        return [
            'data' => $items,
            'total' => (int) ($total['total'] ?? 0),
            'page' => $page,
            'per_page' => $perPage,
            'total_pages' => (int) ceil((int) ($total['total'] ?? 0) / $perPage),
        ];
    }

    public function getUnreadCount(int $userId): int
    {
        $result = $this->db->fetch(
            "SELECT COUNT(*) as total FROM notifications n
             WHERE (n.user_id IS NULL OR n.user_id = ?)
             AND NOT EXISTS (
                 SELECT 1 FROM notification_reads nr
                 WHERE nr.notification_id = n.id AND nr.user_id = ?
             )",
            [$userId, $userId]
        );
        return (int) ($result['total'] ?? 0);
    }

    public function markAsRead(int $id, int $userId): void
    {
        try {
            $this->db->insert('notification_reads', [
                'notification_id' => $id,
                'user_id' => $userId,
                'read_at' => date('Y-m-d H:i:s'),
            ]);
        } catch (\Throwable $e) {
            // Already read, ignore
        }
    }

    public function markAllAsRead(int $userId): void
    {
        $unread = $this->db->fetchAll(
            "SELECT n.id FROM notifications n
             WHERE (n.user_id IS NULL OR n.user_id = ?)
             AND NOT EXISTS (
                 SELECT 1 FROM notification_reads nr
                 WHERE nr.notification_id = n.id AND nr.user_id = ?
             )",
            [$userId, $userId]
        );

        $now = date('Y-m-d H:i:s');
        foreach ($unread as $note) {
            try {
                $this->db->insert('notification_reads', [
                    'notification_id' => (int) $note['id'],
                    'user_id' => $userId,
                    'read_at' => $now,
                ]);
            } catch (\Throwable $e) {
                // Duplicate entry — already read, skip
            }
        }
    }

    public function getAll(int $page = 1, int $perPage = 20): array
    {
        $offset = ($page - 1) * $perPage;

        $total = $this->db->fetch("SELECT COUNT(*) as total FROM notifications");

        $items = $this->db->fetchAll(
            "SELECT n.*, u.username as target_username,
                    (SELECT COUNT(*) FROM notification_reads nr WHERE nr.notification_id = n.id) as read_count
             FROM notifications n
             LEFT JOIN users u ON n.user_id = u.id
             ORDER BY n.created_at DESC LIMIT ? OFFSET ?",
            [$perPage, $offset]
        );

        return [
            'data' => $items,
            'total' => (int) ($total['total'] ?? 0),
            'page' => $page,
            'per_page' => $perPage,
            'total_pages' => (int) ceil((int) ($total['total'] ?? 0) / $perPage),
        ];
    }

    public function getTotalActiveUsers(): int
    {
        $result = $this->db->fetch("SELECT COUNT(*) as total FROM users WHERE status = 'active'");
        return (int) ($result['total'] ?? 0);
    }
}
