package com.neuroair;

import com.dseelab.pov.socket.SocketHelper;
import com.dseelab.pov.model.FileItem;
import com.dseelab.pov.model.VideoItem;
import com.dseelab.pov.PovException;
import com.dseelab.pov.ffmpeg.FFmpegUtils;
import com.dseelab.pov.model.DeviceState;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Objects;

import com.dseelab.pov.socket.SocketClient;

public class CommandHandler {
    public static SocketHelper mSocketHelper = new SocketHelper();    
    public WebSocketSession session;
    private boolean looping = false;
    private int repeat = 3;
    
    public CommandHandler(WebSocketSession session) {
        this.session = session;
        initializeConnection();
    }

    /**
     * Инициализирует соединение, устанавливая значения для цикличности и повтора,
     * и затем пытается подключиться к устройству.
     */
    private void initializeConnection() {
        connectToDevice();
    }

    /**
     * Пытается подключиться к устройству.
     *
     * @return true, если подключение успешно, иначе false.
     */
    public boolean connectToDevice() {
        // System.out.println("Attempting to connect...");
        boolean isSuccess = mSocketHelper.connect("DseeLab_60H_60002999");
        // boolean isSuccess = mSocketHelper.connect("192.168.43.1", "36265545", "60002999");
        System.out.println("Результат подключения：" + isSuccess);
        if (isSuccess) {
            fullInformationAboutDevice();  // Получение полной информации об устройстве
        }
        return isSuccess;
    }

