<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="UTF-8" />
    <title>File Manager with FTP Sync</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <nav id="sidebar">
      <button id="selectDirBtn" aria-label="Select Directory">📁</button>
      <button id="toggleFilesBtn" aria-label="Toggle Files">📂</button>
      <button id="toggleTrashBtn" aria-label="Toggle Trash">🗑️</button>
      <button id="toggleThemeBtn" aria-label="Toggle Theme">🌓</button>
      <button id="toggleConfirmationsBtn" aria-label="Toggle Confirmations">🔒</button>
      <button id="openSyncSettingsBtn" aria-label="Open FTP Sync Settings">⚙️</button>
      <button id="toggleSyncBtn" aria-label="Toggle Sync">🔄</button>
      <input type="text" id="searchInput" placeholder="Поиск..." aria-label="Search Files and Folders" />
    </nav>

    <section class="wrapper">
      <section id="filePanel" class="panel left hidden" role="region">
        <button id="createFolderBtn" aria-label="Create Folder">Создать папку</button>
        <div id="foldersList" class="droppable" role="list"></div>
      </section>

      <div class="gutter hidden" id="resizer1"></div>

      <section id="folderContentPanel" class="panel middle hidden" role="region">
        <button id="createFileBtn" aria-label="Create File">Создать файл</button>
        <div id="filesList" class="droppable" role="list"></div>
      </section>

      <div class="gutter hidden" id="resizer2"></div>

      <section id="trashPanel" class="panel left hidden" role="region">
        <button id="restoreFromTrashBtn" aria-label="Restore from Trash">Восстановить</button>
        <div id="trashList" class="droppable" role="list"></div>
      </section>

      <div class="gutter hidden" id="resizer3"></div>

      <section id="thirdPanel" class="panel right">
        <div id="contentView">FTP синхронизация</div>
      </section>
    </section>

    <div id="infoDisplay" role="status"></div>

    <div id="contextMenu" class="context-menu">
      <button id="openOption">Открыть</button>
      <button id="renameOption">Переименовать</button>
      <button id="deleteOption">Удалить</button>
      <button id="restoreOption">Восстановить</button>
      <button id="syncOption">Синхронизировать/Отменить синхронизацию</button>
    </div>

    <!-- Диалоговое окно настроек синхронизации -->
    <div id="syncSettingsDialog" class="confirmation-dialog hidden">
      <h2>Настройки синхронизации FTP</h2>
      <div>
        <label>
          Подключения FTP:
          <select id="ftpConnections"></select>
        </label>
        <button id="addFtpConnectionBtn">Добавить новое подключение</button>
      </div>
      <div id="ftpConnectionDetails" class="hidden">
        <label> Хост: <input type="text" id="ftpHostInput" /> </label>
        <label> Порт: <input type="number" id="ftpPortInput" value="21" /> </label>
        <label> Имя пользователя: <input type="text" id="ftpUserInput" /> </label>
        <label> Пароль: <input type="password" id="ftpPasswordInput" /> </label>
        <label> Удаленный каталог: <input type="text" id="remoteDirInput" /> </label>
      </div>
      <div>
        <h3>Опции синхронизации</h3>
        <label>
          <input type="checkbox" id="syncOnStartCheckbox" />
          Синхронизация при старте
        </label>
        <label>
          <input type="checkbox" id="syncOnChangesCheckbox" />
          Синхронизация при изменении
        </label>
        <label> Таймер синхронизации (минуты): <input type="number" id="syncIntervalInput" /> </label>
      </div>
      <div>
        <button id="saveFtpSettingsBtn">Сохранить</button>
        <button id="closeSyncSettingsBtn">Отмена</button>
      </div>
    </div>
    <div id="confirmationDialog" class="confirmation-dialog hidden">
      <p id="confirmationMessage"></p>
      <!-- Сообщение подтверждения -->
      <div>
        <button id="confirmYes">Да</button>
        <!-- Кнопка подтверждения -->
        <button id="confirmNo">Нет</button>
        <!-- Кнопка отмены -->
      </div>
    </div>
    <!-- Диалог выбора при конфликте -->
    <div id="fileConflictDialog" class="confirmation-dialog hidden">
      <h2>Конфликты синхронизации</h2>
      <p>Выберите действие для каждого конфликта:</p>
      <table>
        <thead>
          <tr>
            <th>Имя файла</th>
            <th>Локальный</th>
            <th>Удалённый</th>
            <th>Действие</th>
          </tr>
        </thead>
        <tbody id="conflictTable"></tbody>
      </table>
      <button id="resolveConflictsBtn">Применить</button>
    </div>
    <script src="js/main.js"></script>
  </body>
</html>


/* Основные переменные цветов для лёгкой настройки */
:root {
  --primary-color: #2c3e50; /* Основной цвет боковой панели */
  --secondary-color: #ecf0f1; /* Лёгкий цвет для текста и фона */
  --highlight-color: #3498db; /* Цвет выделения */
  --success-color: #2ecc71; /* Зелёный для успешных операций */
  --error-color: #e74c3c; /* Красный для ошибок */
  --text-color: #333333; /* Основной цвет текста */
  --dark-bg-color: #1e1e1e; /* Тёмный фон (в тёмной теме) */
  --dark-text-color: #ffffff; /* Текст при тёмной теме */
  --divider-color: #dcdcdc; /* Разделитель между панелями */
  --gutter-color: #7f8c8d; /* Цвет линии ресайзера */
}

*,
*::before,
*::after {
  box-sizing: border-box; /* Корректное отображение размеров элементов */
  margin: 0;
  padding: 0;
}

body {
  margin: 0;
  font-family: Arial, sans-serif; /* Удобный шрифт без засечек */
  font-size: 14px;
  color: var(--text-color); /* Основной цвет текста */
  background-color: var(--secondary-color); /* Фон приложения */
  display: flex;
  height: 100vh; /* Высота окна */
}

body.dark-mode {
  background-color: var(--dark-bg-color); /* Тёмная тема — фон */
  color: var(--dark-text-color); /* Тёмная тема — текст */
}

/* --- Боковая панель --- */
#sidebar {
  width: 60px; /* Фиксированная ширина боковой панели */
  background-color: var(--primary-color); /* Основной цвет */
  color: var(--secondary-color); /* Текст на боковой панели */
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 10px 0;
  gap: 10px; /* Расстояние между кнопками */
}

#sidebar button,
#sidebar input {
  background: none;
  border: none;
  color: var(--secondary-color); /* Цвет текста */
  font-size: 20px;
  cursor: pointer;
}

#sidebar input {
  background-color: rgba(255, 255, 255, 0.2); /* Полупрозрачный фон */
  color: var(--secondary-color);
  padding: 5px;
  border-radius: 5px;
  font-size: 14px;
}

#sidebar button:hover,
#sidebar input:focus {
  color: var(--highlight-color); /* Цвет при наведении и фокусе */
}

/* --- Общая структура панелей --- */
.wrapper {
  height: 100%;
  width: calc(100% - 60px); /* Вычитаем ширину боковой панели */
  display: flex;
}

.panel {
  background: var(--secondary-color); /* Фон панелей */
  padding: 15px;
  overflow-y: auto;
  border-right: 1px solid var(--divider-color); /* Разделительная линия */
}

.panel.hidden {
  display: none;
}

