<?php
/**
 * Kontroler playlist
 */

require_once __DIR__ . '/BaseController.php';

class PlaylistController extends BaseController
{
    private Playlist $playlistModel;
    private Device $deviceModel;
    private AuditLog $auditLog;

    public function __construct()
    {
        parent::__construct();
        $this->playlistModel = new Playlist();
        $this->deviceModel = new Device();
        $this->auditLog = new AuditLog();
    }

    /**
     * Lista playlist
     */
    public function index(): void
    {
        $page = max(1, (int)get('page', 1));
        $search = get('search');
        $deviceId = get('device_id') ? (int)get('device_id') : null;
        $filterUserId = get('user_id'); // może być 'all' lub ID lub puste
        
        // Użytkownik model do pobierania listy userów
        $userModel = new User();
        
        // Jeśli wybrano urządzenie, automatycznie ustaw właściciela w filtrze user_id
        $filterDeviceName = null;
        $filterDeviceOwner = null;
        $filterDeviceOwnerId = null;
        
        if ($deviceId) {
            $device = $this->deviceModel->getById($deviceId);
            if (!$device || !$this->canAccess($device['owner_id'])) {
                $this->redirect('devices', 'danger', 'Brak dostępu do tego urządzenia.');
                return;
            }
            $filterDeviceName = $device['name'] ?: $device['mac'];
            $filterDeviceOwner = $device['username'];
            $filterDeviceOwnerId = $device['owner_id'];
            
            // Auto-ustaw user_id na właściciela urządzenia
            if (!$filterUserId || $filterUserId === 'all') {
                $filterUserId = (string)$device['owner_id'];
            }
        }
        
        $filterUserName = null;

        // Pobierz playlisty w zależności od roli i filtrów
        if ($this->auth->isAdmin()) {
            // Pobierz wszystkich użytkowników dla filtra
            $users = $userModel->getAll(1000);
            
            if ($deviceId) {
                // Filtrowanie po urządzeniu
                $total = $this->playlistModel->count($deviceId, null, $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getAll(ITEMS_PER_PAGE, $pagination['offset'], $deviceId, $search);
                $filterUserName = $filterDeviceOwner;
            } elseif ($filterUserId === 'all') {
                // Wszystkie playlisty
                $total = $this->playlistModel->count(null, null, $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getAll(ITEMS_PER_PAGE, $pagination['offset'], null, $search);
            } elseif ($filterUserId && is_numeric($filterUserId)) {
                // Filtrowanie po konkretnym użytkowniku
                $filterUserName = $this->getUsernameById((int)$filterUserId, $users);
                $total = $this->playlistModel->countByUserId((int)$filterUserId, $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getByUserId((int)$filterUserId, ITEMS_PER_PAGE, $pagination['offset'], $search);
            } else {
                // Domyślnie: tylko własne playlisty admina
                $total = $this->playlistModel->countByUserId($this->currentUser['id'], $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getByUserId($this->currentUser['id'], ITEMS_PER_PAGE, $pagination['offset'], $search);
            }
            
            // Pobierz urządzenia (wszystkie dla admina)
            $allDevices = $this->deviceModel->getAll(1000);
            
        } elseif ($this->auth->isReseller()) {
            $visibleUserIds = $userModel->getVisibleUserIds($this->currentUser);
            $users = $userModel->getByParentId($this->currentUser['id'], 1000);
            
            if ($deviceId) {
                $total = $this->playlistModel->count($deviceId, null, $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getAll(ITEMS_PER_PAGE, $pagination['offset'], $deviceId, $search);
                $filterUserName = $filterDeviceOwner;
            } elseif ($filterUserId === 'all') {
                // Wszystkie widoczne dla resellera
                $total = $this->playlistModel->countByUserIds($visibleUserIds, $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getByUserIds($visibleUserIds, ITEMS_PER_PAGE, $pagination['offset'], $search);
            } elseif ($filterUserId && is_numeric($filterUserId) && in_array((int)$filterUserId, $visibleUserIds)) {
                $filterUserName = $this->getUsernameById((int)$filterUserId, $users);
                $total = $this->playlistModel->countByUserId((int)$filterUserId, $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getByUserId((int)$filterUserId, ITEMS_PER_PAGE, $pagination['offset'], $search);
            } else {
                // Domyślnie: tylko własne
                $total = $this->playlistModel->countByUserId($this->currentUser['id'], $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getByUserId($this->currentUser['id'], ITEMS_PER_PAGE, $pagination['offset'], $search);
            }
            
            // Pobierz urządzenia (wszystkie widoczne dla resellera)
            $allDevices = $this->deviceModel->getByUserIds($visibleUserIds, 1000);
            
        } else {
            // Zwykły user - tylko własne
            $userId = $this->currentUser['id'];
            $users = [];
            
            if ($deviceId) {
                $total = $this->playlistModel->count($deviceId, null, $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getAll(ITEMS_PER_PAGE, $pagination['offset'], $deviceId, $search);
            } else {
                $total = $this->playlistModel->countByUserId($userId, $search);
                $pagination = paginate($total, ITEMS_PER_PAGE, $page);
                $playlists = $this->playlistModel->getByUserId($userId, ITEMS_PER_PAGE, $pagination['offset'], $search);
            }
            
            $allDevices = $this->deviceModel->getByUserId($this->currentUser['id'], 100);
        }

        // Filtruj urządzenia po wybranym użytkowniku
        $filteredDevices = [];
        if ($this->auth->isAdmin() || $this->auth->isReseller()) {
            if ($filterUserId === 'all') {
                // Wszystkie urządzenia
                $filteredDevices = $allDevices;
            } elseif ($filterUserId && is_numeric($filterUserId)) {
                // Tylko urządzenia wybranego użytkownika
                foreach ($allDevices as $d) {
                    if ($d['user_id'] == (int)$filterUserId) {
                        $filteredDevices[] = $d;
                    }
                }
            } else {
                // Domyślnie: tylko własne urządzenia (Moje)
                foreach ($allDevices as $d) {
                    if ($d['user_id'] == $this->currentUser['id']) {
                        $filteredDevices[] = $d;
                    }
                }
            }
        } else {
            $filteredDevices = $allDevices;
        }

        // Dekoduj config_json dla wyświetlenia
        foreach ($playlists as &$p) {
            $p['config'] = json_decode($p['config_json'], true);
        }

        $this->render('playlists/list.tpl', [
            'pageTitle' => 'Playlisty',
            'playlists' => $playlists,
            'pagination' => $pagination,
            'search' => $search,
            'filterDeviceId' => $deviceId,
            'filterDeviceName' => $filterDeviceName,
            'filterDeviceOwner' => $filterDeviceOwner,
            'filterUserId' => $filterUserId,
            'filterUserName' => $filterUserName,
            'devices' => $allDevices,
            'filteredDevices' => $filteredDevices,
            'users' => $users
        ]);
    }
    
    /**
     * Pomocnicza - pobierz username po ID
     */
    private function getUsernameById(int $userId, array $users): ?string
    {
        foreach ($users as $user) {
            if ($user['id'] == $userId) {
                return $user['username'];
            }
        }
        return null;
    }

    /**
     * Dodaj playlistę
     */
    public function add(): void
    {
        $deviceId = (int)get('device_id');
        
        // Sprawdź czy urządzenie istnieje i mamy dostęp
        if ($deviceId) {
            $device = $this->deviceModel->getById($deviceId);
            if (!$device || !$this->canAccess($device['owner_id'])) {
                $this->redirect('devices', 'danger', 'Brak dostępu do tego urządzenia.');
                return;
            }
        }

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            if (!$this->verifyCsrf()) {
                return;
            }

            $targetDeviceId = (int)post('device_id');
            
            // Weryfikacja dostępu do urządzenia
            $device = $this->deviceModel->getById($targetDeviceId);
            if (!$device || !$this->canAccess($device['owner_id'])) {
                if (isAjax()) {
                    $this->json(['success' => false, 'error' => 'Brak dostępu do urządzenia.']);
                } else {
                    $this->redirect('devices', 'danger', 'Brak dostępu do urządzenia.');
                }
                return;
            }

            $data = $this->getPlaylistDataFromPost();
            $data['device_id'] = $targetDeviceId;
            $data['update_date'] = time();

            $result = $this->playlistModel->create($data, $this->currentUser['id']);

            // Audit log
            if ($result['success'] && isset($result['id'])) {
                $this->auditLog->log(
                    AuditLog::ENTITY_PLAYLIST,
                    $result['id'],
                    AuditLog::ACTION_CREATE,
                    null,
                    $this->sanitizePlaylistDataForAudit($data)
                );
                
                // Dodaj notatkę jeśli podano
                $initialNote = trim(post('initial_note', ''));
                if ($initialNote) {
                    $notesModel = new EntityNotes();
                    $notesModel->add('playlist', $result['id'], $this->currentUser['id'], [
                        'title' => 'Uwagi przy tworzeniu',
                        'content' => $initialNote,
                        'color' => 'yellow'
                    ]);
                }
            }

            if (isAjax()) {
                $this->json($result);
            } else {
                if ($result['success']) {
                    $this->redirect('playlists?device_id=' . $targetDeviceId, 'success', 'Playlista została dodana.');
                } else {
                    $devices = $this->getAccessibleDevices();
                    $this->render('playlists/form.tpl', [
                        'pageTitle' => 'Dodaj playlistę',
                        'error' => $result['error'],
                        'data' => $data,
                        'isEdit' => false,
                        'devices' => $devices
                    ]);
                }
            }
            return;
        }

        $devices = $this->getAccessibleDevices();

        $this->render('playlists/form.tpl', [
            'pageTitle' => 'Dodaj playlistę',
            'isEdit' => false,
            'data' => ['device_id' => $deviceId, 'type' => 'xtream'],
            'devices' => $devices
        ]);
    }

    /**
     * Edytuj playlistę
     */
    public function edit(): void
    {
        $id = (int)get('id');
        $playlist = $this->playlistModel->getById($id);

        if (!$playlist) {
            $this->redirect('playlists', 'danger', 'Playlista nie istnieje.');
            return;
        }

        // Sprawdź uprawnienia
        if (!$this->canAccess($playlist['owner_id'])) {
            $this->redirect('playlists', 'danger', 'Brak dostępu do tej playlisty.');
            return;
        }

        // Dekoduj config
        $playlist['config'] = json_decode($playlist['config_json'], true);

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            if (!$this->verifyCsrf()) {
                return;
            }

            $data = $this->getPlaylistDataFromPost();
            
            // Aktualizuj update_date jeśli zaznaczono
            if (post('update_timestamp')) {
                $data['update_date'] = time();
            }

            $result = $this->playlistModel->update($id, $data, $this->currentUser['id']);

            // Audit log
            if ($result['success']) {
                $oldData = array_merge(
                    ['name' => $playlist['name'], 'type' => $playlist['type'], 'device_id' => $playlist['device_id'], 
                     'sort_order' => $playlist['sort_order'], 'is_active' => $playlist['is_active']],
                    $playlist['config'] ?? []
                );
                $this->auditLog->log(
                    AuditLog::ENTITY_PLAYLIST,
                    $id,
                    AuditLog::ACTION_UPDATE,
                    $this->sanitizePlaylistDataForAudit($oldData),
                    $this->sanitizePlaylistDataForAudit($data)
                );
            }

            if (isAjax()) {
                $this->json($result);
            } else {
                if ($result['success']) {
                    $this->redirect('playlists?device_id=' . $playlist['device_id'], 'success', 'Playlista została zaktualizowana.');
                } else {
                    $devices = $this->getAccessibleDevices();
                    $this->render('playlists/form.tpl', [
                        'pageTitle' => 'Edytuj playlistę',
                        'error' => $result['error'],
                        'data' => array_merge($playlist, $playlist['config'], $data),
                        'isEdit' => true,
                        'devices' => $devices
                    ]);
                }
            }
            return;
        }

        $devices = $this->getAccessibleDevices();

        // Połącz dane playlisty z config
        $formData = array_merge($playlist, $playlist['config']);

        $this->render('playlists/form.tpl', [
            'pageTitle' => 'Edytuj playlistę',
            'isEdit' => true,
            'data' => $formData,
            'devices' => $devices
        ]);
    }

    /**
     * Usuń playlistę
     */
    public function delete(): void
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            $this->redirect('playlists');
            return;
        }

        if (!$this->verifyCsrf()) {
            return;
        }

        $id = (int)post('id');
        $playlist = $this->playlistModel->getById($id);

        if (!$playlist) {
            if (isAjax()) {
                $this->json(['success' => false, 'error' => 'Playlista nie istnieje.']);
            } else {
                $this->redirect('playlists', 'danger', 'Playlista nie istnieje.');
            }
            return;
        }

        // Sprawdź uprawnienia
        if (!$this->canAccess($playlist['owner_id'])) {
            if (isAjax()) {
                $this->json(['success' => false, 'error' => 'Brak dostępu.']);
            } else {
                $this->redirect('playlists', 'danger', 'Brak dostępu.');
            }
            return;
        }

        $deviceId = $playlist['device_id'];
        
        // Dekoduj config przed usunięciem dla audit logu
        $playlist['config'] = json_decode($playlist['config_json'] ?? '{}', true) ?: [];
        
        $result = $this->playlistModel->delete($id, $this->currentUser['id']);

        // Audit log
        if ($result['success']) {
            $oldData = array_merge(
                ['name' => $playlist['name'], 'type' => $playlist['type'], 'device_id' => $playlist['device_id'],
                 'sort_order' => $playlist['sort_order'], 'is_active' => $playlist['is_active'],
                 'update_date' => $playlist['update_date'] ?? null],
                $playlist['config']
            );
            $this->auditLog->log(
                AuditLog::ENTITY_PLAYLIST,
                $id,
                AuditLog::ACTION_DELETE,
                $this->sanitizePlaylistDataForAudit($oldData),
                null
            );
        }

        if (isAjax()) {
            $this->json($result);
        } else {
            if ($result['success']) {
                $this->redirect('playlists?device_id=' . $deviceId, 'success', 'Playlista została usunięta.');
            } else {
                $this->redirect('playlists', 'danger', $result['error']);
            }
        }
    }

    /**
     * Przełącz status aktywności playlisty
     */
    public function toggleActive(): void
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            $this->redirect('playlists');
            return;
        }

        if (!$this->verifyCsrf()) {
            return;
        }

        $id = (int)post('id');
        $playlist = $this->playlistModel->getById($id);

        if (!$playlist) {
            if (isAjax()) {
                $this->json(['success' => false, 'error' => 'Playlista nie istnieje.']);
            } else {
                $this->redirect('playlists', 'danger', 'Playlista nie istnieje.');
            }
            return;
        }

        // Sprawdź uprawnienia
        if (!$this->canAccess($playlist['owner_id'])) {
            if (isAjax()) {
                $this->json(['success' => false, 'error' => 'Brak dostępu.']);
            } else {
                $this->redirect('playlists', 'danger', 'Brak dostępu.');
            }
            return;
        }

        $result = $this->playlistModel->toggleActive($id, $this->currentUser['id']);

        // Audit log
        if ($result['success']) {
            $this->auditLog->log(
                AuditLog::ENTITY_PLAYLIST,
                $id,
                $result['is_active'] ? AuditLog::ACTION_ACTIVATE : AuditLog::ACTION_DEACTIVATE,
                ['is_active' => !$result['is_active']],
                ['is_active' => $result['is_active'], 'name' => $playlist['name']]
            );
        }

        if (isAjax()) {
            $this->json($result);
        } else {
            if ($result['success']) {
                $status = $result['is_active'] ? 'aktywowana' : 'dezaktywowana';
                $this->redirect('playlists?device_id=' . $playlist['device_id'], 'success', "Playlista została {$status}.");
            } else {
                $this->redirect('playlists', 'danger', $result['error']);
            }
        }
    }

    /**
     * Pobierz dane playlisty z POST
     */
    private function getPlaylistDataFromPost(): array
    {
        $data = [
            'name' => post('name'),
            'type' => post('type'),
            'sort_order' => (int)post('sort_order', 0),
            'is_active' => post('is_active') !== null
        ];

        // Pola zależne od typu
        switch (post('type')) {
            case 'xtream':
                $data['host'] = post('host');
                $data['username'] = post('username');
                $data['password'] = post('password');
                break;

            case 'm3u':
                $data['url'] = post('url');
                $data['epg_link'] = post('m3u_epg_link');
                break;

            case 'stalker':
                $data['server_url'] = post('server_url');
                $data['referrer_url'] = post('referrer_url');
                $data['mac_address'] = post('mac_address');
                $data['serial_number'] = post('serial_number');
                $data['device_id'] = post('stalker_device_id');
                $data['device_id2'] = post('device_id2');
                $data['signature'] = post('signature');
                $data['epg_link'] = post('stalker_epg_link');
                break;
        }

        return $data;
    }

    /**
     * Pobierz urządzenia dostępne dla użytkownika
     */
    private function getAccessibleDevices(): array
    {
        if ($this->auth->isAdmin()) {
            return $this->deviceModel->getAll(100);
        }
        return $this->deviceModel->getByUserId($this->currentUser['id'], 100);
    }

    /**
     * Sklonuj playlistę do innego urządzenia
     */
    public function clone(): void
    {
        $id = (int)get('id');
        $playlist = $this->playlistModel->getById($id);

        if (!$playlist) {
            $this->redirect('playlists', 'danger', 'Playlista nie istnieje.');
            return;
        }

        // Sprawdź uprawnienia do źródłowej playlisty
        if (!$this->canAccess($playlist['owner_id'])) {
            $this->redirect('playlists', 'danger', 'Brak dostępu do tej playlisty.');
            return;
        }

        // Dekoduj config
        $config = json_decode($playlist['config_json'], true);

        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            if (!$this->verifyCsrf()) {
                return;
            }

            $targetDeviceId = (int)post('device_id');

            // Sprawdź dostęp do urządzenia docelowego
            $targetDevice = $this->deviceModel->getById($targetDeviceId);
            if (!$targetDevice || !$this->canAccess($targetDevice['owner_id'])) {
                $this->redirect("playlists/clone?id={$id}", 'danger', 'Brak dostępu do urządzenia docelowego.');
                return;
            }

            // Przygotuj dane do sklonowania
            $cloneData = [
                'device_id' => $targetDeviceId,
                'type' => $playlist['type'],
                'name' => $playlist['name'],
                'sort_order' => $playlist['sort_order'],
                'is_active' => $playlist['is_active'],
                'update_date' => time()
            ];

            // Dodaj konfigurację - uwaga na stalker_device_id
            if ($playlist['type'] === 'stalker' && isset($config['device_id'])) {
                $cloneData['stalker_device_id'] = $config['device_id'];
                unset($config['device_id']);
            }
            
            $cloneData = array_merge($cloneData, $config);

            $result = $this->playlistModel->create($cloneData, $this->currentUser['id']);

            if ($result['success']) {
                $this->logger->log(
                    'playlist_cloned',
                    "Sklonowano playlistę \"{$playlist['name']}\" z urządzenia {$playlist['device_id']} do {$targetDeviceId}",
                    $this->currentUser['id']
                );

                // Audit log
                $this->auditLog->log(
                    AuditLog::ENTITY_PLAYLIST,
                    $result['id'],
                    AuditLog::ACTION_CLONE,
                    ['source_id' => $id, 'source_name' => $playlist['name'], 'source_device_id' => $playlist['device_id']],
                    $this->sanitizePlaylistDataForAudit($cloneData)
                );

                $message = "Playlista została sklonowana.";
                if (!empty($result['name_changed'])) {
                    $message .= " Nazwa zmieniona na: \"{$result['name']}\"";
                }

                $this->redirect("playlists?device_id={$targetDeviceId}", 'success', $message);
            } else {
                $devices = $this->getAccessibleDevices();
                $this->render('playlists/clone.tpl', [
                    'pageTitle' => 'Sklonuj playlistę',
                    'playlist' => $playlist,
                    'config' => $config,
                    'devices' => $devices,
                    'error' => $result['error']
                ]);
            }
            return;
        }

        $devices = $this->getAccessibleDevices();

        $this->render('playlists/clone.tpl', [
            'pageTitle' => 'Sklonuj playlistę',
            'playlist' => $playlist,
            'config' => $config,
            'devices' => $devices
        ]);
    }

    /**
     * Masowe akcje na playlistach
     */
    public function bulk(): void
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            $this->redirect('playlists');
            return;
        }

        if (!$this->verifyCsrf()) {
            return;
        }

        $action = post('action');
        $idsString = post('ids');
        
        if (empty($idsString)) {
            $this->redirect('playlists', 'danger', 'Nie wybrano żadnych playlist.');
            return;
        }

        $ids = array_filter(array_map('intval', explode(',', $idsString)));
        
        if (empty($ids)) {
            $this->redirect('playlists', 'danger', 'Nie wybrano żadnych playlist.');
            return;
        }

        // Filtruj tylko playlisty do których mamy dostęp
        $accessibleIds = $this->filterAccessiblePlaylists($ids);
        
        if (empty($accessibleIds)) {
            $this->redirect('playlists', 'danger', 'Brak dostępu do wybranych playlist.');
            return;
        }

        $count = count($accessibleIds);
        $result = ['success' => false, 'message' => ''];

        switch ($action) {
            case 'delete':
                $result = $this->bulkDelete($accessibleIds);
                break;
                
            case 'activate':
                $result = $this->bulkSetActive($accessibleIds, true);
                break;
                
            case 'deactivate':
                $result = $this->bulkSetActive($accessibleIds, false);
                break;
                
            case 'touch':
                $result = $this->bulkTouch($accessibleIds);
                break;
                
            case 'copy':
                $targetDeviceId = (int)post('target_device_id');
                $result = $this->bulkTransfer($accessibleIds, $targetDeviceId, false);
                break;
                
            case 'move':
                $targetDeviceId = (int)post('target_device_id');
                $result = $this->bulkTransfer($accessibleIds, $targetDeviceId, true);
                break;
                
            default:
                $this->redirect('playlists', 'danger', 'Nieznana akcja.');
                return;
        }

        $alertType = $result['success'] ? 'success' : 'danger';
        $this->redirect('playlists', $alertType, $result['message']);
    }

