import path from 'path';
import { app, ipcMain } from 'electron';
import fs from 'fs';
import https from 'https';
import extract from 'extract-zip';
import { launch, Version, diagnose } from '@xmcl/core';
import { execSync } from 'child_process';
import {
  installDependencies,
  installFabric,
  getFabricLoaders,
  getVersionList,
  install,
  installTask,
  installDependenciesTask,
} from '@xmcl/installer';
import { Dispatcher, Agent } from 'undici';
import { spawn } from 'child_process';
import { AuthService } from './auth-service';
import { API_BASE_URL } from '../renderer/api';

// const CDN = 'https://cdn.minecraft.popa-popa.ru';

// const DOWNLOAD_OPTIONS = {
//   // assets (objects/)
//   assetsHost: `${CDN}/assets/objects`,

//   // библиотеки (jar'ы)
//   libraryHost(library: { path: any }) {
//     return `${CDN}/libraries/${library.path}`;
//   },

//   assetsIndexUrl: (version: any) =>
//     `${CDN}/assets/indexes/${version.assetIndex.id}.json`,

//   // версии
//   json(versionInfo: { id: any }) {
//     return `${CDN}/versions/${versionInfo.id}/${versionInfo.id}.json`;
//   },
//   client(resolved: { id: any }) {
//     return `${CDN}/versions/${resolved.id}/${resolved.id}.jar`;
//   },
// };

const INSTALL_PHASES = [
  { id: 'download', weight: 0.25 }, // 25% — скачивание сборки
  { id: 'minecraft-install', weight: 0.3 }, // 30% — ваниль
  { id: 'fabric-install', weight: 0.15 }, // 15% — Fabric
  { id: 'dependencies', weight: 0.25 }, // 25% — библиотеки/ресурсы
  { id: 'launch', weight: 0.05 }, // 5% — запуск
] as const;

type InstallPhaseId = (typeof INSTALL_PHASES)[number]['id'];

function getGlobalProgress(phaseId: InstallPhaseId, localProgress01: number) {
  let offset = 0;
  let weight = 0;

  for (const phase of INSTALL_PHASES) {
    if (phase.id === phaseId) {
      weight = phase.weight;
      break;
    }
    offset += phase.weight;
  }

  if (!weight) return 100;

  const clampedLocal = Math.max(0, Math.min(1, localProgress01));
  const global = (offset + clampedLocal * weight) * 100;

  return Math.round(Math.max(0, Math.min(global, 100)));
}

// Константы
const AUTHLIB_INJECTOR_FILENAME = 'authlib-injector-1.2.5.jar';
const MCSTATUS_API_URL = 'https://api.mcstatus.io/v2/status/java/';

// Создаем экземпляр сервиса аутентификации
const authService = new AuthService();

const agent = new Agent({
  connections: 16, // максимум 16 одновременных соединений (скачиваний)
  // тут можно задать и другие параметры при необходимости
});

let currentMinecraftProcess: any | null = null;

// Модифицированная функция для получения последней версии релиза с произвольного URL
export async function getLatestReleaseVersion(apiUrl: string): Promise<string> {
  try {
    const response = await fetch(apiUrl);
    const data = await response.json();
    return data.tag_name || '0.0.0';
  } catch (error) {
    console.error('Failed to fetch latest version:', error);
    return '0.0.0';
  }
}

// Функция для загрузки файла
export async function downloadFile(
  url: string,
  dest: string,
  progressCallback: (progress: number) => void,
): Promise<void> {
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(dest);
    let downloadedSize = 0;
    let totalSize = 0;
    let redirectCount = 0;

    const makeRequest = (requestUrl: string) => {
      https
        .get(requestUrl, (response) => {
          // Обрабатываем редиректы
          if (response.statusCode === 301 || response.statusCode === 302) {
            if (redirectCount++ > 5) {
              reject(new Error('Too many redirects'));
              return;
            }
            makeRequest(response.headers.location!);
            return;
          }

          if (response.statusCode !== 200) {
            reject(new Error(`Server returned ${response.statusCode}`));
            return;
          }

          totalSize = parseInt(response.headers['content-length'] || '0', 10);

          response.on('data', (chunk) => {
            downloadedSize += chunk.length;
            const progress = Math.round((downloadedSize / totalSize) * 100);
            progressCallback(progress);
          });

          response.pipe(file);

          file.on('finish', () => {
            file.close();
            // Проверяем, что файл скачан полностью
            if (downloadedSize !== totalSize && totalSize > 0) {
              fs.unlink(dest, () => {
                reject(new Error('File download incomplete'));
              });
              return;
            }
            resolve();
          });
        })
        .on('error', (err) => {
          fs.unlink(dest, () => reject(err));
        });
    };

    makeRequest(url);
  });
}