/* --- Разделители между панелями --- */
.gutter {
  width: 4px;
  height: 100%;
  background: var(--gutter-color); /* Цвет разделителей */
  cursor: ew-resize;
}
.gutter.hidden {
  display: none;
}

/* --- Элементы файлов и папок --- */
.draggable {
  display: flex;
  align-items: center;
  margin: 5px 0;
  padding: 8px 10px;
  border-radius: 4px;
  background: none;
  cursor: pointer;
}

.draggable:hover {
  background: rgba(52, 152, 219, 0.2); /* Лёгкий синий фон при наведении */
}

.draggable::before {
  content: '';
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 8px; /* Отступ между кружком и текстом */
  border-radius: 50%;
  background-color: transparent; /* Прозрачный по умолчанию */
}

.draggable.synced::before {
  background-color: var(--success-color); /* Зелёный кружок для синхронизации */
}

.draggable.unsynced::before {
  background-color: var(--error-color); /* Красный кружок для не синхронизированных */
}

/* --- Диалог подтверждения --- */
.confirmation-dialog {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: var(--secondary-color); /* Белый фон */
  border: 1px solid var(--divider-color);
  padding: 20px;
  border-radius: 8px; /* Закруглённые края */
  z-index: 1001;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25); /* Тень */
}

.confirmation-dialog.hidden {
  display: none;
}

.confirmation-dialog button {
  margin: 5px;
  padding: 8px 15px;
  background-color: var(--highlight-color); /* Синий фон кнопок */
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.confirmation-dialog button:hover {
  background-color: darken(var(--highlight-color), 10%);
}

.confirmation-dialog #confirmNo {
  background-color: var(--error-color); /* Красный для отмены */
}

/* --- Контекстное меню --- */
.context-menu {
  position: absolute;
  display: none;
  background: white;
  border: 1px solid var(--divider-color);
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Тень меню */
  z-index: 1000;
}

.context-menu.visible {
  display: block;
}

.context-menu button {
  display: block;
  padding: 10px;
  width: 100%;
  border: none;
  background: none;
  cursor: pointer;
}

.context-menu button:hover {
  background: rgba(0, 0, 0, 0.1); /* Тёмный фон при наведении */
}

/* --- Информационное положение --- */
#infoDisplay {
  position: fixed;
  bottom: 10px;
  right: 10px;
  background: rgba(52, 73, 94, 0.9); /* Полупрозрачный фон */
  color: white;
  padding: 10px 15px;
  border-radius: 5px;
  font-size: 14px;
}

/* --- Тёмная тема (дополнительно) --- */
body.dark-mode .panel {
  background: var(--dark-bg-color);
  color: var(--dark-text-color);
}

body.dark-mode #infoDisplay {
  background: rgba(255, 255, 255, 0.2);
  color: #eee;
}
.panel.resizing {
  cursor: col-resize;
  border-right: 3px dashed var(--highlight-color); /* Подсветка */
  transition: border-color 0.2s ease-in-out;
}


const ftp = require('basic-ftp'); // Для связи с FTP
const fs = require('fs').promises; // Для работы с файловой системой
const path = require('path'); // Для управления путями
const appPath = nw.__dirname; // путь к папке приложения

// Глобальные переменные
let messageQueue = [];
let currentDir = nw.__dirname; // Текущая директория приложения
let filesForSync = []; // Список файлов/папок на синхронизацию
let ftpConnections = []; // Список всех FTP-подключений
let currentFtpConnection = null; // Текущее выбранное подключение
let filePanelWidth; // Ширина панели файлов
let trashPanelWidth;
let folderContentPanelWidth; // Ширина панели содержимого папок
let isDarkMode = false; // Текущая тема интерфейса
let confirmDeletion = true; // Подтверждение удаления включено или нет

let fileWatcher = null; // Наблюдатель за изменениями файлов
let syncOptions = {
  syncOnStart: false, // Синхронизация при старте программы
  syncOnChanges: false, // Синхронизация при изменении файлов
  syncInterval: null, // Интервал синхронизации (в минутах)
};

// Confirmation dialog functions
function showConfirmationDialog(message, onConfirm) {
  const dialog = document.getElementById('confirmationDialog'); // Находим диалог подтверждения
  const confirmationMessage = document.getElementById('confirmationMessage'); // Находим сообщение

  if (!confirmationMessage || !dialog) {
    console.error('Элемент подтверждения отсутствует в DOM.');
    return; // Завершаем выполнение, если DOM-структура не готова
  }

  confirmationMessage.textContent = message; // Устанавливаем текст сообщения

  const confirmYes = document.getElementById('confirmYes'); // Кнопка "Да"
  const confirmNo = document.getElementById('confirmNo'); // Кнопка "Нет"

  if (!confirmYes || !confirmNo) {
    console.error('Кнопки подтверждения отсутствуют в DOM.');
    return;
  }

  // Устанавливаем обработчики событий для подтверждения
  confirmYes.onclick = () => {
    onConfirm(); // Вызов функции подтверждения
    closeConfirmationDialog(); // Закрываем диалог
  };

  confirmNo.onclick = closeConfirmationDialog; // Закрываем диалог без подтверждения

  dialog.classList.remove('hidden'); // Показываем диалог
}

function closeConfirmationDialog() {
  const dialog = document.getElementById('confirmationDialog');
  if (dialog) {
    dialog.classList.add('hidden'); // Скрываем диалог
  }
}

async function createDirectoryIfNotExists(dirPath) {
  try {
    await fs.access(dirPath);
  } catch (err) {
    if (err.code === 'ENOENT') {
      await fs.mkdir(dirPath, { recursive: true });
    } else {
      throw err;
    }
  }
}

async function updateSaveDataWithTrashItem(trashItem) {
  let saveData = await loadSaveData();
  saveData.trash.push(trashItem);
  await saveSaveData(saveData);
}

async function renameItem(itemPath, itemType) {
  const itemName = path.basename(itemPath); // Текущее имя
  const newName = prompt(`Введите новое имя для ${itemType}:`, itemName); // Запрашиваем новое имя

  // Проверяем, если пользователь отменил ввод
  if (!newName || newName === itemName) {
    displayInfo('Переименование отменено.');
    return;
  }

  // Генерируем путь с новым именем
  const newPath = path.join(path.dirname(itemPath), newName);

  try {
    // Переименовываем файл или папку
    await fs.rename(itemPath, newPath);

    displayInfo(`"${itemName}" успешно переименован в "${newName}".`);

    // Обновляем интерфейс
    await refreshUI();
  } catch (err) {
    console.error(`Ошибка переименования объекта "${itemName}":`, err);

    // Отображаем сообщение об ошибке
    if (err.code === 'EEXIST') {
      displayInfo(`Объект с именем "${newName}" уже существует.`);
    } else {
      displayInfo(`Ошибка переименования "${itemName}": ${err.message}`);
    }
  }
}

async function openFolder(folderName) {
  const folderPath = path.join(currentDir, folderName); // Получаем путь выбранной папки
  const folderContentPanel = document.getElementById('folderContentPanel'); // Панель для отображения содержимого папки
  const resizer2 = document.getElementById('resizer2'); // Разделитель между панелями

  // Проверяем, открыта ли уже эта папка. Если да — закрываем её.
  if (folderContentPanel.getAttribute('data-current-folder') === folderName) {
    folderContentPanel.classList.add('hidden');
    resizer2.classList.add('hidden');
    folderContentPanel.removeAttribute('data-current-folder');
    return;
  }

  // Загружаем содержимое папки и показываем её
  folderContentPanel.classList.remove('hidden');
  resizer2.classList.remove('hidden');

  try {
    await loadFiles(folderPath); // Загружаем файлы из выбранной папки
    folderContentPanel.setAttribute('data-current-folder', folderName); // Сохраняем открытое состояние папки
  } catch (err) {
    console.error(`Ошибка загрузки содержимого папки "${folderName}":`, err);
    displayInfo(`Не удалось открыть папку "${folderName}".`);
  }
}