    /**
     * Filtruj playlisty do których użytkownik ma dostęp
     */
    private function filterAccessiblePlaylists(array $ids): array
    {
        $accessible = [];
        
        foreach ($ids as $id) {
            $playlist = $this->playlistModel->getById($id);
            if ($playlist && $this->canAccess($playlist['owner_id'])) {
                $accessible[] = $id;
            }
        }
        
        return $accessible;
    }

    /**
     * Masowe usunięcie
     */
    private function bulkDelete(array $ids): array
    {
        $deleted = 0;
        
        foreach ($ids as $id) {
            $playlist = $this->playlistModel->getById($id);
            $result = $this->playlistModel->delete($id, $this->currentUser['id']);
            if ($result['success']) {
                $deleted++;
                // Audit log dla każdego usunięcia
                $this->auditLog->log(
                    AuditLog::ENTITY_PLAYLIST,
                    $id,
                    AuditLog::ACTION_DELETE,
                    ['name' => $playlist['name'] ?? 'unknown', 'bulk' => true],
                    null
                );
            }
        }

        $this->logger->log('bulk_playlist_delete', "Masowo usunięto {$deleted} playlist", $this->currentUser['id']);

        return [
            'success' => $deleted > 0,
            'message' => "Usunięto {$deleted} z " . count($ids) . " playlist."
        ];
    }

