<?php
declare(strict_types=1);

namespace App\Models;

use PDO;

class Notification extends BaseModel
{
    protected string $table = 'notifications';

    public function recentForUser(int $userId, int $limit = 12): array
    {
        $limit = min(max($limit, 1), 40);
        $statement = $this->db()->prepare(
            'SELECT id, type, title, body, data, read_at, created_at
             FROM notifications
             WHERE user_id = :user_id
             ORDER BY created_at DESC, id DESC
             LIMIT :limit'
        );
        $statement->bindValue('user_id', $userId, PDO::PARAM_INT);
        $statement->bindValue('limit', $limit, PDO::PARAM_INT);
        $statement->execute();

        return array_map([$this, 'normalize'], $statement->fetchAll());
    }

    public function unreadCount(int $userId): int
    {
        $statement = $this->db()->prepare('SELECT COUNT(*) FROM notifications WHERE user_id = :user_id AND read_at IS NULL');
        $statement->execute(['user_id' => $userId]);

        return (int) $statement->fetchColumn();
    }

    public function markRead(int $userId, int $id): void
    {
        $statement = $this->db()->prepare('UPDATE notifications SET read_at = COALESCE(read_at, NOW()) WHERE id = :id AND user_id = :user_id');
        $statement->execute(['id' => $id, 'user_id' => $userId]);
    }

    public function markAllRead(int $userId): void
    {
        $statement = $this->db()->prepare('UPDATE notifications SET read_at = COALESCE(read_at, NOW()) WHERE user_id = :user_id AND read_at IS NULL');
        $statement->execute(['user_id' => $userId]);
    }

    public function clearForUser(int $userId): int
    {
        $statement = $this->db()->prepare('DELETE FROM notifications WHERE user_id = :user_id');
        $statement->execute(['user_id' => $userId]);

        return $statement->rowCount();
    }

    public function sendFromAdmin(array $input): int
    {
        $title = trim((string) ($input['title'] ?? ''));
        $body = trim((string) ($input['body'] ?? ''));
        $url = trim((string) ($input['url'] ?? ''));
        $targetType = (string) ($input['target_type'] ?? 'all');
        $role = (string) ($input['role'] ?? '');
        $userId = (int) ($input['user_id'] ?? 0);

        if ($title === '' || $body === '') {
            throw new \InvalidArgumentException('Bildirim basligi ve mesaji zorunludur.');
        }

        $users = $this->notificationUsers($targetType, $role, $userId);
        if ($users === []) {
            throw new \InvalidArgumentException('Bildirim gonderilecek kullanici bulunamadi.');
        }

        $statement = $this->db()->prepare(
            'INSERT INTO notifications (user_id, type, title, body, data, read_at, created_at)
             VALUES (:user_id, "system", :title, :body, :data, NULL, NOW())'
        );
        $data = json_encode(['url' => $url !== '' ? $url : null, 'source' => 'zpanel'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

        foreach ($users as $id) {
            $statement->execute([
                'user_id' => $id,
                'title' => substr($title, 0, 190),
                'body' => $body,
                'data' => $data,
            ]);
        }

        return count($users);
    }

    private function notificationUsers(string $targetType, string $role, int $userId): array
    {
        if ($targetType === 'user') {
            if ($userId < 1) {
                return [];
            }

            $statement = $this->db()->prepare('SELECT id FROM users WHERE id = :id AND status = "active" LIMIT 1');
            $statement->execute(['id' => $userId]);
            $id = (int) ($statement->fetchColumn() ?: 0);

            return $id > 0 ? [$id] : [];
        }

        if ($targetType === 'role' && in_array($role, ['user', 'creator', 'moderator', 'admin'], true)) {
            $statement = $this->db()->prepare('SELECT id FROM users WHERE role = :role AND status = "active" ORDER BY id ASC');
            $statement->execute(['role' => $role]);

            return array_map('intval', $statement->fetchAll(PDO::FETCH_COLUMN));
        }

        $statement = $this->db()->query('SELECT id FROM users WHERE status = "active" ORDER BY id ASC');

        return array_map('intval', $statement->fetchAll(PDO::FETCH_COLUMN));
    }

    private function normalize(array $row): array
    {
        $data = [];
        if (!empty($row['data'])) {
            $decoded = json_decode((string) $row['data'], true);
            $data = is_array($decoded) ? $decoded : [];
        }

        $row['data'] = $data;
        $row['url'] = (string) ($data['url'] ?? '');
        $row['unread'] = empty($row['read_at']);

        return $row;
    }
}