const gutter1 = document.getElementById('resizer1');
const gutter2 = document.getElementById('resizer2');
const gutter3 = document.getElementById('resizer3');

resizer(gutter1, filePanel, 10, 800);
resizer(gutter2, folderContentPanel, 10, 800);
resizer(gutter3, trashPanel, 10, 800); // Минимальная и максимальная ширина корзины

filePanel.style.width = `${filePanelWidth}px`;
folderContentPanel.style.width = `${folderContentPanelWidth}px`;
trashPanel.style.width = `${trashPanel}px`;
updateThirdPanelWidth();

function resizer(gutter, panel, minWidth, maxWidth) {
  if (!gutter || !panel) {
    console.error('Элемент gutter или panel не найден');
    return;
  }

  let animationFrame; // Оптимизация через requestAnimationFrame
  let prevX = 0;

  // Обработчик события mousedown
  function mouseDownHandler(e) {
    e.preventDefault();
    prevX = e.clientX; // Сохраняем начальную позицию курсора мыши

    // Обработчик изменения размеров
    function mouseMoveHandler(event) {
      const dx = event.clientX - prevX; // Вычисление изменения позиции
      const currentWidth = panel.getBoundingClientRect().width;
      const newWidth = Math.max(minWidth, Math.min(currentWidth + dx, maxWidth));
      prevX = event.clientX;

      // Используем requestAnimationFrame вместо немедленного изменения DOM
      if (animationFrame) cancelAnimationFrame(animationFrame);
      animationFrame = requestAnimationFrame(() => {
        panel.style.width = `${newWidth}px`;

        // Обновляем глобальные данные
        if (panel.id === 'filePanel') {
          filePanelWidth = newWidth;
        }
        if (panel.id === 'folderContentPanel') {
          folderContentPanelWidth = newWidth;
        }
        if (panel.id === 'trashPanel') {
          trashPanelWidth = newWidth;
        }

        updateThirdPanelWidth(); // Обновляем третью панель
      });
    }

    // Завершение изменения размеров
    function mouseUpHandler() {
      document.removeEventListener('mousemove', mouseMoveHandler);
      document.removeEventListener('mouseup', mouseUpHandler);

      if (animationFrame) cancelAnimationFrame(animationFrame);

      // Сохраняем настройки только один раз при завершении
      saveSettings();
    }

    // Подключаем обработку событий движения мыши и отпускания кнопки
    document.addEventListener('mousemove', mouseMoveHandler);
    document.addEventListener('mouseup', mouseUpHandler);
  }

  gutter.addEventListener('mousedown', mouseDownHandler); // Добавляем обработку на разделитель
}

function initializeContextMenu() {
  // Находим все элементы с классом draggable
  const draggableElements = document.querySelectorAll('.draggable');

  draggableElements.forEach((element) => {
    element.addEventListener('contextmenu', (event) => {
      const itemType = element.getAttribute('data-type'); // Тип элемента: folder, file, trash
      const itemName = element.textContent; // Имя элемента (например, имя файла)
      showContextMenu(event, itemName, itemType); // Вызываем showContextMenu при правом клике
    });
  });

  // Убираем стандартное контекстное меню браузера
  document.addEventListener('contextmenu', (event) => {
    event.preventDefault(); // Базовое отключение системного контекстного меню
  });
}

function updateThirdPanelWidth() {
  // Получаем ссылки на все панели
  const filePanel = document.getElementById('filePanel');
  const folderContentPanel = document.getElementById('folderContentPanel');
  const trashPanel = document.getElementById('trashPanel');
  const thirdPanel = document.getElementById('thirdPanel');

  // Вычисляем размеры панелей
  const filePanelWidth = filePanel.classList.contains('hidden') ? 0 : filePanel.offsetWidth;
  const folderContentPanelWidth = folderContentPanel.classList.contains('hidden') ? 0 : folderContentPanel.offsetWidth;
  const trashPanelWidth = trashPanel.classList.contains('hidden') ? 0 : trashPanel.offsetWidth;

  // Новый доступный размер третьей панели
  const remainingWidth = `calc(100% - ${filePanelWidth + folderContentPanelWidth + trashPanelWidth + 20}px)`;

  // Проверяем корректное обновление третьей панели
  if (thirdPanel) {
    thirdPanel.style.width = remainingWidth;
  } else {
    console.error('Элемент thirdPanel не найден');
  }
}

async function loadTrash() {
  const trashList = document.getElementById('trashList');
  trashList.innerHTML = ''; // Очищаем текущий список

  try {
    const saveData = await loadSaveData();
    const trash = saveData.trash || [];

    if (trash.length === 0) {
      trashList.innerHTML = `<p>Корзина пуста</p>`;
    } else {
      trash.forEach((item) => {
        const trashDiv = document.createElement('div');
        trashDiv.textContent = item.name;
        trashDiv.classList.add('draggable');
        trashDiv.setAttribute('data-type', 'trash');
        trashList.appendChild(trashDiv);
      });
    }
    displayInfo(`Корзина загружена: ${trash.length}`);
    initializeContextMenu(); // Переподключаем обработчики для контекстного меню
  } catch (err) {
    console.error('Ошибка загрузки корзины:', err);
    displayInfo('Ошибка загрузки корзины.');
  }
}

function showContextMenu(e, itemName, itemType) {
  e.preventDefault(); // Предотвращаем стандартное действие браузера
  const menu = document.getElementById('contextMenu');

  // Устанавливаем местоположение контекстного меню
  menu.style.left = `${e.pageX}px`;
  menu.style.top = `${e.pageY}px`;
  menu.classList.add('visible');

  const deleteOption = menu.querySelector('#deleteOption');
  const restoreOption = menu.querySelector('#restoreOption');
  const renameOption = menu.querySelector('#renameOption');
  const syncOption = menu.querySelector('#syncOption');

  // Скрываем или показываем опции в зависимости от типа объекта (файл, папка, корзина)
  if (itemType === 'file' || itemType === 'folder') {
    deleteOption.style.display = 'block';
    restoreOption.style.display = 'none';
    renameOption.style.display = 'block';
    syncOption.style.display = 'block';

    // Натуральный путь объекта
    const itemPath =
      itemType === 'file'
        ? path.join(currentDir, document.getElementById('folderContentPanel').dataset.currentFolder, itemName)
        : path.join(currentDir, itemName);

    // Назначаем действия кнопкам меню
    deleteOption.onclick = () => moveToTrash(itemPath, itemType);
    renameOption.onclick = () => renameItem(itemPath, itemType);
    syncOption.onclick = () => {
      const targetElement = e.target.closest('.draggable'); // Целевой элемент интерфейса
      toggleSyncStatus(itemPath, itemType, targetElement);
      updateSyncIndicators();
    };
  } else if (itemType === 'trash') {
    deleteOption.style.display = 'block';
    restoreOption.style.display = 'block';
    renameOption.style.display = 'none';
    syncOption.style.display = 'none';

    // Назначаем действия - удаление из корзины и восстановление
    deleteOption.onclick = () => deleteFromTrash(itemName);
    restoreOption.onclick = () => restoreFromTrash(itemName);
  }

  // Скрытие контекстного меню при клике в любом другом месте
  const hideContextMenu = () => {
    menu.classList.remove('visible');
    document.removeEventListener('click', hideContextMenu);
  };

  document.addEventListener('click', hideContextMenu);
}