// Добавим функцию для определения версии Java
export async function getJavaVersion(
  javaPath: string,
): Promise<{ version: string; majorVersion: number }> {
  return new Promise((resolve, reject) => {
    const process = spawn(javaPath, ['-version']);
    let output = '';

    process.stderr.on('data', (data) => {
      output += data.toString();
    });

    process.on('close', (code) => {
      if (code === 0) {
        // Извлекаем версию из вывода (например, "java version "1.8.0_291"")
        const versionMatch = output.match(/version "([^"]+)"/);
        if (versionMatch) {
          const version = versionMatch[1];
          // Определяем major версию
          let majorVersion = 8; // По умолчанию предполагаем Java 8

          if (version.startsWith('1.8')) {
            majorVersion = 8;
          } else if (version.match(/^(9|10|11|12|13|14|15|16)/)) {
            majorVersion = parseInt(version.split('.')[0], 10);
          } else if (version.match(/^1\.(9|10|11|12|13|14|15|16)/)) {
            majorVersion = parseInt(version.split('.')[1], 10);
          } else if (version.match(/^([0-9]+)/)) {
            majorVersion = parseInt(version.match(/^([0-9]+)/)?.[1] || '0', 10);
          }

          resolve({ version, majorVersion });
        } else {
          reject(new Error('Unable to parse Java version'));
        }
      } else {
        reject(new Error(`Java process exited with code ${code}`));
      }
    });
  });
}

// Модифицируем функцию findJava, чтобы она находила все версии Java и определяла их версии
export async function findJavaVersions(): Promise<
  Array<{ path: string; version: string; majorVersion: number }>
> {
  const javaPaths: string[] = [];
  const results: Array<{
    path: string;
    version: string;
    majorVersion: number;
  }> = [];

  try {
    // 1. Сначала проверяем переменную JAVA_HOME
    if (process.env.JAVA_HOME) {
      const javaPath = path.join(
        process.env.JAVA_HOME,
        'bin',
        'java' + (process.platform === 'win32' ? '.exe' : ''),
      );
      if (fs.existsSync(javaPath)) {
        javaPaths.push(javaPath);
      }
    }

    // 2. Проверяем стандартные пути установки в зависимости от платформы
    const checkPaths: string[] = [];

    if (process.platform === 'win32') {
      // Windows
      const programFiles = process.env['ProgramFiles'] || 'C:\\Program Files';
      const programFilesX86 =
        process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)';

      // JDK пути
      [
        'Java',
        'AdoptOpenJDK',
        'Eclipse Adoptium',
        'BellSoft',
        'Zulu',
        'Amazon Corretto',
        'Microsoft',
      ].forEach((vendor) => {
        checkPaths.push(path.join(programFiles, vendor));
        checkPaths.push(path.join(programFilesX86, vendor));
      });
    } else if (process.platform === 'darwin') {
      // macOS
      checkPaths.push('/Library/Java/JavaVirtualMachines');
      checkPaths.push('/System/Library/Java/JavaVirtualMachines');
      checkPaths.push('/usr/libexec/java_home');
    } else {
      // Linux
      checkPaths.push('/usr/lib/jvm');
      checkPaths.push('/usr/java');
      checkPaths.push('/opt/java');
    }

    // Проверяем каждый путь
    for (const basePath of checkPaths) {
      if (fs.existsSync(basePath)) {
        try {
          // Находим подпапки с JDK/JRE
          const entries = fs.readdirSync(basePath, { withFileTypes: true });
          for (const entry of entries) {
            if (entry.isDirectory()) {
              // Проверяем наличие исполняемого файла java в bin
              const javaPath = path.join(
                basePath,
                entry.name,
                'bin',
                'java' + (process.platform === 'win32' ? '.exe' : ''),
              );

              if (fs.existsSync(javaPath)) {
                javaPaths.push(javaPath);
              }
            }
          }
        } catch (err) {
          console.error(`Ошибка при сканировании ${basePath}:`, err);
        }
      }
    }

    // 3. Пробуем найти java в PATH через команду which/where
    try {
      const command =
        process.platform === 'win32' ? 'where java' : 'which java';
      const javaPathFromCmd = execSync(command).toString().trim().split('\n');

      javaPathFromCmd.forEach((path) => {
        if (path && fs.existsSync(path) && !javaPaths.includes(path)) {
          javaPaths.push(path);
        }
      });
    } catch (err) {
      console.error('Ошибка при поиске java через PATH:', err);
    }

    // Получаем информацию о версиях найденных Java
    for (const javaPath of javaPaths) {
      try {
        const versionInfo = await getJavaVersion(javaPath);
        results.push({
          path: javaPath,
          version: versionInfo.version,
          majorVersion: versionInfo.majorVersion,
        });
      } catch (err) {
        console.error(`Ошибка при определении версии для ${javaPath}:`, err);
      }
    }

    // Сортируем результаты по majorVersion (от меньшей к большей)
    return results.sort((a, b) => a.majorVersion - b.majorVersion);
  } catch (error) {
    console.error('Ошибка при поиске версий Java:', error);
    return results;
  }
}