    /**
     * Masowa zmiana statusu aktywności
     */
    private function bulkSetActive(array $ids, bool $active): array
    {
        $updated = 0;
        
        foreach ($ids as $id) {
            $playlist = $this->playlistModel->getById($id);
            $result = $this->playlistModel->update($id, ['is_active' => $active], $this->currentUser['id']);
            if ($result['success']) {
                $updated++;
                // Audit log
                $this->auditLog->log(
                    AuditLog::ENTITY_PLAYLIST,
                    $id,
                    $active ? AuditLog::ACTION_ACTIVATE : AuditLog::ACTION_DEACTIVATE,
                    ['is_active' => !$active, 'bulk' => true],
                    ['is_active' => $active, 'name' => $playlist['name'] ?? 'unknown']
                );
            }
        }

        $action = $active ? 'aktywowano' : 'dezaktywowano';
        $this->logger->log('bulk_playlist_' . ($active ? 'activate' : 'deactivate'), 
            "Masowo {$action} {$updated} playlist", $this->currentUser['id']);

        return [
            'success' => $updated > 0,
            'message' => ucfirst($action) . " {$updated} z " . count($ids) . " playlist."
        ];
    }

    /**
     * Masowe odświeżenie update_date
     */
    private function bulkTouch(array $ids): array
    {
        $touched = 0;
        
        foreach ($ids as $id) {
            if ($this->playlistModel->touch($id, $this->currentUser['id'])) {
                $touched++;
            }
        }

        $this->logger->log('bulk_playlist_touch', "Masowo odświeżono update_date dla {$touched} playlist", $this->currentUser['id']);

        return [
            'success' => $touched > 0,
            'message' => "Odświeżono update_date dla {$touched} z " . count($ids) . " playlist."
        ];
    }