function getTrashPath() {
  return path.join(appPath, 'Trash');
}

async function deleteFromTrash(itemName) {
  try {
    let saveData = await loadSaveData();
    const trashItemIndex = saveData.trash.findIndex((item) => item.name === itemName);
    if (trashItemIndex !== -1) {
      const trashItem = saveData.trash[trashItemIndex];

      await fs.access(trashItem.trashPath, fs.constants.F_OK);

      if (trashItem.isFile) {
        await fs.unlink(trashItem.trashPath);
      } else {
        await fs.rmdir(trashItem.trashPath, { recursive: true });
      }

      saveData.trash.splice(trashItemIndex, 1);
      await saveSaveData(saveData);
      displayInfo(`Элемент "${itemName}" удален из корзины.`);

      await loadTrash();
    }
  } catch (err) {
    console.error('Не удалось удалить элемент из корзины:', err);
    displayInfo(`Ошибка удаления элемента "${itemName}" из корзины.`);
  }
}

async function createFolder() {
  const folderName = prompt('Введите имя новой папки:');
  if (!folderName || folderName.trim() === '') {
    displayInfo('Операция создания папки отменена или имя папки пустое.');
    return;
  }
  if (folderName) {
    const folderPath = path.join(currentDir, folderName);
    try {
      await fs.access(folderPath);
      alert('Папка с таким именем уже существует.');
    } catch {
      await fs.mkdir(folderPath);
      let saveData = await loadSaveData();
      saveData.folders.push({ name: folderName, path: folderPath });
      await saveSaveData(saveData);
      await loadFolders();
      displayInfo(`Папка "${folderName}" создана.`);
    }
  }
}

async function createFile() {
  const currentFolder = document.getElementById('folderContentPanel').getAttribute('data-current-folder');
  if (currentFolder) {
    const fileName = prompt('Введите имя нового файла:');
    if (fileName) {
      const filePath = path.join(currentDir, currentFolder, fileName);
      try {
        await fs.access(filePath);
        alert('Файл с таким именем уже существует.');
      } catch {
        await fs.writeFile(filePath, '');
        let saveData = await loadSaveData();
        saveData.files.push({ name: fileName, path: filePath });
        await saveSaveData(saveData);
        await loadFiles(path.join(currentDir, currentFolder));
        displayInfo(`Файл "${fileName}" создан.`);
      }
    }
  } else {
    alert('Пожалуйста, выберите папку для создания файла.');
  }
}

async function moveToTrash(itemPath, type) {
  try {
    const itemStats = await fs.lstat(itemPath);
    const itemName = path.basename(itemPath);
    const trashDir = getTrashPath();

    await createDirectoryIfNotExists(trashDir);

    const trashItemPath = path.join(trashDir, itemName);
    const trashItem = {
      name: itemName,
      originalPath: itemPath,
      trashPath: trashItemPath,
      type,
      isFile: itemStats.isFile(),
    };

    // If confirmations are enabled
    if (confirmDeletion) {
      showConfirmationDialog(`Вы уверены, что хотите переместить "${itemName}" в корзину?`, async () => {
        await updateSaveDataWithTrashItem(trashItem);
        await fs.rename(itemPath, trashItemPath);
        displayInfo(`Элемент "${itemName}" перемещен в корзину.`);
        if (type === 'folder' && itemName === document.getElementById('folderContentPanel').dataset.currentFolder) {
          document.getElementById('folderContentPanel').classList.add('hidden');
          document.getElementById('resizer2').classList.add('hidden');
          document.getElementById('folderContentPanel').removeAttribute('data-current-folder');
        }
        await refreshUI();
      });
    } else {
      await updateSaveDataWithTrashItem(trashItem);
      await fs.rename(itemPath, trashItemPath);
      displayInfo(`Элемент "${itemName}" перемещен в корзину.`);
      if (type === 'folder' && itemName === document.getElementById('folderContentPanel').dataset.currentFolder) {
        document.getElementById('folderContentPanel').classList.add('hidden');
        document.getElementById('resizer2').classList.add('hidden');
        document.getElementById('folderContentPanel').removeAttribute('data-current-folder');
      }
      await refreshUI();
    }
  } catch (err) {
    console.error(`Не удалось переместить элемент "${itemPath}" в корзину:`, err);
    displayInfo(`Ошибка перемещения элемента "${itemPath}" в корзину: ${err}`);
  }
}

async function restoreFromTrash(itemName) {
  try {
    let saveData = await loadSaveData();
    const trashItemIndex = saveData.trash.findIndex((item) => item.name === itemName);
    if (trashItemIndex !== -1) {
      const trashItem = saveData.trash[trashItemIndex];
      const targetPath = trashItem.originalPath;

      // If confirmations are enabled
      if (confirmDeletion) {
        showConfirmationDialog(`Вы уверены, что хотите восстановить "${itemName}" из корзины?`, async () => {
          await fs.rename(trashItem.trashPath, targetPath);
          saveData.trash.splice(trashItemIndex, 1);
          await saveSaveData(saveData);
          displayInfo(`Элемент "${itemName}" восстановлен из корзины.`);
          await refreshUI();
        });
      } else {
        await fs.rename(trashItem.trashPath, targetPath);
        saveData.trash.splice(trashItemIndex, 1);
        await saveSaveData(saveData);
        displayInfo(`Элемент "${itemName}" восстановлен из корзины.`);
        await refreshUI();
      }
    }
  } catch (err) {
    console.error('Не удалось восстановить элемент из корзины:', err);
    displayInfo(`Ошибка восстановления элемента "${itemName}" из корзины.`);
  }
}

async function selectDirectory() {
  const fileInput = document.createElement('input');
  fileInput.type = 'file';
  fileInput.setAttribute('nwdirectory', true);

  fileInput.addEventListener('change', async () => {
    if (fileInput.files.length > 0) {
      currentDir = fileInput.files[0].path;
      await saveSettings(); // Сохраняем новую директорию
      await loadFolders(); // Загружаем новые папки
      displayInfo(`Выбрана директория: ${currentDir}`);
    }
  });

  fileInput.click();
}

async function loadFolders() {
  const foldersList = document.getElementById('foldersList');
  foldersList.innerHTML = '';

  try {
    // Проверка доступности директории
    await fs.access(currentDir);
    const items = await fs.readdir(currentDir, { withFileTypes: true });
    const folders = items.filter((item) => item.isDirectory());

    if (folders.length === 0) {
      foldersList.innerHTML = '<p>Папок не найдено</p>';
    } else {
      folders.forEach((folder) => {
        const folderDiv = document.createElement('div');
        folderDiv.textContent = folder.name;
        folderDiv.classList.add('draggable');
        folderDiv.setAttribute('data-type', 'folder');
        folderDiv.addEventListener('click', () => openFolder(folder.name));
        folderDiv.addEventListener('contextmenu', (e) => showContextMenu(e, folder.name, 'folder'));

        foldersList.appendChild(folderDiv);
      });
    }

    displayInfo(`Загружены папки: ${folders.length}`);
    initializeContextMenu();
  } catch (err) {
    console.error('Ошибка загрузки папок:', err);
    foldersList.innerHTML = '<p>Папки не найдены или текущая директория недоступна.</p>';
  }
}