// Обновим функцию findJava для использования Java 8
export async function findJava(): Promise<string> {
  try {
    console.log('Поиск доступных версий Java...');

    const javaVersions = await findJavaVersions();

    if (javaVersions.length === 0) {
      throw new Error('Java не найдена. Установите Java и повторите попытку.');
    }

    console.log('Найденные версии Java:');
    javaVersions.forEach((java) => {
      console.log(
        `- Java ${java.majorVersion} (${java.version}) по пути: ${java.path}`,
      );
    });

    // Предпочитаем Java 21 или 17 для совместимости с authlib-injector
    const preferredVersions = [24, 21, 17, 11];

    for (const preferredVersion of preferredVersions) {
      const preferred = javaVersions.find(
        (java) => java.majorVersion === preferredVersion,
      );
      if (preferred) {
        console.log(
          `Выбрана предпочтительная версия Java ${preferredVersion}: ${preferred.path}`,
        );
        return preferred.path;
      }
    }

    // Если не нашли предпочтительные версии, берем самую старую версию
    console.log(`Выбрана доступная версия Java: ${javaVersions[0].path}`);
    return javaVersions[0].path;
  } catch (error) {
    console.error('Ошибка при поиске Java:', error);
    throw error;
  }
}

// Добавим функцию для проверки/копирования authlib-injector (как в C#)
async function ensureAuthlibInjectorExists(appPath: string): Promise<string> {
  const authlibPath = path.join(appPath, AUTHLIB_INJECTOR_FILENAME);

  // Проверяем, существует ли файл
  if (fs.existsSync(authlibPath)) {
    console.log(
      `Файл ${AUTHLIB_INJECTOR_FILENAME} уже существует: ${authlibPath}`,
    );
    return authlibPath;
  }

  // Ищем authlib в ресурсах приложения
  const resourcePath = path.join(app.getAppPath(), AUTHLIB_INJECTOR_FILENAME);

  if (fs.existsSync(resourcePath)) {
    console.log(`Копирование ${AUTHLIB_INJECTOR_FILENAME} из ресурсов...`);
    fs.copyFileSync(resourcePath, authlibPath);
    console.log(`Файл успешно скопирован: ${authlibPath}`);
    return authlibPath;
  }

  // Если не нашли локальный файл - скачиваем его
  console.log(`Скачивание ${AUTHLIB_INJECTOR_FILENAME}...`);
  await downloadFile(
    `https://github.com/yushijinhun/authlib-injector/releases/download/v1.2.5/${AUTHLIB_INJECTOR_FILENAME}`,
    authlibPath,
    (progress) => {
      console.log(`Прогресс скачивания: ${progress}%`);
    },
  );

  return authlibPath;
}