    private void fullInformationAboutDevice() {
        try {
            // Получение состояния устройства
            readDeviceState();
            Thread.sleep(500);
    
            // // Получение текущего плейлиста
            // readCurrentPlayList();
            // Thread.sleep(500);
    
            // // Получение текущей позиции видео
            // readCurrentPosition();
            // Thread.sleep(500);
    
            // // Получение списка всех плейлистов
            // readAllPlaylists();
            // Thread.sleep(500);
    
            // // Чтение списка файлов
            // readFileList();
            // Thread.sleep(500);
    
            // // Отправка списка плейлистов
            // sendPlayList();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // Восстановление прерванного статуса
            System.err.println("Операция была прервана: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    
    /**
     * Метод выполнения команды.
     * Принимает команду и выполняет соответствующее действие в зависимости от метода команды.
     *
     * @param command Команда для выполнения.
     */
    public void execute(Command command) {
        
        try {
            // Добавляем задержку перед проверкой подключения
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // Восстановление прерванного статуса
            System.err.println("Операция была прервана: " + e.getMessage());
            e.printStackTrace();
        }
        
        if (!mSocketHelper.isConnect()) {
            System.out.println("Reconnecting...");
            connectToDevice();
        }
    
        ObjectMapper mapper = new ObjectMapper();
    
        switch (command.getMethod()) {
            case "start":
                System.out.println("команда: start");
                openDevice();
                break;
            case "stop":
                System.out.println("команда: stop");
                closeDevice();
                break;
            case "setLight":
                System.out.println("команда: setLight");
                int bright = Integer.parseInt(command.getArgs());
                boolean lightResult = mSocketHelper.setLight(bright);
                System.out.println("setLight result：" + lightResult);
                break;
            case "setAngle":
                // System.out.println("command: setAngle");
                int angle = Integer.parseInt(command.getArgs());
                boolean angleResult = mSocketHelper.setAngle(angle);
                System.out.println("setAngle result：" + angleResult);
                break;
            case "openDevice":
                System.out.println("команда: openDevice");
                openDevice();
                break;
            case "closeDevice":
                System.out.println("команда: closeDevice");
                closeDevice();
                break;
            case "pausePlayer":
                System.out.println("команда: pausePlayer");
                boolean pauseResult = mSocketHelper.pausePlayer();
                System.out.println("pausePlayer result：" + pauseResult);
                break;
            case "resumePlayer":
                System.out.println("команда: resumePlayer");
                boolean resumeResult = mSocketHelper.resumePlayer();
                System.out.println("Результат запуска плеера：" + resumeResult);
                break;
            case "playVideo":
                System.out.println("команда: playVideo");
                int videoIndex = Integer.parseInt(command.getArgs());
                playVideoByIndex(videoIndex);
                break;
            case "readDeviceState":
                System.out.println("команда: readDeviceState");
                readDeviceState();
                break;
            case "readFileList":
                System.out.println("команда: readFileList");
                readFileList();
                break;
            case "readPlayList":
                System.out.println("команда: readPlayList");
                sendPlayList();
                break;
            case "setLooping":
                System.out.println("команда: setLooping");
                setLooping(command.getArgs());
                break;
            case "setRepeat":
                System.out.println("команда: setRepeat");
                setRepeat(command.getArgs());
                break;
            case "uploadFile":
                System.out.println("команда: uploadFile");
                uploadFile(command.getArgs());
                break;
            case "createPlaylist":
                System.out.println("команда: createPlaylist");
                createPlaylist(command.getArgs());
                break;
            case "addVideoToPlaylist":
                System.out.println("команда: addVideoToPlaylist");
                try {
                    JSONObject jsonArgs = new JSONObject(command.getArgs());
                    String playlistName = jsonArgs.getString("playlistName");
                    String videoFileName = jsonArgs.getString("videoFileName");
                    addVideoToPlaylist(playlistName, videoFileName);
                } catch (JSONException e) {
                    e.printStackTrace();
                    System.out.println("Не удалось разобрать аргументы для addVideoToPlaylist");
                }
                break;
            case "updateFileList":
                System.out.println("команда: updateFileList");
                updateFileList(command.getArgs());
                break;
            case "clearAllVideos":
                clearAllVideos();
                break;
            case "deleteVideo":
                deleteVideo(command.getArgs());
                break;
            case "usePlayList":
                usePlayList(command.getArgs());
                break;
            case "readPlayListItems":
                System.out.println("команда: readPlayListItems");
                int playlistIndex = Integer.parseInt(command.getArgs());
                readPlayListItems(playlistIndex);
                break;
            case "playVideoFromPlaylist":
                // System.out.println("command: playVideoFromPlaylist");
                try {
                    JSONObject args = new JSONObject(command.getArgs());
                    int playlistIdx = args.getInt("playlistIndex");
                    int videoIdx = args.getInt("videoIndex");
                    playVideoFromPlaylist(playlistIdx, videoIdx);
                } catch (JSONException e) {
                    e.printStackTrace();
                    System.out.println("Failed to parse arguments for playVideoFromPlaylist");
                }
                break;
            case "readCurrentPlayList":
                System.out.println("команда: readCurrentPlayList");
                readCurrentPlayList();
                break;
            case "readCurrentVideo":
                System.out.println("команда: readCurrentVideo");
                int currentVideoIndex = mSocketHelper.readCurrentPosition();
                String currentVideoName = mSocketHelper.readCurrentName();
                sendMessage("currentVideo:" + currentVideoIndex + ";" + currentVideoName);
                break;  
            case "setMotorSpeed":
                int speed = Integer.parseInt(command.getArgs());
                setMotorSpeed(speed);
                break;
            case "restartSystem":
                System.out.println("команда: restartSystem");
                restartSystem();
                break;
            case "setSwitchInterval":
                // System.out.println("команда: setSwitchInterval");
                try {
                    float intervalFloat = Float.parseFloat(command.getArgs());
                    int intervalInMillis = Math.round(intervalFloat); 
                    setSwitchInterval(intervalInMillis);
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                    System.out.println("Не удалось разобрать значение интервала: " + command.getArgs());
                }
                break;
            case "readAllPlaylists":
                System.out.println("команда: readAllPlaylists");
                readAllPlaylists();
                break;
            case "readCurrentPosition":
                System.out.println("команда: readCurrentPosition");
                readCurrentPosition();
                break;
        
        }
        // fullInformationAboutDevice();  // 
        // closeConnection();
    }
    

    
    private void readDeviceState() {
        DeviceState deviceState = mSocketHelper.readDeviceState();
        try {
            String jsonDeviceState = new ObjectMapper().writeValueAsString(deviceState);
            sendMessage("deviceState:" + jsonDeviceState);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            sendMessage("deviceState:{}");
        }
    }

    private void readCurrentPlayList() {
        int currentPlaylistIndex = mSocketHelper.readCurrentListPosition();
        sendMessage("currentPlaylist:" + currentPlaylistIndex);
    }

    private void readCurrentPosition() {
        int currentVideoIndex = mSocketHelper.readCurrentPosition();
        String currentVideoName = mSocketHelper.readCurrentName();
        sendMessage("currentVideo:" + currentVideoIndex + ";" + currentVideoName);
    }

    public void readAllPlaylists() {
        List<String> playListNames = mSocketHelper.readFileList();
        if (playListNames == null) {
            System.out.println("Не удалось получить список плейлистов.");
            return;  // Логически корректное завершение метода, если нет плейлистов
        }
    
        JSONObject allPlaylists = new JSONObject();
        for (int i = 0; i < playListNames.size(); i++) {
            List<FileItem> playlistItems = mSocketHelper.readPlayList(i);
    
            if (playlistItems == null) {
                System.out.println("Не удалось получить элементы плейлиста для индекса: " + i);
                continue; // Пропускаем текущую итерацию, если плейлист пуст или недоступен
            }
    
            JSONArray videoArray = new JSONArray();
            for (FileItem item : playlistItems) {
                videoArray.put(item.getFileName()); // Только имена файлов
            }
            allPlaylists.put(String.valueOf(i), videoArray);
        }
    
        sendMessage(allPlaylists.toString());
    }
    

    /**
     * Перезагрузка системы.
     * Закрывает текущее соединение и открывает его снова.
     */
    public void restartSystem() {
        System.out.println("Перезагрузка системы...");
        closeDevice();
        closeConnection();
        try {
            Thread.sleep(500); 
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // Восстанавливаем статус прерывания
            System.out.println("Поток был прерван. Завершение выполнения метода.");
            return;
        }
        connectToDevice();
        System.out.println("Система перезагружена.");
    }

    /**
     * Читает текущий список файлов и отправляет их через WebSocket.
     */
    private void readFileList() {
        int cp = mSocketHelper.readCurrentPosition();
        System.out.println("cp:" + cp);
        String curn = mSocketHelper.readCurrentName();
        System.out.println("curn:" + curn);
        List<VideoItem> videoList = mSocketHelper.readVideoList(); 
        if (videoList == null || videoList.isEmpty()) {
            System.out.println("Видео список пуст или не был получен.");
            sendMessage("fileList:"); // Отправляем пустой список
            return;
        }
        // Проверяем, что данные верны
        System.out.println("Список необработанных видеофайлов, полученных с устройства: " + videoList);
    
        // Форматируем список видео
        StringBuilder videoListString = new StringBuilder();
        for (VideoItem videoItem : videoList) {
            String fileName = videoItem.getFileName() != null ? videoItem.getFileName() : "";
            String fileSize = videoItem.getFileSize() != null ? videoItem.getFileSize() : "";
            String period = videoItem.getPeriod() != null ? videoItem.getPeriod() : "";
    
            // Добавляем значения в строку
            videoListString.append(fileName).append(";").append(fileSize).append(";").append(period).append(";");
        }
    
        // Удаляем последний символ ";", если есть
        if (videoListString.length() > 0 && videoListString.charAt(videoListString.length() - 1) == ';') {
            videoListString.setLength(videoListString.length() - 1);
        }
    
        // Заменяем все вхождения "null" на пустые строки
        String formattedVideoList = videoListString.toString().replace("null", "");
    
        System.out.println("Formatted video list: " + formattedVideoList);
        sendMessage("fileList:" + formattedVideoList);
    }
    
    /**
     * Метод отправки плейлиста.
     * Читает плейлист с устройства и отправляет его через WebSocket.
     */
    private void sendPlayList() {
        List<String> playList = mSocketHelper.readFileList();
        
        // Проверяем, что список плейлистов не null и не пустой
        if (playList != null && !playList.isEmpty()) {
            System.out.println("Длина плейлиста: " + playList.size());
            sendMessage("playList:" + String.join(";", playList));
        } else if (playList == null) {
            System.out.println("Не удалось получить список плейлистов. Список равен null.");
            sendMessage("playList:");  // Отправляем пустое сообщение, чтобы клиент знал, что плейлисты отсутствуют
        } else {
            System.out.println("Список плейлистов пуст.");
            sendMessage("playList:");  // Отправляем пустое сообщение
        }
    }
    

    /**
     * Вспомогательный класс для парсинга аргументов команды.
     * Содержит индексы плейлиста и видео.
     */
    public static class PlaylistCommandArgs {
        private int playlistIndex;
        private int videoIndex;

        public int getPlaylistIndex() {
            return playlistIndex;
        }

        public void setPlaylistIndex(int playlistIndex) {
            this.playlistIndex = playlistIndex;
        }

        public int getVideoIndex() {
            return videoIndex;
        }

        public void setVideoIndex(int videoIndex) {
            this.videoIndex = videoIndex;
        }
    }

    public void setMotorSpeed(int speed) {
        boolean result = mSocketHelper.setMotorSpeed(speed);
        if (result) {
            System.out.println("Скорость вращения двигателя установлена на: " + speed);
        } else {
            System.out.println("Не удалось установить скорость вращения двигателя: " + speed);
        }
    }
    
    public void setSwitchInterval(int interval) {
        boolean result = mSocketHelper.setSwitchInterval(interval);
        if (result) {
            System.out.println("Установлен интервал переключения: " + interval);
        } else {
            System.out.println("Не удалось установить интервал переключения: " + interval);
        }
    }
       

    /**
     * Метод для удаления видео.
     * Принимает строку аргументов, парсит индекс видео и вызывает метод удаления видео.
     *
     * @param args Аргументы команды в виде строки.
     */
    private void deleteVideo(String args) {
        try {
            int videoIndex = Integer.parseInt(args);
            boolean result = mSocketHelper.deleteVideo(videoIndex);
            if (result) {
                System.out.println("Видео успешно удалено в индексе: " + videoIndex);
            } else {
                System.out.println("Не удалось удалить видео по индексу: " + videoIndex);
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
            System.out.println("Не удалось разобрать аргументы для deleteVideo");
        }
    }

    /**
     * Метод для очистки всех видео.
     * Вызывает метод очистки всех видео из SocketHelper и выводит результат в лог.
     */
    private void clearAllVideos() {
        boolean result = mSocketHelper.clearAllVideo();
        if (result) {
            System.out.println("Все видео успешно очищены");
        } else {
            System.out.println("Не удалось очистить все видео");
        }
    }

    /**
     * Метод для настройки зацикливания видео.
     * Парсит аргументы команды и устанавливает параметр зацикливания.
     *
     * @param args Аргументы команды в виде строки.
     */
    private void setLooping(String args) {
        try {
            boolean looping = Boolean.parseBoolean(args);
            mSocketHelper.setLooping(looping);  // Устанавливаем зацикливание

            // Логирование результата
            System.out.println("Зацикливание установлено на: " + looping);
            System.out.println("Вывод с устройства, подтверждающий статус зацикливания:" + mSocketHelper.isLooping());
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Не удалось разобрать аргументы для setLooping");
        }
    }

    /**
     * Метод для настройки количества повторов видео.
     * Парсит аргументы команды и устанавливает количество повторов.
     *
     * @param args Аргументы команды в виде строки.
     */
    private void setRepeat(String args) {
        try {
            int repeat = Integer.parseInt(args);
            mSocketHelper.setRepeat(repeat);

            // Логирование результата
            System.out.println("Повторение установле на: " + repeat);
        } catch (NumberFormatException e) {
            e.printStackTrace();
            System.out.println("Не удалось разобрать аргументы для setRepeat");
        }
    }

    /**
     * Метод для обновления списка файлов в плейлисте.
     * Парсит JSON строку с аргументами, создает список FileItem и обновляет его через SocketHelper.
     *
     * @param jsonArgs JSON строка с аргументами, содержащая имя плейлиста и список видео.
     */
    public void updateFileList(String jsonArgs) {
        try {
            // Разбор JSON строки с аргументами
            JSONObject args = new JSONObject(jsonArgs);
            String playlistName = args.getString("playlistName");
            JSONArray videoArray = args.getJSONArray("videoList");

            // Создание списка FileItem на основе полученных данных
            List<FileItem> videoList = new ArrayList<>();
            for (int i = 0; i < videoArray.length(); i++) {
                JSONObject videoObj = videoArray.getJSONObject(i);
                FileItem fileItem = new FileItem();
                fileItem.setFileName(videoObj.getString("fileName"));
                fileItem.setFileSize(videoObj.getString("fileSize"));
                fileItem.setRepeatCount(videoObj.getString("repeatCount"));
                videoList.add(fileItem);
            }

            // Обновление списка файлов через SocketHelper
            System.out.println("Обновление списка файлов для списка воспроизведения: " + playlistName);
            boolean result = mSocketHelper.updateFileList(playlistName, videoList);
            if (result) {
                System.out.println("Список файлов успешно обновлен для списка воспроизведения: " + playlistName);
                sendPlayList(); // Обновление списка плейлистов на клиенте
            } else {
                System.out.println("Не удалось обновить список файлов для списка воспроизведения: " + playlistName);
            }
        } catch (JSONException e) {
            e.printStackTrace();
            System.out.println("Не удалось разобрать аргументы для updateFileList");
        }
    }

    /**
     * Метод для создания нового плейлиста.
     * Создает пустой плейлист и обновляет его через SocketHelper.
     *
     * @param playlistName Имя нового плейлиста.
     */
    private void createPlaylist(String playlistName) {
        if (playlistName == null || playlistName.trim().isEmpty()) {
            System.out.println("Имя плейлиста не может быть нулевым или пустым.");
            return;
        }

        // Создание пустого плейлиста
        List<FileItem> emptyList = new ArrayList<>();

        boolean result = mSocketHelper.updateFileList(playlistName, emptyList);

        if (result) {
            System.out.println("Плейлист успешно создан: " + playlistName);
            sendPlayList(); // Обновление списка плейлистов на клиенте
        } else {
            System.out.println("Не удалось создать список воспроизведения: " + playlistName);
        }
    }

    /**
     * Метод для добавления видео в плейлист.
     * Читает текущий плейлист, добавляет новое видео и обновляет плейлист через SocketHelper.
     *
     * @param playlistName Имя плейлиста, в который добавляется видео.
     * @param videoFileName Имя файла видео, которое добавляется в плейлист.
     */
    public void addVideoToPlaylist(String playlistName, String videoFileName) {
        // System.out.println("Adding video to playlist: " + playlistName);
        List<FileItem> playListItems = mSocketHelper.readPlayList(mSocketHelper.readCurrentListPosition());

        if (playListItems != null) {
            FileItem newItem = new FileItem();
            newItem.setFileName(videoFileName);
            newItem.setFileSize("0"); // Placeholder value, update if actual size is needed
            newItem.setRepeatCount("1"); // Default repeat count

            playListItems.add(newItem);
            boolean result = mSocketHelper.updateFileList(playlistName, playListItems);
            if (result) {
                // System.out.println("Video added to playlist successfully: " + videoFileName);
                sendPlayList(); // Обновление списка плейлистов на клиенте
            } else {
                System.out.println("Не удалось добавить видео в список воспроизведения: " + videoFileName);
            }
        } else {
            // System.out.println("Playlist items are null for playlist: " + playlistName);
        }
    }

    /**
     * Метод для обработки видеофайла.
     * Использует FFmpeg для транскодирования видео и перемещает обработанный файл в указанную директорию.
     *
     * @param inputFilePath Путь к входному файлу для обработки.
     * @param outputDirectory Директория, куда будет перемещен обработанный файл.
     * @return true, если видео успешно обработано и перемещено, иначе false.
     */
    public boolean processVideo(String inputFilePath, String outputDirectory) {
        // System.out.println("Processing video: " + inputFilePath);

        try {
            String[] pathArray = {inputFilePath};
            String[] resultPaths = FFmpegUtils.getInstance().transCode(pathArray);

            if (resultPaths != null && resultPaths.length > 0) {
                String transcodedFilePath = resultPaths[0];
                File transcodedFile = new File(transcodedFilePath);

                // System.out.println("Transcoded file path: " + transcodedFile.getAbsolutePath());

                if (transcodedFile.exists()) {
                    // Проверяем, существует ли выходная директория, если нет, создаём её
                    File finalOutputDir = new File(outputDirectory);
                    if (!finalOutputDir.exists()) {
                        boolean dirCreated = finalOutputDir.mkdirs();
                        if (!dirCreated) {
                            // System.out.println("Failed to create output directory: " + finalOutputDir.getPath());
                            return false;
                        }
                    }

                    // Перемещаем файл в выходную директорию
                    File finalOutputFile = new File(finalOutputDir, transcodedFile.getName());
                    boolean fileMoved = transcodedFile.renameTo(finalOutputFile);
                    if (fileMoved) {
                        // System.out.println("Output file moved to final location: " + finalOutputFile.getAbsolutePath());
                        return true;
                    } else {
                        System.out.println("Не удалось переместить выходной файл в конечное место.");
                        return false;
                    }
                } else {
                    System.out.println("Выходной файл не существует после транскодирования.");
                    return false;
                }
            } else {
                System.out.println("Транскодирование не удалось.");
                return false;
            }
        } catch (IOException | PovException | InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * Метод для загрузки файлов.
     * Парсит JSON строку, получает пути к файлам, проверяет их наличие и обрабатывает их.
     *
     * @param jsonString JSON строка с информацией о файлах.
     */
    public void uploadFile(String jsonString) {
        try {
            // Разбор JSON строки
            JSONArray jsonArray = new JSONArray(jsonString);
            Path outputDirectory = Paths.get("uploads/temp").toAbsolutePath().normalize();
    
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String fileName = jsonObject.getString("fileName");
                String filePath = jsonObject.getString("filePath");
    
                // Полный путь к файлу
                Path fullFilePath = Paths.get("uploads").resolve(filePath).toAbsolutePath().normalize();
    
                // Логирование полученного полного пути
                // System.out.println("Full file path received: " + fullFilePath);
    
                // Проверка, существует ли файл
                File file = fullFilePath.toFile();
                if (file.exists()) {
                    // System.out.println("File exists: " + fullFilePath);
    
                    // Проверка существования выходного файла после обработки
                    File outputFile = new File(outputDirectory.toFile(), fileName);
                    if (outputFile.exists()) {
                        System.out.println("Выходной файл уже существует: " + outputFile.getPath());
                    } else {
                        // Преобразование пути в формат, используемый FFmpeg
                        String ffmpegFilePath = convertPathToFFmpegFormat(fullFilePath.toString());
                        System.out.println("Путь к файлу FFmpeg: " + ffmpegFilePath);
    
                        // Декодирование URL-кодированного пути
                        String decodedFilePath = decodeFilePath(ffmpegFilePath);
                        System.out.println("Расшифрованный путь к файлу: " + decodedFilePath);
    
                        // Обработка видео с помощью FFmpeg и проверка результата
                        boolean isProcessed = processVideo(decodedFilePath, outputDirectory.toString());
                        if (!isProcessed) {
                            System.out.println("Не удалось обработать видео.");
                            continue;
                        }
                    }
    
                    // Проверка существования выходного файла после обработки
                    if (outputFile.exists()) {
                        // Отправка команды на устройство с полным путем
                        String[] inputPath = { outputFile.getPath() };
                        List<FileItem> uploadedFiles = mSocketHelper.uploadFile(inputPath);
                        if (!uploadedFiles.isEmpty()) {
                            System.out.println("Файл успешно загружен: " + inputPath[0]);
                        } else {
                            System.out.println("Ошибка при загрузке файла.");
                        }
                    } else {
                        System.out.println("Выходной файл не существует: " + outputFile.getPath());
                    }
                } else {
                    System.out.println("Файл не существует: " + fullFilePath);
                }
            }
    
            // Очистка директории temp после завершения обработки
            try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(outputDirectory)) {
                for (Path path : directoryStream) {
                    Files.delete(path);
                }
                System.out.println("Директория temp очищена.");
            } catch (IOException e) {
                System.out.println("Ошибка при очистке директории temp: " + e.getMessage());
            }
    
        } catch (IOException | JSONException | PovException | InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * Преобразование пути в формат, используемый FFmpeg.
     *
     * @param path Путь к файлу, который нужно преобразовать.
     * @return Путь, преобразованный в формат, используемый FFmpeg.
     */
    private String convertPathToFFmpegFormat(String path) {
        return path.replace("\\", "/");
    }

    /**
     * Декодирование URL-кодированного пути.
     *
     * @param path Путь к файлу, который нужно декодировать.
     * @return Декодированный путь к файлу.
     * @throws UnsupportedEncodingException Если кодировка не поддерживается.
     */
    private String decodeFilePath(String path) throws UnsupportedEncodingException {
        return URLDecoder.decode(path, "UTF-8");
    }

    /**
     * Отправка сообщения через WebSocket сессии.
     *
     * @param message Сообщение для отправки.
     */
    private void sendMessage(String message) {
        if (message == null || message.isEmpty()) {
            System.out.println("Попытка отправить пустое или null сообщение была предотвращена.");
            return;
        }

        if (session == null || !session.isOpen()) {
            System.out.println("WebSocket сессия закрыта или недоступна. Сообщение не будет отправлено.");
            return;
        }

        System.out.println("Отправка сообщения: " + message); // Логирование отправляемого сообщения
        try {
            session.sendMessage(new TextMessage(message));
        } catch (IOException e) {
            System.err.println("Ошибка при отправке сообщения: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * Воспроизведение видео по его индексу.
     *
     * @param index Индекс видео для воспроизведения.
     */
    private void playVideoByIndex(int index) {
        boolean playResult = false;
        
        while (!playResult) {
            playResult = mSocketHelper.playVideo(index);
            System.out.println("результат playVideo: " + playResult + " для индекса: " + index);
            
            if (!playResult) {
                System.out.println("Failed to play video at index: " + index + ". Retrying...");
                try {
                    Thread.sleep(500); 
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // Восстанавливаем статус прерывания
                    System.out.println("Поток был прерван. Завершение выполнения метода.");
                    return;
                }
            }
        }
    }

    /**
     * Чтение элементов плейлиста по индексу плейлиста и отправка их на клиент.
     * Выбирает файлы с расширением .mp4 из данных, которые могут быть перепутаны
     * китайскими разработчиками, и отправляет их в формате JSON.
     *
     * @param playlistIndex Индекс плейлиста, элементы которого нужно прочитать.
     */
    private void readPlayListItems(int playlistIndex) {
        List<FileItem> playlistItems = mSocketHelper.readPlayList(playlistIndex);
        if (playlistItems != null) {
            try {
                // Создание JSON объекта для ответа
                JSONObject response = new JSONObject();
                response.put("method", "playlistItems");

                JSONArray videoArray = new JSONArray();
                for (FileItem item : playlistItems) {
                    if (item.getFileName().endsWith(".mp4")) {
                        JSONObject videoObj = new JSONObject();
                        videoObj.put("fileName", item.getFileName().replace("null", ""));
                        videoArray.put(videoObj);
                    }
                    if (item.getFileSize().endsWith(".mp4")) {
                        JSONObject videoObj = new JSONObject();
                        videoObj.put("fileName", item.getFileSize().replace("null", ""));
                        videoArray.put(videoObj);
                    }
                    if (item.getRepeatCount().endsWith(".mp4")) {
                        JSONObject videoObj = new JSONObject();
                        videoObj.put("fileName", item.getRepeatCount().replace("null", ""));
                        videoArray.put(videoObj);
                    }
                }

                response.put("videoList", videoArray);
                sendMessage(response.toString());
            } catch (JSONException e) {
                e.printStackTrace();
                System.out.println("Не удалось разобрать элементы плейлиста для отправки");
            }
        }
    }

    /**
     * Воспроизведение видео из плейлиста по индексу плейлиста и индексу видео.
     * 
     * @param playlistIndex Индекс плейлиста, из которого воспроизводится видео.
     * @param videoIndex Индекс видео для воспроизведения.
     */
    private void playVideoFromPlaylist(int playlistIndex, int videoIndex) {
        try {
            boolean playlistResult = false;
            boolean playResult = false;
            
            // Добавляем задержку перед получением текущего индекса плейлиста
            try {
                Thread.sleep(500); 
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); 
                System.out.println("Поток был прерван. Завершение выполнения метода.");
                return;
            }
            
            // Попытка получить текущий индекс плейлиста
            Integer currentPlaylistIndex = null;

            while (true) {
                // Запрашиваем текущий индекс плейлиста
                currentPlaylistIndex = mSocketHelper.readCurrentListPosition();
                
                // Проверяем, что индекс был получен и является валидным
                if (currentPlaylistIndex != null && currentPlaylistIndex >= 0) {
                    break; // Если индекс валидный, выходим из цикла
                }

                // Задержка перед следующей попыткой
                try {
                    Thread.sleep(500); // Задержка 500 миллисекунд перед повторной попыткой
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // Восстанавливаем статус прерывания
                    System.out.println("Поток был прерван. Завершение выполнения метода.");
                    return;
                }
            }

            // Проверяем, если текущий плейлист уже выбран, пропускаем переключение
            if (currentPlaylistIndex != null && !currentPlaylistIndex.equals(playlistIndex)) {
                // Пытаемся установить плейлист до тех пор, пока не получится
                while (!playlistResult) {
                    try {
                        Thread.sleep(500); // Задержка перед попыткой переключить плейлист
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt(); // Восстанавливаем статус прерывания
                        System.out.println("Поток был прерван. Завершение выполнения метода.");
                        return;
                    }
                    
                    playlistResult = mSocketHelper.usePlayList(playlistIndex);
                    System.out.println("Результат установки плейлиста: " + playlistResult + " для индекса плейлиста: " + playlistIndex);

                    if (!playlistResult) {
                        System.out.println("Не удалось установить плейлист на индекс: " + playlistIndex + ". Повторная попытка...");
                        
                        try {
                            Thread.sleep(500); // Задержка перед попыткой переключить плейлист
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt(); // Восстанавливаем статус прерывания
                            System.out.println("Поток был прерван. Завершение выполнения метода.");
                            return;
                        }
                        
                        // Обновляем текущий индекс перед повторной попыткой
                        currentPlaylistIndex = mSocketHelper.readCurrentListPosition();
                        
                        if (currentPlaylistIndex != null && currentPlaylistIndex.equals(playlistIndex)) {
                            System.out.println("Плейлист уже установлен на индекс: " + playlistIndex);
                            playlistResult = true;
                            break;
                        }
                    }
                }
            } else if (currentPlaylistIndex != null) {
                System.out.println("Плейлист уже установлен на индекс: " + playlistIndex);
                playlistResult = true; // Считаем, что установка прошла успешно, если плейлист уже выбран
            }

            // Если установка плейлиста прошла успешно, пытаемся воспроизвести видео до тех пор, пока не получится
            while (!playResult) {
                try {
                    Thread.sleep(500); // Задержка для корректной установки плейлиста
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // Восстанавливаем статус прерывания
                    System.out.println("Поток был прерван. Завершение выполнения метода.");
                    return;
                }
                playResult = mSocketHelper.playVideo(videoIndex);
                System.out.println("Результат воспроизведения видео: " + playResult + " для индекса видео: " + videoIndex + " в плейлисте с индексом: " + playlistIndex);

                if (!playResult) {
                    System.out.println("Не удалось воспроизвести видео на индексе: " + videoIndex + " в плейлисте с индексом: " + playlistIndex + ". Повторная попытка...");
                    try {
                        Thread.sleep(500); // Задержка перед повторной попыткой
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt(); // Восстанавливаем статус прерывания
                        System.out.println("Поток был прерван. Завершение выполнения метода.");
                        return;
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Не удалось выполнить playVideoFromPlaylist");
        }
    }

    /**
     * Установка плейлиста по индексу.
     * 
     * @param args Аргументы, содержащие индекс плейлиста.
     */
    private void usePlayList(String args) {
        try {
            int newPlaylistIndex = Integer.parseInt(args);
            boolean result = false;

            // Добавляем задержку перед началом
            try {
                Thread.sleep(500); 
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt(); 
                System.out.println("Поток был прерван. Завершение выполнения метода.");
                return;
            }

            // Попытка получить текущий индекс плейлиста
            Integer currentPlaylistIndex = null;

            while (true) {
                // Запрашиваем текущий индекс плейлиста
                currentPlaylistIndex = mSocketHelper.readCurrentListPosition();
                
                // Проверяем, что индекс был получен и является валидным
                if (currentPlaylistIndex != null && currentPlaylistIndex >= 0) {
                    break; // Если индекс валидный, выходим из цикла
                }

                // Задержка перед следующей попыткой
                try {
                    Thread.sleep(500); // Задержка 500 миллисекунд перед повторной попыткой
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt(); 
                    System.out.println("Поток был прерван. Завершение выполнения метода.");
                    return;
                }
            }

            // Проверяем, изменился ли индекс плейлиста
            if (currentPlaylistIndex != null && !currentPlaylistIndex.equals(newPlaylistIndex)) {
                System.out.println("Переключение плейлиста с индекса " + currentPlaylistIndex + " на " + newPlaylistIndex);
                while (!result) {
                    try {
                        Thread.sleep(500); // Задержка перед попыткой переключить плейлист
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Thread.currentThread().interrupt(); 
                        return; 
                    }

                    result = mSocketHelper.usePlayList(newPlaylistIndex);
                    if (result) {
                        System.out.println("Плейлист успешно установлен на индекс: " + newPlaylistIndex);
                    } else {
                        System.out.println("Не удалось установить плейлист на индекс: " + newPlaylistIndex + ". Повторная попытка...");
                        // Обновляем текущий индекс перед повторной попыткой
                        try {
                            Thread.sleep(500); // Задержка перед попыткой переключить плейлист
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            Thread.currentThread().interrupt(); 
                            return; 
                        }
                        currentPlaylistIndex = mSocketHelper.readCurrentListPosition();
                        if (currentPlaylistIndex != null && currentPlaylistIndex.equals(newPlaylistIndex)) {
                            System.out.println("Плейлист уже установлен на индекс: " + newPlaylistIndex);
                            result = true;
                            break;
                        }
                    }
                }
            } else {
                System.out.println("Плейлист уже установлен на индекс: " + newPlaylistIndex);
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
            System.out.println("Не удалось разобрать аргументы для usePlayList");
        }
    }

    /**
     * Закрытие соединения с сокетом.
     */
    public void closeConnection() {
        if (mSocketHelper != null && mSocketHelper.isConnect()) {
            mSocketHelper.close();
            // System.out.println("Socket connection closed.");
        }
    }

    /**
     * Открытие устройства для воспроизведения.
     */
    private void openDevice() {
        boolean result = mSocketHelper.openDevice();
        System.out.println("результат openDevice: " + result);
    }

    /**
     * Закрытие устройства для воспроизведения.
     */
    private void closeDevice() {
        boolean result = mSocketHelper.closeDevice();
        System.out.println("результат closeDevice: " + result);
    }
}