async function loadFiles(folderPath) {
  const filesList = document.getElementById('filesList'); // Список файлов в текущей панели
  filesList.innerHTML = ''; // Очищаем содержимое перед обновлением

  try {
    const items = await fs.readdir(folderPath, { withFileTypes: true });
    const files = items.filter((item) => item.isFile()); // Фильтруем только файлы

    if (files.length === 0) {
      filesList.innerHTML = '<p>Папка пуста</p>'; // Отображаем сообщение, если нет файлов
    } else {
      files.forEach((file) => {
        const fileDiv = document.createElement('div');
        fileDiv.textContent = file.name;
        fileDiv.classList.add('draggable'); // Добавляем класс для обработки
        fileDiv.setAttribute('data-type', 'file');

        // Добавляем обработку событий клика и контекстного меню
        fileDiv.addEventListener('click', () => {
          displayInfo(`Выбран файл: ${file.name}`);
        });

        fileDiv.addEventListener('contextmenu', (e) => {
          showContextMenu(e, file.name, 'file');
        });

        filesList.appendChild(fileDiv); // Добавляем элемент в список
      });
    }

    displayInfo(`Загружено файлов: ${files.length}`);
    initializeContextMenu(); // Подключаем контекстное меню для новых файлов
  } catch (err) {
    console.error('Ошибка загрузки файлов:', err);
    displayInfo('Не удалось загрузить файлы.');
  }
}

// --- ФУНКЦИИ НАСТРОЕК ---

// Функция загрузки настроек из settings.json
async function loadSettings() {
  try {
    const data = await fs.readFile('settings.json', 'utf8');
    const parsedData = JSON.parse(data);

    currentDir = parsedData.currentDir || currentDir;
    filePanelWidth = parsedData.filePanelWidth || filePanelWidth;
    folderContentPanelWidth = parsedData.folderContentPanelWidth || folderContentPanelWidth;
    trashPanelWidth = parsedData.trashPanelWidth || trashPanelWidth;
    isDarkMode = parsedData.isDarkMode || isDarkMode;

    if (parsedData.confirmDeletion !== undefined) {
      confirmDeletion = parsedData.confirmDeletion;
    }

    if (parsedData.syncOptions) {
      syncOptions = parsedData.syncOptions;
    }

    if (isDarkMode) {
      document.body.classList.add('dark-mode');
    }
  } catch (err) {
    console.error('Не удалось загрузить настройки:', err);
  }
}

// Функция сохранения текущих настроек в settings.json
async function saveSettings() {
  const settings = {
    currentDir,
    filePanelWidth,
    folderContentPanelWidth,
    trashPanelWidth,
    isDarkMode,
    confirmDeletion,
    syncOptions,
  };

  try {
    await fs.writeFile('settings.json', JSON.stringify(settings, null, 2));
  } catch (err) {
    console.error('Не удалось сохранить настройки:', err);
  }
}

// --- ФУНКЦИИ ДЛЯ FTP-ПОДКЛЮЧЕНИЙ ---

// Подключение к FTP с безопасным доступом
async function safelyConnectToFtp(connection) {
  const client = new ftp.Client(); // Создаём новый объект FTP-клиента
  client.ftp.verbose = true; // Отладочный режим FTP
  try {
    await client.access({
      host: connection.host,
      port: connection.port,
      user: connection.user,
      password: connection.password,
      secure: false, // Используйте secure: true для защищённых соединений
    });
    return client;
  } catch (err) {
    console.error('Ошибка подключения к FTP:', err);
    displayInfo('Ошибка подключения к FTP: ' + err.message);
    return null;
  }
}

// Безопасное закрытие FTP-соединения
async function safelyCloseFtp(client) {
  if (client) {
    try {
      client.close();
    } catch (err) {
      console.error('Ошибка закрытия FTP-соединения:', err);
    }
  }
}

// Синхронизация файлов
async function synchronizeFiles() {
  if (!currentFtpConnection) {
    displayInfo('Нет активного FTP-подключения для синхронизации.');
    return;
  }

  const client = await safelyConnectToFtp(currentFtpConnection);

  if (!client) {
    displayInfo('Не удалось подключиться к FTP.');
    return;
  }

  try {
    const tasks = []; // Лист задач для многопоточности FTP-операций
    for (const file of filesForSync) {
      const remotePath = path.join(currentFtpConnection.remoteDir, file.name);
      const localStats = await fs.stat(file.path).catch(() => null);

      try {
        const remoteStats = await client.size(remotePath); // Получаем размер удалённого файла
        if (localStats && localStats.mtimeMs > remoteStats) {
          tasks.push({ type: 'upload', localPath: file.path, remotePath });
        } else if (localStats && localStats.mtimeMs < remoteStats) {
          tasks.push({ type: 'download', localPath: file.path, remotePath });
        }
      } catch {
        // Если файл отсутствует на сервере
        tasks.push({ type: 'upload', localPath: file.path, remotePath });
      }
    }

    await processSyncTasks(client, tasks); // Выполняем задачи синхронизации
    displayInfo('Синхронизация завершена!');
  } catch (err) {
    console.error('Ошибка синхронизации файлов:', err);
    displayInfo('Ошибка синхронизации.');
  } finally {
    await safelyCloseFtp(client);
  }
}

// Управление задачами синхронизации (многопоточность)
async function processSyncTasks(client, tasks, maxConcurrency = 5) {
  const queue = tasks.slice(); // Создаём копию очереди задач

  async function worker() {
    while (queue.length > 0) {
      const task = queue.shift(); // Удаляем задачу из очереди
      try {
        if (task.type === 'upload') {
          await client.uploadFrom(task.localPath, task.remotePath);
        } else if (task.type === 'download') {
          await client.downloadTo(task.localPath, task.remotePath);
        }
      } catch (err) {
        console.error('Ошибка задачи синхронизации:', err);
      }
    }
  }

  const workers = Array.from({ length: maxConcurrency }, () => worker());
  await Promise.all(workers); // Дождаться выполнения всех потоков
}

// --- ОБРАБОТКА ДИСКОВ И ПАПОК ---

async function deleteFromFileSystem(itemPath) {
  try {
    await fs.rm(itemPath, { recursive: true, force: true });
    displayInfo(`Элемент "${path.basename(itemPath)}" успешно удалён.`);
  } catch (err) {
    console.error('Ошибка удаления:', err);
    displayInfo(`Ошибка удаления ${path.basename(itemPath)}.`);
  }
}

// --- ОБНОВЛЕНИЕ ИНТЕРФЕЙСА И ДАННЫХ ---

function displayInfo(message) {
  messageQueue.push(message);
  processQueue();
}

function processQueue() {
  if (messageQueue.length === 0) return;

  const infoDisplay = document.getElementById('infoDisplay');
  if (infoDisplay.textContent === '') {
    const message = messageQueue.shift();
    infoDisplay.textContent = message;

    setTimeout(() => {
      infoDisplay.textContent = '';
      processQueue();
    }, 5000);
  }
}