// Инициализация IPC обработчиков
export function initMinecraftHandlers() {
  // Обработчик для скачивания и распаковки
  ipcMain.handle('download-and-extract', async (event, options) => {
    try {
      const {
        downloadUrl = 'https://github.com/DIKER0K/Comfort/releases/latest/download/Comfort.zip',
        apiReleaseUrl = 'https://api.github.com/repos/DIKER0K/Comfort/releases/latest',
        versionFileName = 'comfort_version.txt',
        packName = 'Comfort',
        preserveFiles = [], // Новый параметр: список файлов/папок для сохранения
      } = options || {};

      const appPath = path.dirname(app.getPath('exe'));
      const minecraftDir = path.join(appPath, '.minecraft');
      const versionsDir = path.join(minecraftDir, 'versions');
      const versionFilePath = path.join(minecraftDir, versionFileName);

      // Получаем текущую и последнюю версии
      const latestVersion = await getLatestReleaseVersion(apiReleaseUrl);
      let currentVersion = '';

      // Проверяем текущую версию, если файл существует
      if (fs.existsSync(versionFilePath)) {
        currentVersion = fs.readFileSync(versionFilePath, 'utf-8').trim();
      }

      // Проверяем, нужно ли обновление
      if (currentVersion === latestVersion) {
        return {
          success: true,
          updated: false,
          version: currentVersion,
          packName,
        };
      }

      const tempDir = path.join(appPath, 'temp');
      const packDir = path.join(versionsDir, packName); // Директория пакета

      // Создаем/очищаем временную директорию
      if (fs.existsSync(tempDir)) {
        fs.rmSync(tempDir, { recursive: true });
      }
      fs.mkdirSync(tempDir, { recursive: true });

      const zipPath = path.join(tempDir, `${packName}.zip`);

      // Скачиваем файл
      await downloadFile(downloadUrl, zipPath, (progress) => {
        event.sender.send('download-progress', progress);

        const global = getGlobalProgress('download', progress / 100);
        event.sender.send('overall-progress', global);
      });

      // Проверяем архив
      const fileStats = fs.statSync(zipPath);
      if (fileStats.size < 1024) {
        throw new Error('Downloaded file is too small, likely corrupted');
      }

      // Создаем папку versions если её нет
      if (!fs.existsSync(versionsDir)) {
        fs.mkdirSync(versionsDir, { recursive: true });
      }

      // Сохраняем файлы/папки, которые нужно оставить
      const backupDir = path.join(tempDir, 'backup');
      fs.mkdirSync(backupDir, { recursive: true });

      // Проверка и бэкап указанных файлов/папок
      for (const filePath of preserveFiles) {
        const fullPath = path.join(packDir, filePath);

        if (fs.existsSync(fullPath)) {
          const backupPath = path.join(backupDir, filePath);

          // Создаем необходимые директории для бэкапа
          const backupDirPath = path.dirname(backupPath);
          if (!fs.existsSync(backupDirPath)) {
            fs.mkdirSync(backupDirPath, { recursive: true });
          }

          // Копируем файл или директорию
          if (fs.lstatSync(fullPath).isDirectory()) {
            fs.cpSync(fullPath, backupPath, { recursive: true });
            console.log(`Директория ${filePath} сохранена во временный бэкап`);
          } else {
            fs.copyFileSync(fullPath, backupPath);
            console.log(`Файл ${filePath} сохранен во временный бэкап`);
          }
        }
      }

      // Распаковываем архив напрямую в папку versions
      await extract(zipPath, { dir: versionsDir });
      fs.unlinkSync(zipPath);

      // Восстанавливаем файлы/папки из бэкапа
      for (const filePath of preserveFiles) {
        const backupPath = path.join(backupDir, filePath);
        if (fs.existsSync(backupPath)) {
          const targetPath = path.join(packDir, filePath);

          // Создаем необходимые директории для восстановления
          const targetDirPath = path.dirname(targetPath);
          if (!fs.existsSync(targetDirPath)) {
            fs.mkdirSync(targetDirPath, { recursive: true });
          }

          // Копируем обратно файл или директорию
          if (fs.lstatSync(backupPath).isDirectory()) {
            fs.cpSync(backupPath, targetPath, { recursive: true });
            console.log(`Директория ${filePath} восстановлена из бэкапа`);
          } else {
            fs.copyFileSync(backupPath, targetPath);
            console.log(`Файл ${filePath} восстановлен из бэкапа`);
          }
        }
      }

      // Сохраняем новую версию
      fs.writeFileSync(versionFilePath, latestVersion);

      // Удаляем временную директорию
      fs.rmSync(tempDir, { recursive: true });

      return { success: true, updated: true, version: latestVersion, packName };
    } catch (error) {
      console.error('Error in download-and-extract:', error);
      throw error;
    }
  });

  // Обработчик для запуска Minecraft
  ipcMain.handle('launch-minecraft', async (event, gameConfig) => {
    try {
      const {
        accessToken,
        uuid,
        username,
        memory = 4096,
        baseVersion = '1.21.4',
        fabricVersion = '0.16.14',
        packName = 'Comfort', // имя сборки (папка с модами)
        versionToLaunchOverride = '', // переопределение версии для запуска (например, 1.21.10 для ванили)
        serverIp = 'popa-popa.ru',
        serverPort,
        isVanillaVersion = false,
      } = gameConfig || {};

      const appPath = path.dirname(app.getPath('exe'));
      const minecraftDir = path.join(appPath, '.minecraft');
      const versionsDir = path.join(minecraftDir, 'versions');
      fs.mkdirSync(versionsDir, { recursive: true });

      // gamePath:
      //  - ваниль → .minecraft
      //  - модпак → .minecraft/versions/Comfort (или другое packName)
      const packDir = isVanillaVersion
        ? minecraftDir
        : path.join(versionsDir, packName);
      if (!fs.existsSync(packDir)) {
        fs.mkdirSync(packDir, { recursive: true });
      }

      const versionsContents = fs.existsSync(versionsDir)
        ? fs.readdirSync(versionsDir)
        : [];
      console.log('Доступные версии:', versionsContents);

      // --- Определяем базовую / фактическую версию ---
      let effectiveBaseVersion = baseVersion;

      // Для ванили считаем базовой именно ту, которую хотим запустить
      if (isVanillaVersion && versionToLaunchOverride) {
        effectiveBaseVersion = versionToLaunchOverride;
      }

      let versionToLaunch: string | undefined =
        versionToLaunchOverride || undefined;

      if (!versionToLaunch) {
        if (isVanillaVersion) {
          // Ваниль — запускаем baseVersion (или override)
          versionToLaunch = effectiveBaseVersion;
        } else {
          // Модпак — запускаем именно fabric-версию
          const fabricId = `${effectiveBaseVersion}-fabric${fabricVersion}`;
          if (versionsContents.includes(fabricId)) {
            versionToLaunch = fabricId;
          } else {
            // даже если папки нет — installFabric её создаст
            versionToLaunch = fabricId;
          }
        }
      }

      console.log('isVanillaVersion:', isVanillaVersion);
      console.log('baseVersion:', baseVersion);
      console.log('effectiveBaseVersion:', effectiveBaseVersion);
      console.log('fabricVersion:', fabricVersion);
      console.log('versionToLaunch:', versionToLaunch);
      console.log('packDir:', packDir);

      // --- Поиск Java ---
      event.sender.send('installation-status', {
        step: 'java',
        message: 'Поиск Java...',
      });

      console.log('Поиск Java...');

      let javaPath = 'java';
      try {
        javaPath = await findJava();
      } catch (error) {
        console.warn('Ошибка при поиске Java:', error);
        event.sender.send('installation-status', {
          step: 'java-error',
          message:
            'Не удалось найти Java. Попробуем запустить с системной Java.',
        });
      }

      console.log('Используем Java:', javaPath);

      // --- 1. Установка ванильного Minecraft (effectiveBaseVersion) ---
      let resolvedVersion: any;

      try {
        event.sender.send('installation-status', {
          step: 'minecraft-list',
          message: 'Получение списка версий Minecraft...',
        });

        console.log('Получение списка версий Minecraft...');

        const versionList = await getVersionList();
        const minecraftVersion = versionList.versions.find(
          (v) => v.id === effectiveBaseVersion,
        );

        console.log('minecraftVersion:', minecraftVersion);

        if (minecraftVersion) {
          const installMcTask = installTask(minecraftVersion, minecraftDir, {
            skipRevalidate: true,
            assetsDownloadConcurrency: 2,
            librariesDownloadConcurrency: 2,
            dispatcher: agent,
          });

          console.log('installMcTask started for', minecraftVersion.id);

          event.sender.send('installation-status', {
            step: 'minecraft-install',
            message: `Установка Minecraft ${minecraftVersion.id}...`,
          });

          await installMcTask.startAndWait({
            onUpdate(task, chunkSize) {
              // локальный прогресс инсталлятора XMCL
              const local =
                installMcTask.total > 0
                  ? installMcTask.progress / installMcTask.total
                  : 0;

              const global = getGlobalProgress('minecraft-install', local);
              event.sender.send('overall-progress', global);
            },
            onFailed(task, error) {
              const stepName = (task as any).path || task.name || 'unknown';
              console.warn(
                `[minecraft-install] step "${stepName}" failed: ${
                  (error as any).code ?? ''
                } ${(error as any).message}`,
              );

              event.sender.send('installation-status', {
                step: `minecraft-install.${stepName}`,
                message: `Ошибка: ${(error as any).message}`,
              });
            },
          });
        } else {
          console.warn(
            `Версия ${effectiveBaseVersion} не найдена в списке версий Minecraft. Предполагаем, что она уже установлена.`,
          );
        }
      } catch (error: any) {
        const agg = error as any;
        const innerCount = Array.isArray(agg?.errors) ? agg.errors.length : 0;

        console.log(
          'Ошибка при установке ванильного Minecraft, продолжаем:',
          agg?.message || String(agg),
          innerCount ? `(внутренних ошибок: ${innerCount})` : '',
        );
      }

      // --- 2. Установка Fabric (только для модпаков) ---
      if (!isVanillaVersion && fabricVersion) {
        try {
          event.sender.send('installation-status', {
            step: 'fabric-install',
            message: `Установка Fabric ${fabricVersion}...`,
          });

          event.sender.send(
            'overall-progress',
            getGlobalProgress('fabric-install', 0),
          );

          console.log('installFabric:', {
            minecraftVersion: effectiveBaseVersion,
            fabricVersion,
            minecraftDir,
          });

          await installFabric({
            minecraftVersion: effectiveBaseVersion,
            version: fabricVersion,
            minecraft: minecraftDir,
          });
          event.sender.send(
            'overall-progress',
            getGlobalProgress('fabric-install', 1),
          );
        } catch (error) {
          console.log('Ошибка при установке Fabric, продолжаем:', error);
        }
      }

      // --- 3. Установка зависимостей для versionToLaunch ---
      try {
        if (!versionToLaunch) {
          throw new Error('versionToLaunch не определён');
        }

        console.log('version-parse:', {
          minecraftDir,
          versionToLaunch,
        });

        event.sender.send('installation-status', {
          step: 'version-parse',
          message: 'Подготовка версии...',
        });

        resolvedVersion = await Version.parse(minecraftDir, versionToLaunch);

        event.sender.send('installation-status', {
          step: 'dependencies',
          message: 'Установка библиотек и ресурсов...',
        });

        const depsTask = installDependenciesTask(resolvedVersion, {
          skipRevalidate: true,
          prevalidSizeOnly: true,
          dispatcher: agent,
          assetsDownloadConcurrency: 2,
          librariesDownloadConcurrency: 2,
          checksumValidatorResolver: () => ({
            async validate() {
              // Игнорируем sha1, чтобы не падать из-за несоответствий
            },
          }),
          // ...DOWNLOAD_OPTIONS,
        });

        await depsTask.startAndWait({
          onUpdate(task, chunkSize) {
            const local =
              depsTask.total > 0 ? depsTask.progress / depsTask.total : 0;

            const global = getGlobalProgress('dependencies', local);
            event.sender.send('overall-progress', global);
          },
          onFailed(task, error) {
            const stepName = (task as any).path || task.name || 'unknown';
            console.warn(
              `[deps] step "${stepName}" failed: ${
                (error as any).code ?? ''
              } ${(error as any).message}`,
            );

            event.sender.send('installation-status', {
              step: `dependencies.${stepName}`,
              message: `Ошибка: ${(error as any).message}`,
            });
          },
        });
      } catch (error: any) {
        console.log(
          'Ошибка при подготовке версии/зависимостей, продолжаем запуск:',
          error.message || error,
        );
      }

      // --- authlib-injector ---
      const authlibPath = await ensureAuthlibInjectorExists(appPath);
      console.log('authlibPath:', authlibPath);

      event.sender.send('installation-status', {
        step: 'authlib-injector',
        message: 'authlib-injector готов',
      });

      // --- Запуск игры ---
      console.log('Запуск игры...');

      event.sender.send('installation-status', {
        step: 'launch',
        message: 'Запуск игры...',
      });

      event.sender.send('overall-progress', getGlobalProgress('launch', 0));

      const proc = await launch({
        gamePath: packDir,
        resourcePath: minecraftDir,
        javaPath,
        version: versionToLaunch!,
        launcherName: 'popa-popa',
        extraJVMArgs: [
          '-Dlog4j2.formatMsgNoLookups=true',
          `-javaagent:${authlibPath}=${API_BASE_URL}`,
          `-Xmx${memory}M`,
          '-Dauthlibinjector.skinWhitelist=https://minecraft.api.popa-popa.ru/',
          '-Dauthlibinjector.debug=verbose,authlib',
          '-Dauthlibinjector.legacySkinPolyfill=enabled',
          '-Dauthlibinjector.mojangAntiFeatures=disabled',
          '-Dcom.mojang.authlib.disableSecureProfileEndpoints=true',
        ],
        extraMCArgs: [
          '--quickPlayMultiplayer',
          `${serverIp}:${serverPort || 25565}`,
        ],
        accessToken,
        gameProfile: {
          id: uuid,
          name: username,
        },
      });

      event.sender.send('minecraft-started', { pid: proc.pid });

      currentMinecraftProcess = proc;

      event.sender.send('overall-progress', getGlobalProgress('launch', 1));

      let stderrBuffer = '';

      proc.stdout?.on('data', (data) => {
        console.log(`Minecraft stdout: ${data}`);
      });

      proc.stderr?.on('data', (data) => {
        const text = data.toString();
        console.error(`Minecraft stderr: ${text}`);
        stderrBuffer += text;

        // Пробрасываем сырой лог клиенту (если захочешь где-то выводить)
        event.sender.send('minecraft-log', text);

        // Если это ошибка — сразу уведомим пользователя
        if (text.toLowerCase().includes('error')) {
          event.sender.send('minecraft-error', {
            message: text,
          });
        }
      });

      proc.on('exit', (code) => {
        console.log('Minecraft exited with code', code);

        currentMinecraftProcess = null;
        event.sender.send('minecraft-stopped', { code });

        if (code !== 0) {
          event.sender.send('installation-status', {
            step: 'error',
            message: `Minecraft завершился с ошибкой (код ${code})`,
          });

          event.sender.send('minecraft-error', {
            message: `Minecraft завершился с ошибкой (код ${code})`,
            stderr: stderrBuffer,
            code,
          });
        }
      });

      console.log('Запуск игры...');

      return { success: true, pid: proc.pid };
    } catch (error: any) {
      console.error('Ошибка при запуске Minecraft:', error);
      event.sender.send('installation-status', {
        step: 'error',
        message: `Ошибка запуска: ${error.message || String(error)}`,
      });

      return { success: false, error: error.message || String(error) };
    }
  });

  ipcMain.handle('stop-minecraft', async (event) => {
    try {
      if (currentMinecraftProcess && !currentMinecraftProcess.killed) {
        console.log('Останавливаем Minecraft по запросу пользователя...');
        // На Windows этого обычно достаточно
        currentMinecraftProcess.kill();

        // Можно чуть подождать, но не обязательно
        return { success: true };
      }

      return { success: false, error: 'Minecraft сейчас не запущен' };
    } catch (error: any) {
      console.error('Ошибка при остановке Minecraft:', error);
      return { success: false, error: error.message || String(error) };
    }
  });

  // Добавьте в функцию initMinecraftHandlers или создайте новую
  ipcMain.handle('get-pack-files', async (event, packName) => {
    try {
      const appPath = path.dirname(app.getPath('exe'));
      const minecraftDir = path.join(appPath, '.minecraft');
      const packDir = path.join(minecraftDir, 'versions', packName);

      if (!fs.existsSync(packDir)) {
        return { success: false, error: 'Директория сборки не найдена' };
      }

      // Функция для рекурсивного обхода директории
      const scanDir: any = (dir: any, basePath: any = '') => {
        const result = [];
        const items = fs.readdirSync(dir);

        for (const item of items) {
          const itemPath = path.join(dir, item);
          const relativePath = basePath ? path.join(basePath, item) : item;
          const isDirectory = fs.statSync(itemPath).isDirectory();

          result.push({
            name: item,
            path: relativePath,
            isDirectory,
            // Если это директория, рекурсивно сканируем ее
            children: isDirectory ? scanDir(itemPath, relativePath) : [],
          });
        }

        return result;
      };

      const files = scanDir(packDir);
      return { success: true, files };
    } catch (error) {
      console.error('Ошибка при получении файлов сборки:', error);
      return { success: false, error: error.message };
    }
  });

  // ПРОБЛЕМА: У вас два обработчика для одного и того же канала 'get-installed-versions'
  // РЕШЕНИЕ: Объединим логику в один обработчик, а из второго обработчика вызовем функцию getInstalledVersions

  // Сначала создаем общую функцию для получения установленных версий
  function getInstalledVersions() {
    try {
      const appPath = path.dirname(app.getPath('exe'));
      const minecraftDir = path.join(appPath, '.minecraft');
      const versionsDir = path.join(minecraftDir, 'versions');

      if (!fs.existsSync(versionsDir)) {
        return { success: true, versions: [] };
      }

      const items = fs.readdirSync(versionsDir);
      const versions = [];

      for (const item of items) {
        const versionPath = path.join(versionsDir, item);
        if (!fs.statSync(versionPath).isDirectory()) continue;

        // ❗ Прячем технические fabric-версии типа 1.21.10-fabric0.18.1
        if (item.includes('-fabric')) {
          continue;
        }

        const versionJsonPath = path.join(versionPath, `${item}.json`);
        let versionInfo = {
          id: item,
          name: item,
          version: item,
        };

        if (fs.existsSync(versionJsonPath)) {
          try {
            const versionData = JSON.parse(
              fs.readFileSync(versionJsonPath, 'utf8'),
            );
            versionInfo.version = versionData.id || item;
          } catch (error) {
            console.warn(`Ошибка при чтении файла версии ${item}:`, error);
          }
        }

        versions.push(versionInfo);
      }

      return { success: true, versions };
    } catch (error) {
      console.error('Ошибка при получении установленных версий:', error);
      return { success: false, error: error.message, versions: [] };
    }
  }

  // Регистрируем обработчик для get-installed-versions
  ipcMain.handle('get-installed-versions', async () => {
    return getInstalledVersions();
  });

  // Обработчик get-available-versions использует функцию getInstalledVersions
  ipcMain.handle('get-available-versions', async (event, { gistUrl }) => {
    try {
      // Используем URL из параметров или значение по умолчанию
      const url =
        gistUrl ||
        'https://gist.githubusercontent.com/DIKER0K/06cd12fb3a4d08b1f0f8c763a7d05e06/raw/versions.json';

      const response = await fetch(url);

      if (!response.ok) {
        throw new Error(
          `Failed to fetch versions from Gist: ${response.status} ${response.statusText}`,
        );
      }

      const versions = await response.json();

      // Получаем уже установленные версии
      const installedResult = getInstalledVersions();
      const installedVersions = installedResult.success
        ? installedResult.versions
        : [];

      // Добавляем флаг installed к каждой версии
      const versionsWithInstallStatus = versions.map((version: any) => {
        const isInstalled = installedVersions.some(
          (installed: any) => installed.id === version.id,
        );
        return {
          ...version,
          installed: isInstalled,
        };
      });

      return {
        success: true,
        versions: versionsWithInstallStatus,
      };
    } catch (error) {
      console.error('Ошибка при получении доступных версий:', error);
      return { success: false, error: error.message, versions: [] };
    }
  });
}

