#!/usr/bin/env bun

import { $ } from "bun";
import { spawn } from "child_process";
import path from "path";
import { promisify } from "util";
import net from "net";

const sleep = promisify(setTimeout);

// Проверка занятости порта
async function isPortInUse(port) {
  return new Promise((resolve) => {
    const server = net.createServer();
    server.once("error", () => resolve(true));
    server.once("listening", () => {
      server.close();
      resolve(false);
    });
    server.listen(port);
  });
}

// Принудительное убийство процесса по PID (Windows)
async function killProcess(pid, force = true) {
  try {
    if (process.platform === "win32") {
      await $`taskkill /PID ${pid} ${force ? "/F" : ""}`.quiet();
    } else {
      process.kill(pid, force ? "SIGKILL" : "SIGTERM");
    }
  } catch (e) {
    // Процесс уже мёртв — ок
  }
}

// Поиск и убийство процессов по имени порта
async function killPort(port) {
  try {
    if (process.platform === "win32") {
      // Находим PID по порту
      const { stdout } = await $`netstat -ano | findstr :${port}`.quiet().nothrow();
      const lines = stdout.toString().trim().split("\n");
      const pids = new Set();

      for (const line of lines) {
        const parts = line.trim().split(/\s+/);
        if (parts.length >= 5) {
          const pid = parts[4];
          if (pid && !isNaN(parseInt(pid))) {
            pids.add(parseInt(pid));
          }
        }
      }

      for (const pid of pids) {
        await killProcess(pid);
        console.log(`   🔪 Убит процесс ${pid} на порту ${port}`);
      }
    } else {
      await $`lsof -ti:${port} | xargs kill -9`.quiet().nothrow();
    }
  } catch (e) {
    // Нет процессов — ок
  }
}

// Проверка и освобождение портов
async function cleanupPorts() {
  console.log("🔍 Проверка портов...");
  const ports = [1025, 1080, 4321, 8090];

  for (const port of ports) {
    if (await isPortInUse(port)) {
      console.log(`   ⚠️  Порт ${port} занят, освобождаем...`);
      await killPort(port);
      await sleep(500); // Даём время на освобождение
    }
  }
}

let maildev, backend, frontend;

// Корректное завершение всех процессов
async function cleanup() {
  console.log("\n🛑 Остановка серверов...");

  // Принудительно убиваем каждый процесс с SIGKILL
  const kills = [];

  if (maildev && !maildev.killed) {
    maildev.kill("SIGKILL");
    kills.push(new Promise(r => maildev.once("exit", r)));
  }
  if (backend && !backend.killed) {
    backend.kill("SIGKILL");
    kills.push(new Promise(r => backend.once("exit", r)));
  }
  if (frontend && !frontend.killed) {
    frontend.kill("SIGKILL");
    kills.push(new Promise(r => frontend.once("exit", r)));
  }

  // Ждём завершения не дольше 3 секунд
  await Promise.race([
    Promise.all(kills),
    sleep(3000)
  ]);

  process.exit(0);
}

// Главная функция
async function main() {
  await cleanupPorts();

  console.log("🚀 Запуск серверов avtourist086...\n");

  // Запуск Maildev с отдельной группой процессов
  maildev = spawn("maildev", ["--web", "1080", "--smtp", "1025"], {
    stdio: "inherit",
    shell: true,
    windowsHide: true,
    detached: false
  });

  // Запуск PocketBase
  backend = spawn("pocketbase.exe", ["serve"], {
    cwd: path.join(process.cwd(), "backend"),
    stdio: "inherit",
    shell: true,
    windowsHide: true,
    detached: false,
    env: {
      ...process.env,
      PB_SMTP_HOST: "localhost",
      PB_SMTP_PORT: "1025",
      PB_SMTP_FROM: "noreply@avtourist-surgut.ru"
    }
  });

  // Запуск Astro
  frontend = spawn("bun", ["dev"], {
    cwd: "frontend",
    stdio: "inherit",
    shell: true,
    windowsHide: true,
    detached: false
  });

  // Обработчики сигналов
  process.on("SIGINT", cleanup);
  process.on("SIGTERM", cleanup);
  process.on("SIGBREAK", cleanup); // Windows-specific

  // Обработка закрытия консоли Windows
  if (process.platform === "win32") {
    const readline = await import("readline");
    readline.createInterface({
      input: process.stdin,
      output: process.stdout
    }).on("SIGINT", cleanup);
  }

  // Мониторинг процессов
  maildev.on("exit", (code) => {
    console.log(`\n📧 Maildev остановлен с кодом ${code}`);
    if (code !== 0 && code !== null) cleanup();
  });

  backend.on("exit", (code) => {
    console.log(`\n💾 Backend остановлен с кодом ${code}`);
    if (code !== 0 && code !== null) cleanup();
  });

  frontend.on("exit", (code) => {
    console.log(`\n🌐 Frontend остановлен с кодом ${code}`);
    cleanup();
  });

  console.log("✅ Серверы запущены:\n");
  console.log("   📧 Maildev (SMTP): http://localhost:1080");
  console.log("   💾 Backend (PocketBase): http://localhost:8090");
  console.log("   🌐 Frontend (Astro): http://localhost:4321\n");
  console.log("Нажмите Ctrl+C для остановки\n");
}

main().catch(err => {
  console.error("❌ Ошибка:", err);
  process.exit(1);
});