async function refreshUI() {
  try {
    await loadFolders();

    const currentFolder = document.getElementById('folderContentPanel').getAttribute('data-current-folder');

    if (currentFolder) {
      const folderPath = path.join(currentDir, currentFolder);
      try {
        await loadFiles(folderPath); // Загрузка файлов в выбранной папке
      } catch (err) {
        console.warn(`Ошибка доступа к папке ${currentFolder}:`, err);

        document.getElementById('folderContentPanel').classList.add('hidden');
        document.getElementById('folderContentPanel').removeAttribute('data-current-folder');
      }
    }

    await loadTrash(); // Загрузка корзины

    updateSyncIndicators(); // Обновление синхронизации (визуальные индикаторы)
    initializeContextMenu(); // Подключаем контекстное меню ко всем элементам
    displayInfo('Интерфейс обновлён.');
  } catch (err) {
    console.error('Ошибка обновления интерфейса:', err);
    displayInfo('Ошибка загрузки интерфейса.');
  }
}

function updateSyncIndicators() {
  const folders = document.querySelectorAll('#foldersList .draggable');
  const files = document.querySelectorAll('#filesList .draggable');

  folders.forEach((folder) => {
    const folderPath = path.join(currentDir, folder.textContent);
    const isSynced = filesForSync.some((file) => file.path === folderPath);
    folder.classList.toggle('synced', isSynced);
    folder.classList.toggle('unsynced', !isSynced);
  });

  files.forEach((file) => {
    const currentFolder = document.getElementById('folderContentPanel').dataset.currentFolder;
    const filePath = path.join(currentDir, currentFolder || '', file.textContent);
    const isSynced = filesForSync.some((file) => file.path === filePath);
    file.classList.toggle('synced', isSynced);
    file.classList.toggle('unsynced', !isSynced);
  });
}

// --- УПРАВЛЕНИЕ ОБНОВЛЕНИЕМ ДАННЫХ В ПРИЛОЖЕНИИ ---

async function loadSaveData() {
  try {
    const data = await fs.readFile('save.json', 'utf8');
    return JSON.parse(data) || { folders: [], files: [], trash: [], syncFiles: [] };
  } catch (err) {
    if (err.code === 'ENOENT') {
      await saveSaveData({ folders: [], files: [], trash: [], syncFiles: [] });
      return { folders: [], files: [], trash: [], syncFiles: [] };
    } else {
      console.error('Не удалось загрузить данные сохранения:', err);
      throw err;
    }
  }
}

async function saveSaveData(data) {
  try {
    await fs.writeFile('save.json', JSON.stringify(data, null, 2));
    displayInfo('Данные сохранены.');
  } catch (err) {
    console.error('Не удалось сохранить данные:', err);
    displayInfo('Ошибка сохранения данных.');
  }
}

// --- ДОРАБОТКИ РАБОТЫ С FTP-ФАЙЛАМИ ---

async function uploadFile(client, localPath, remotePath) {
  try {
    await client.uploadFrom(localPath, remotePath);
    displayInfo(`Файл "${path.basename(localPath)}" успешно загружен на сервер.`);
  } catch (err) {
    console.error(`Ошибка загрузки файла "${localPath}":`, err);
    displayInfo(`Ошибка загрузки файла "${path.basename(localPath)}".`);
  }
}

async function downloadFile(client, remotePath, localPath) {
  try {
    await client.downloadTo(localPath, remotePath);
    displayInfo(`Файл "${path.basename(remotePath)}" успешно загружен с сервера.`);
  } catch (err) {
    console.error(`Ошибка загрузки файла "${remotePath}":`, err);
    displayInfo(`Ошибка загрузки файла "${path.basename(remotePath)}".`);
  }
}

// --- УСТАНОВКА НАБЛЮДАТЕЛЯ ЗА ФАЙЛАМИ ---

function startFileWatcher() {
  if (!syncOptions.syncOnChanges) return;

  fileWatcher = fs.watch(currentDir, { recursive: true }, async (eventType, filename) => {
    const filePath = path.join(currentDir, filename);
    const isSynced = filesForSync.some((file) => file.path === filePath);

    if (!isSynced) return;

    if (fileChangeTimeouts.has(filePath)) {
      clearTimeout(fileChangeTimeouts.get(filePath));
    }

    fileChangeTimeouts.set(
      filePath,
      setTimeout(async () => {
        fileChangeTimeouts.delete(filePath);
        const client = await safelyConnectToFtp(currentFtpConnection);

        if (client) {
          try {
            const remotePath = path.join(currentFtpConnection.remoteDir, filename);
            if (eventType === 'rename') {
              try {
                await fs.stat(filePath);
                await uploadFile(client, filePath, remotePath);
              } catch {
                await client.remove(remotePath);
              }
            } else if (eventType === 'change') {
              await uploadFile(client, filePath, remotePath);
            }
            displayInfo(`Файл "${filename}" успешно синхронизирован.`);
          } catch (err) {
            console.error(`Ошибка синхронизации файла "${filename}":`, err);
          } finally {
            await safelyCloseFtp(client);
          }
        }
      }, 300)
    );
  });

  displayInfo('Файловое наблюдение включено.');
}

// --- ЗАГРУЗКА НАСТРОЕК ПРИ СТАРТЕ ПРИЛОЖЕНИЯ ---

document.addEventListener('DOMContentLoaded', async () => {
  try {
    // Загружаем настройки из settings.json (например, текущую директорию, ширину панелей, тему и пр.)
    await loadSettings();

    // Устанавливаем начальные размеры
    const filePanel = document.getElementById('filePanel');
    const folderContentPanel = document.getElementById('folderContentPanel');
    const trashPanel = document.getElementById('trashPanel');

    filePanel.style.width = `${filePanelWidth || 300}px`;
    folderContentPanel.style.width = `${folderContentPanelWidth || 300}px`;
    trashPanel.style.width = `${trashPanelWidth || 300}px`;

    // Обновляем ширину третьей панели
    updateThirdPanelWidth();

    // Привязываем обработку ресайзеров
    const gutter1 = document.getElementById('resizer1');
    const gutter2 = document.getElementById('resizer2');
    const gutter3 = document.getElementById('resizer3');

    resizer(gutter1, filePanel, 100, 900);
    resizer(gutter2, folderContentPanel, 100, 900);
    resizer(gutter3, trashPanel, 100, 900);

    displayInfo('Приложение запущено.');
    // Обновляем пользовательский интерфейс
    await refreshUI();
    // Показываем панель файлов

    // Загружаем список файлов/папок для синхронизации из save.json
    const saveData = await loadSaveData();
    if (saveData.syncFiles) {
      filesForSync = saveData.syncFiles.map((file) => ({
        path: file.path,
        type: file.type,
        name: file.name,
      }));
      updateSyncIndicators(); // Обновляем индикаторы синхронизации
    }

    // Если активирована синхронизация при старте (из настроек)
    if (syncOptions.syncOnStart) {
      displayInfo('Запуск автоматической синхронизации при старте...');
      if (currentFtpConnection) {
        await synchronizeFiles(); // Выполняем синхронизацию с FTP
      } else {
        displayInfo('Нет активного FTP-подключения. Синхронизация не выполнена.');
      }
    }

    // Настройка интервала синхронизации (если задан)
    if (syncOptions.syncInterval) {
      displayInfo(`Запуск интервала синхронизации каждые ${syncOptions.syncInterval} минут...`);
      startSyncInterval(syncOptions.syncInterval); // Активируем таймер синхронизации
    }

    // Включение автоматического отслеживания изменений файлов
    if (syncOptions.syncOnChanges) {
      displayInfo('Настроено наблюдение за изменениями файлов...');
      startFileWatcher(); // Наблюдаем за изменениями в текущей директории
    }

    // Сообщение о запуске приложения
    displayInfo('Приложение успешно запущено.');
  } catch (err) {
    // Обрабатываем все ошибки, возникшие при загрузке приложения
    console.error('Ошибка при запуске приложения:', err);
    displayInfo('Ошибка при запуске приложения. Проверьте настройки.');
  }
});