// Добавляем обработчики IPC для аутентификации
export function initAuthHandlers() {
  // Аутентификация
  ipcMain.handle('authenticate', async (event, { username, password }) => {
    try {
      const auth = await authService.login(username, password);
      return {
        accessToken: auth.accessToken,
        clientToken: auth.clientToken,
        selectedProfile: auth.selectedProfile,
      };
    } catch (error) {
      console.error('Ошибка аутентификации:', error);
      throw error;
    }
  });

  // Валидация токена
  ipcMain.handle(
    'validate-token',
    async (event, { accessToken, clientToken }) => {
      try {
        const valid = await authService.validate(accessToken, clientToken);
        return { valid };
      } catch (error) {
        console.error('Ошибка валидации токена:', error);
        return { valid: false };
      }
    },
  );

  // Обновление токена
  ipcMain.handle(
    'refresh-token',
    async (event, { accessToken, clientToken }) => {
      try {
        const auth = await authService.refresh(accessToken, clientToken);
        if (!auth) return null;

        return {
          accessToken: auth.accessToken,
          clientToken: auth.clientToken,
          selectedProfile: auth.selectedProfile,
        };
      } catch (error) {
        console.error('Ошибка обновления токена:', error);
        return null;
      }
    },
  );
}

// Функция для получения статуса сервера
export function initServerStatusHandler() {
  ipcMain.handle('get-server-status', async (event, { host, port }) => {
    try {
      // Формируем адрес с портом, если указан
      const serverAddress = port ? `${host}:${port}` : host;

      // Делаем запрос к API mcstatus.io
      const response = await fetch(`${MCSTATUS_API_URL}${serverAddress}`);

      // Проверяем статус ответа
      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`API вернул ошибку ${response.status}: ${errorText}`);
      }

      const data = await response.json();

      if (data.online) {
        return {
          success: true,
          online: data.players?.online || 0,
          max: data.players?.max || 0,
          version: data.version?.name_clean || 'Unknown',
          icon: data.icon || null, // Возвращаем иконку
          motd: data.motd?.clean || '', // Название сервера
        };
      } else {
        return { success: false, error: 'Сервер не доступен' };
      }
    } catch (error) {
      console.error('Ошибка при получении статуса сервера:', error);
      return { success: false, error: error.message };
    }
  });
}