    /**
     * Masowe kopiowanie/przenoszenie
     */
    private function bulkTransfer(array $ids, int $targetDeviceId, bool $deleteSource): array
    {
        // Sprawdź dostęp do urządzenia docelowego
        $targetDevice = $this->deviceModel->getById($targetDeviceId);
        if (!$targetDevice || !$this->canAccess($targetDevice['owner_id'])) {
            return ['success' => false, 'message' => 'Brak dostępu do urządzenia docelowego.'];
        }

        $transferred = 0;
        $skipped = 0;
        $action = $deleteSource ? 'przeniesiono' : 'skopiowano';

        foreach ($ids as $id) {
            $playlist = $this->playlistModel->getById($id);
            if (!$playlist) {
                $skipped++;
                continue;
            }

            // Nie kopiuj/przenoś do tego samego urządzenia
            if ($playlist['device_id'] == $targetDeviceId) {
                $skipped++;
                continue;
            }

            $config = json_decode($playlist['config_json'], true);

            // Przygotuj dane
            $cloneData = [
                'device_id' => $targetDeviceId,
                'type' => $playlist['type'],
                'name' => $playlist['name'],
                'sort_order' => $playlist['sort_order'],
                'is_active' => $playlist['is_active'],
                'update_date' => time()
            ];

            // Obsłuż stalker_device_id
            if ($playlist['type'] === 'stalker' && isset($config['device_id'])) {
                $cloneData['stalker_device_id'] = $config['device_id'];
                unset($config['device_id']);
            }

            $cloneData = array_merge($cloneData, $config);

            $result = $this->playlistModel->create($cloneData, $this->currentUser['id']);

            if ($result['success']) {
                $transferred++;
                
                // Audit log dla kopiowania/przenoszenia
                $this->auditLog->log(
                    AuditLog::ENTITY_PLAYLIST,
                    $result['id'],
                    $deleteSource ? 'move' : 'copy',
                    ['source_id' => $id, 'source_device_id' => $playlist['device_id'], 'bulk' => true],
                    ['name' => $playlist['name'], 'target_device_id' => $targetDeviceId]
                );
                
                // Usuń źródło jeśli to przenoszenie
                if ($deleteSource) {
                    $this->playlistModel->delete($id, $this->currentUser['id']);
                }
            } else {
                $skipped++;
            }
        }

        $logAction = $deleteSource ? 'bulk_playlist_move' : 'bulk_playlist_copy';
        $this->logger->log($logAction, 
            "Masowo {$action} {$transferred} playlist do urządzenia {$targetDevice['mac']}", 
            $this->currentUser['id']);

        $message = ucfirst($action) . " {$transferred} z " . count($ids) . " playlist.";
        if ($skipped > 0) {
            $message .= " Pominięto: {$skipped} (duplikaty lub błędy).";
        }

        return [
            'success' => $transferred > 0,
            'message' => $message
        ];
    }
    
    /**
     * Przygotuj dane playlisty do audit logu (usuń puste wartości)
     */
    private function sanitizePlaylistDataForAudit(array $data): array
    {
        // Usuń puste/null wartości
        $filtered = array_filter($data, function($value) {
            return $value !== null && $value !== '';
        });
        
        return $filtered;
    }
}