// --- СИНХРОНИЗАЦИЯ ПО ТАЙМЕРУ ---

let syncIntervalId = null;

function startSyncInterval(intervalMinutes) {
  if (syncIntervalId) clearInterval(syncIntervalId); // Удаляем предыдущий интервал

  syncIntervalId = setInterval(async () => {
    if (!currentFtpConnection) {
      displayInfo('Нет активного FTP-подключения для интервала синхронизации.');
      return;
    }

    displayInfo('Запущена синхронизация по таймеру...');
    await synchronizeFiles(); // Выполняем синхронизацию по интервалу
  }, intervalMinutes * 60 * 1000);

  displayInfo(`Синхронизация каждые ${intervalMinutes} минут настроена.`);
}

function stopSyncInterval() {
  if (syncIntervalId) {
    clearInterval(syncIntervalId);
    syncIntervalId = null;
    displayInfo('Интервал синхронизации остановлен.');
  }
}

// --- УПРАВЛЕНИЕ СИНХРОННИЗИРУЕМЫМИ ОБЪЕКТАМИ (ФАЙЛЫ, ПАПКИ) ---

function toggleSyncStatus(itemPath, itemType, itemElement) {
  if (!itemPath || !itemType) {
    console.error('Отсутствует атрибут itemPath или itemType. Не удалось переключить статус синхронизации.');
    return;
  }

  const isSynced = filesForSync.some((file) => file.path === itemPath);

  if (isSynced) {
    filesForSync = filesForSync.filter((file) => file.path !== itemPath);
    itemElement.classList.remove('synced');
    itemElement.classList.add('unsynced');
    displayInfo(`${itemType} "${itemPath}" удалено из синхронизации.`);
  } else {
    filesForSync.push({ path: itemPath, type: itemType, name: path.basename(itemPath) });
    itemElement.classList.remove('unsynced');
    itemElement.classList.add('synced');
    displayInfo(`${itemType} "${itemPath}" добавлено в синхронизацию.`);
  }

  saveSyncData();
}

// Сохранение списка файлов/папок для синхронизации
async function saveSyncData() {
  let saveData = await loadSaveData();
  saveData.syncFiles = filesForSync.map((file) => ({
    path: file.path,
    type: file.type,
    name: file.name,
  }));

  try {
    await saveSaveData(saveData);
    displayInfo('Обновлён список файлов синхронизации.');
  } catch (err) {
    console.error('Ошибка сохранения списка файлов синхронизации:', err);
    displayInfo('Ошибка сохранения списка синхронизации.');
  }
}

// --- ОЧИСТКА РЕСУРСОВ ПРИ ЗАВЕРШЕНИИ ---

function cleanUpResources() {
  stopSyncInterval();

  if (fileWatcher) {
    fileWatcher.close();
    fileWatcher = null;
  }

  displayInfo('Закрыты все ресурсы. Завершение приложения.');
}

// Событие при закрытии окна/приложения
window.addEventListener('beforeunload', cleanUpResources);

// --- Показ настроек синхронизации FTP ---
document.getElementById('openSyncSettingsBtn').addEventListener('click', () => {
  document.getElementById('syncSettingsDialog').classList.remove('hidden'); // Открываем диалог настроек
});

document.getElementById('createFolderBtn').addEventListener('click', createFolder);
document.getElementById('createFileBtn').addEventListener('click', createFile);

// --- Закрытие настроек синхронизации ---
document.getElementById('closeSyncSettingsBtn').addEventListener('click', () => {
  document.getElementById('syncSettingsDialog').classList.add('hidden'); // Скрываем диалог
});

// --- Сохранение текущих настроек FTP ---
document.getElementById('saveFtpSettingsBtn').addEventListener('click', saveCurrentFtpConnection);

// --- Добавление нового FTP-подключения ---
document.getElementById('addFtpConnectionBtn').addEventListener('click', () => {
  const newConnection = { host: '', port: '21', user: '', password: '', remoteDir: '/' };
  ftpConnections.push(newConnection); // Добавляем новое подключение
  updateFtpConnectionList(); // Обновляем интерфейс списка подключений
  const lastIndex = ftpConnections.length - 1;
  document.getElementById('ftpConnections').value = lastIndex;
  populateFtpConnectionFields(newConnection); // Устанавливаем его для редактирования
});

// --- Выбор подключения в списке FTP-подключений ---
document.getElementById('ftpConnections').addEventListener('change', (e) => {
  const selectedIndex = e.target.value;
  currentFtpConnection = ftpConnections[selectedIndex]; // Устанавливаем выбранное подключение
  populateFtpConnectionFields(currentFtpConnection); // Отображаем его параметры в форму
});

// --- Ручная синхронизация при нажатии кнопки ---
document.getElementById('toggleSyncBtn').addEventListener('click', async () => {
  if (!currentFtpConnection) {
    return displayInfo('Выберите подключение FTP для начала синхронизации.');
  }

  displayInfo('Ручная синхронизация начата...');
  await synchronizeFiles(); // Запуск синхронизации
});

// --- Тема: переключение между светлой и тёмной ---
document.getElementById('toggleThemeBtn').addEventListener('click', async () => {
  isDarkMode = !isDarkMode;
  document.body.classList.toggle('dark-mode', isDarkMode);
  await saveSettings(); // Сохранение настроек режима
  displayInfo(`Тёмный режим ${isDarkMode ? 'включён' : 'выключен'}.`);
});

// --- Переключение обороны подтверждений удаления ---
document.getElementById('toggleConfirmationsBtn').addEventListener('click', async () => {
  confirmDeletion = !confirmDeletion;
  await saveSettings(); // Сохранение состояния
  displayInfo(`Подтверждение удаления ${confirmDeletion ? 'включено' : 'выключено'}.`);
});

// --- Открытие файлового диалога для выбора директории ---
document.getElementById('selectDirBtn').addEventListener('click', async () => {
  const fileInput = document.createElement('input');
  fileInput.type = 'file';
  fileInput.setAttribute('nwdirectory', true); // Делаем выбор папки

  fileInput.addEventListener('change', async () => {
    if (fileInput.files.length > 0) {
      currentDir = fileInput.files[0].path; // Обновляем текущую директорию
      await saveSettings(); // Сохраняем текущую директорию в настройки
      await refreshUI(); // Перезагружаем интерфейс
      displayInfo(`Выбрана директория: ${currentDir}`);
    }
  });

  fileInput.click(); // Эмуляция нажатия на поле выбора
});