// Функция для работы с конфигурацией сборки
export function initPackConfigHandlers() {
  // Файл конфигурации
  const CONFIG_FILENAME = 'popa-launcher-config.json';

  // Обработчик для сохранения настроек сборки
  ipcMain.handle('save-pack-config', async (event, { packName, config }) => {
    try {
      const appPath = path.dirname(app.getPath('exe'));
      const minecraftDir = path.join(appPath, '.minecraft');
      const packDir = path.join(minecraftDir, 'versions', packName);

      // Создаем папку для сборки, если она не существует
      if (!fs.existsSync(packDir)) {
        fs.mkdirSync(packDir, { recursive: true });
      }

      const configPath = path.join(packDir, CONFIG_FILENAME);

      // Сохраняем конфигурацию в файл
      fs.writeFileSync(configPath, JSON.stringify(config, null, 2));

      // Добавляем файл конфигурации в список файлов, которые не удаляются
      if (!config.preserveFiles.includes(CONFIG_FILENAME)) {
        config.preserveFiles.push(CONFIG_FILENAME);
        // Перезаписываем файл с обновленным списком
        fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
      }

      return { success: true };
    } catch (error) {
      console.error('Ошибка при сохранении настроек сборки:', error);
      return { success: false, error: error.message };
    }
  });

  // Обработчик для загрузки настроек сборки
  ipcMain.handle('load-pack-config', async (event, { packName }) => {
    try {
      const appPath = path.dirname(app.getPath('exe'));
      const minecraftDir = path.join(appPath, '.minecraft');
      const packDir = path.join(minecraftDir, 'versions', packName);
      const configPath = path.join(packDir, CONFIG_FILENAME);

      // Проверяем существование файла конфигурации
      if (!fs.existsSync(configPath)) {
        // Если файла нет, возвращаем дефолтную конфигурацию
        return {
          success: true,
          config: {
            memory: 4096,
            preserveFiles: [CONFIG_FILENAME], // По умолчанию сохраняем файл конфигурации
          },
        };
      }

      // Читаем и парсим конфигурацию
      const configData = fs.readFileSync(configPath, 'utf8');
      const config = JSON.parse(configData);

      // Добавляем файл конфигурации в список сохраняемых файлов, если его там нет
      if (!config.preserveFiles.includes(CONFIG_FILENAME)) {
        config.preserveFiles.push(CONFIG_FILENAME);
      }

      return { success: true, config };
    } catch (error) {
      console.error('Ошибка при загрузке настроек сборки:', error);
      return {
        success: false,
        error: error.message,
        // Возвращаем дефолтную конфигурацию при ошибке
        config: {
          memory: 4096,
          preserveFiles: [CONFIG_FILENAME],
        },
      };
    }
  });
}

// Добавляем после обработчика get-available-versions
ipcMain.handle('get-version-config', async (event, { versionId }) => {
  try {
    const appPath = path.dirname(app.getPath('exe'));
    const minecraftDir = path.join(appPath, '.minecraft');
    const versionsDir = path.join(minecraftDir, 'versions');
    const versionPath = path.join(versionsDir, versionId);

    // Проверяем существование директории версии
    if (!fs.existsSync(versionPath)) {
      return { success: false, error: `Версия ${versionId} не найдена` };
    }

    // Проверяем конфигурационный файл версии
    const configPath = path.join(versionPath, 'popa-launcher-config.json');

    // Определяем базовые настройки по умолчанию
    let config = {
      downloadUrl: '',
      apiReleaseUrl: '',
      versionFileName: `${versionId}_version.txt`,
      packName: versionId,
      memory: 4096,
      baseVersion: '1.21.10',
      serverIp: 'popa-popa.ru',
      fabricVersion: '0.18.1',
      preserveFiles: ['popa-launcher-config.json'],
    };

    // Если это Comfort, используем настройки по умолчанию
    if (versionId === 'Comfort') {
      config.downloadUrl =
        'https://github.com/DIKER0K/Comfort/releases/latest/download/Comfort.zip';
      config.apiReleaseUrl =
        'https://api.github.com/repos/DIKER0K/Comfort/releases/latest';
      config.baseVersion = '1.21.10';
      config.fabricVersion = '0.18.1';
    }

    // Если есть конфигурационный файл, загружаем из него
    if (fs.existsSync(configPath)) {
      try {
        const savedConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
        config = { ...config, ...savedConfig };
      } catch (error) {
        console.warn(`Ошибка чтения конфигурации ${versionId}:`, error);
      }
    }

    return { success: true, config };
  } catch (error) {
    console.error('Ошибка получения настроек версии:', error);
    return { success: false, error: error.message };
  }
});