// Показать/скрыть панель для файлов (filePanel)
document.getElementById('toggleFilesBtn').addEventListener('click', () => {
  const filePanel = document.getElementById('filePanel');
  const folderContentPanel = document.getElementById('folderContentPanel');
  const resizer1 = document.getElementById('resizer1');
  const resizer2 = document.getElementById('resizer2');

  if (filePanel.classList.contains('hidden')) {
    // Если панель скрыта, показываем её
    filePanel.classList.remove('hidden');
    resizer1.classList.remove('hidden');

    // Если панель содержимого папки ранее скрыта, показываем
    if (folderContentPanel.dataset.openWhenHidden === 'true') {
      folderContentPanel.classList.remove('hidden');
      resizer2.classList.remove('hidden');
    }
  } else {
    // Если панель видима, скрываем её
    filePanel.classList.add('hidden');
    resizer1.classList.add('hidden');

    // Скрываем панель содержимого папки, если она открыта
    if (!folderContentPanel.classList.contains('hidden')) {
      folderContentPanel.dataset.openWhenHidden = 'true';
      folderContentPanel.classList.add('hidden');
      resizer2.classList.add('hidden');
    } else {
      folderContentPanel.dataset.openWhenHidden = 'false';
    }
  }

  updateThirdPanelWidth(); // Обновляем ширину третьей панели
});

// Показать/скрыть панель для корзины (trashPanel)
document.getElementById('toggleTrashBtn').addEventListener('click', async () => {
  const trashPanel = document.getElementById('trashPanel');
  const resizer3 = document.getElementById('resizer3');

  if (trashPanel.classList.contains('hidden')) {
    // Если панель скрыта, показываем её
    trashPanel.classList.remove('hidden');
    resizer3.classList.remove('hidden');

    // Загружаем содержимое корзины
    await loadTrash();
  } else {
    // Если панель видима, скрываем её
    trashPanel.classList.add('hidden');
    resizer3.classList.add('hidden');
  }

  updateThirdPanelWidth(); // Обновляем ширину третьей панели
});
// --- РЕДАКТИРОВАНИЕ FTP-ПОДКЛЮЧЕНИЙ ---

// Поля для отображения текущего подключения
function populateFtpConnectionFields(connection) {
  document.getElementById('ftpHostInput').value = connection.host || '';
  document.getElementById('ftpPortInput').value = connection.port || '21';
  document.getElementById('ftpUserInput').value = connection.user || '';
  document.getElementById('ftpPasswordInput').value = connection.password || '';
  document.getElementById('remoteDirInput').value = connection.remoteDir || '/';
}

// Сохранение текущего подключения
async function saveCurrentFtpConnection() {
  if (!currentFtpConnection) {
    displayInfo('Нет активного подключения для сохранения.');
    return;
  }

  const host = document.getElementById('ftpHostInput').value.trim();
  const port = parseInt(document.getElementById('ftpPortInput').value, 10);

  if (!host) {
    displayInfo('Хост не может быть пустым.');
    return;
  }

  if (isNaN(port) || port <= 0) {
    displayInfo('Введите корректный номер порта.');
    return;
  }

  currentFtpConnection.host = host;
  currentFtpConnection.port = port;
  currentFtpConnection.user = document.getElementById('ftpUserInput').value;
  currentFtpConnection.password = document.getElementById('ftpPasswordInput').value;
  currentFtpConnection.remoteDir = document.getElementById('remoteDirInput').value;

  updateFtpConnectionList();
  await saveSettings();
  displayInfo('Настройки текущего подключения FTP успешно сохранены.');
}

// Обновление выпадающего списка доступных FTP-подключений
function updateFtpConnectionList() {
  const dropdown = document.getElementById('ftpConnections');
  dropdown.innerHTML = '';

  ftpConnections.forEach((connection, index) => {
    const option = document.createElement('option');
    option.value = index;
    option.textContent = `${connection.host}:${connection.port}`;
    dropdown.appendChild(option);
  });

  if (ftpConnections.length > 0) {
    currentFtpConnection = ftpConnections[0];
    dropdown.value = 0;
    populateFtpConnectionFields(currentFtpConnection);
  }
}

// --- РАБОТА С КОНФЛИКТАМИ ---

// Отображение диалогового окна с конфликтами
function showFileConflictDialog(conflicts) {
  const conflictTableBody = document.getElementById('conflictTable');
  conflictTableBody.innerHTML = '';

  conflicts.forEach((conflict) => {
    const row = document.createElement('tr');

    row.innerHTML = `
      <td>${path.basename(conflict.filePath)}</td>
      <td>${conflict.local.size} bytes (изменено: ${new Date(conflict.local.mtime).toLocaleString()})</td>
      <td>${conflict.remote.size} bytes (изменено: ${new Date(conflict.remote.mtime).toLocaleString()})</td>
      <td>
        <button data-action="local" data-path="${conflict.filePath}">Сохранить локальный</button>
        <button data-action="remote" data-path="${conflict.remotePath}">Сохранить удалённый</button>
      </td>
    `;

    conflictTableBody.appendChild(row);
  });

  const dialog = document.getElementById('fileConflictDialog');
  dialog.classList.remove('hidden');

  // Обработка выбора пользователя
  document.getElementById('resolveConflictsBtn').onclick = async () => {
    const client = await safelyConnectToFtp(currentFtpConnection);
    if (!client) return;

    try {
      const rows = document.querySelectorAll('#conflictTable tr');
      for (const row of rows) {
        const selectedButton = row.querySelector('button.selected');
        if (!selectedButton) continue;

        const action = selectedButton.getAttribute('data-action');
        const filePath = selectedButton.getAttribute('data-path');

        if (action === 'local') {
          const remotePath = path.join(currentFtpConnection.remoteDir, path.basename(filePath));
          await uploadFile(client, filePath, remotePath);
        } else if (action === 'remote') {
          const remotePath = path.join(currentFtpConnection.remoteDir, path.basename(filePath));
          await downloadFile(client, remotePath, filePath);
        }
      }

      displayInfo('Все конфликты успешно разрешены.');
    } catch (err) {
      console.error('Ошибка разрешения конфликтов:', err);
      displayInfo('Ошибка разрешения конфликтов.');
    } finally {
      client.close();
      dialog.classList.add('hidden');
      await refreshUI();
    }
  };
}

// Визуальное выделение выбранного варианта в диалоге конфликта
document.addEventListener('click', (e) => {
  if (e.target.matches("button[data-action='local'], button[data-action='remote']")) {
    const buttons = e.target.closest('td').querySelectorAll('button');
    buttons.forEach((btn) => btn.classList.remove('selected'));
    e.target.classList.add('selected');
  }
});



settings.json:
{
  "currentDir": "D:\\Downloads\\sdsdsdsd",
  "filePanelWidth": 900,
  "folderContentPanelWidth": 376.8500061035156,
  "isDarkMode": false,
  "confirmDeletion": false,
  "syncOptions": {
    "syncOnStart": false,
    "syncOnChanges": false,
    "syncInterval": null
  }
}

save.json:
{
  "folders": [
    {
      "name": "ввв",
      "path": "D:\\Downloads\\sdsdsdsd\\ввв"
    },
    {
      "name": "всааа",
      "path": "D:\\Downloads\\sdsdsdsd\\всааа"
    }
  ],
  "files": [
    {
      "name": "sscscs",
      "path": "D:\\Downloads\\sdsdsdsd\\всааа\\sscscs"
    }
  ],
  "trash": [],
  "syncFiles": []
}

Оптимизируй все, что связанно с слушателями событий. Напиши что добавить и что удалить из кода