import { spawn, exec, ChildProcess } from "child_process";
import { promisify } from "util";
import fetch from "node-fetch";
import * as fs from "fs";

const execAsync = promisify(exec);

// Windows 支持函数
function getCommand(command: string): string {
  // dotnet 在 Windows 上不需要 .cmd 后缀
  if (command === "dotnet") {
    return "dotnet";
  }
  return process.platform === "win32" ? `${command}.cmd` : command;
}

function getSpawnOptions() {
  return process.platform === "win32"
    ? { stdio: "pipe", shell: true }
    : { stdio: "pipe" };
}

async function waitForServer(
  url: string,
  maxRetries: number = 30,
  interval: number = 1000,
): Promise<boolean> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url);
      if (response.ok) {
        console.log("✓ Server is ready");
        return true;
      }
    } catch (error) {
      // Server not ready yet
    }
    console.log(`Waiting for server... (${i + 1}/${maxRetries})`);
    await new Promise((resolve) => setTimeout(resolve, interval));
  }
  return false;
}

// 改进全局变量类型
let serverProcess: ChildProcess | null = null;
let webProcess: ChildProcess | null = null;

async function startWeb(): Promise<ChildProcess> {
  console.log("Starting Vite frontend...");
  return new Promise((resolve, reject) => {
    const process = spawn(
      getCommand("npm"),
      ["run", "dev"],
      getSpawnOptions() as any,
    );

    let webStarted = false;

    process.stdout?.on("data", (data) => {
      const output = data.toString();
      console.log(`Web: ${output}`);

      // 检查 Vite 是否已启动
      if (
        (output.includes("Local:") || output.includes("ready in")) &&
        !webStarted
      ) {
        webStarted = true;
        resolve(process);
      }
    });

    process.stderr?.on("data", (data) => {
      console.error(`Web Error: ${data}`);
    });

    process.on("error", (error) => {
      reject(error);
    });

    process.on("exit", (code, signal) => {
      console.log(`Web process exited with code ${code} and signal ${signal}`);
      if (!webStarted) {
        reject(new Error(`Web process exited unexpectedly with code ${code}`));
      }
    });

    // 存储进程引用
    webProcess = process;

    // 超时处理
    setTimeout(() => {
      if (!webStarted) {
        reject(new Error("Web server failed to start within timeout"));
      }
    }, 10000); // 10秒超时
  });
}

async function startServer(): Promise<ChildProcess> {
  console.log("Starting .NET server...");
  return new Promise((resolve, reject) => {
    const process = spawn(
      getCommand("dotnet"),
      ["run", "--property:Configuration=Release"],
      {
        cwd: "server",
        ...getSpawnOptions(),
      } as any,
    );

    let serverStarted = false;

    process.stdout?.on("data", (data) => {
      const output = data.toString();
      console.log(`Server: ${output}`);

      // 检查服务器是否已启动
      if (output.includes("Now listening on:") && !serverStarted) {
        serverStarted = true;
        resolve(process);
      }
    });

    process.stderr?.on("data", (data) => {
      console.error(`Server Error: ${data}`);
    });

    process.on("error", (error) => {
      reject(error);
    });

    process.on("exit", (code, signal) => {
      console.log(
        `Server process exited with code ${code} and signal ${signal}`,
      );
      if (!serverStarted) {
        reject(
          new Error(`Server process exited unexpectedly with code ${code}`),
        );
      }
    });

    // 存储进程引用
    serverProcess = process;

    // 超时处理
    setTimeout(() => {
      if (!serverStarted) {
        reject(new Error("Server failed to start within timeout"));
      }
    }, 10000); // 10秒超时
  });
}

async function stopServer(): Promise<void> {
  console.log("Stopping server...");

  if (!serverProcess) {
    console.log("No server process to stop");
    return;
  }

  try {
    // 检查进程是否还存在
    if (serverProcess.killed || serverProcess.exitCode !== null) {
      console.log("✓ Server process already terminated");
      serverProcess = null;
      return;
    }

    // 发送 SIGTERM 信号
    const killed = serverProcess.kill("SIGTERM");
    if (!killed) {
      console.warn("Failed to send SIGTERM to server process");
      return;
    }

    // 设置超时，如果 3 秒内没有退出则强制终止
    const timeoutPromise = new Promise<void>((resolve) => {
      setTimeout(() => {
        if (
          serverProcess &&
          !serverProcess.killed &&
          serverProcess.exitCode === null
        ) {
          console.log("Force killing server process...");
          serverProcess.kill("SIGKILL");
        }
        resolve();
      }, 3000); // 减少超时时间到3秒
    });

    await Promise.race([timeoutPromise]);
  } catch (error) {
    console.warn("Warning: Could not stop server process:", error);
  } finally {
    serverProcess = null;

    // 只有在进程可能没有正常退出时才执行清理
    // 移除自动清理逻辑，因为正常退出时不需要
  }
}

async function stopWeb(): Promise<void> {
  console.log("Stopping web server...");

  if (!webProcess) {
    console.log("No web process to stop");
    return;
  }

  try {
    // 检查进程是否还存在
    if (webProcess.killed || webProcess.exitCode !== null) {
      console.log("✓ Web process already terminated");
      webProcess = null;
      return;
    }

    // 发送 SIGTERM 信号
    const killed = webProcess.kill("SIGTERM");
    if (!killed) {
      console.warn("Failed to send SIGTERM to web process");
      return;
    }

    // 设置超时，如果 3 秒内没有退出则强制终止
    const timeoutPromise = new Promise<void>((resolve) => {
      setTimeout(() => {
        if (webProcess && !webProcess.killed && webProcess.exitCode === null) {
          console.log("Force killing web process...");
          webProcess.kill("SIGKILL");
        }
        resolve();
      }, 3000);
    });

    await Promise.race([timeoutPromise]);
  } catch (error) {
    console.warn("Warning: Could not stop web process:", error);
  } finally {
    webProcess = null;
  }
}

async function postProcessApiClient(): Promise<void> {
  console.log("Post-processing API client...");
  try {
    const filePath = "src/APIClient.ts";

    // 检查文件是否存在
    if (!fs.existsSync(filePath)) {
      throw new Error(`API client file not found: ${filePath}`);
    }

    // 读取文件内容
    let content = fs.readFileSync(filePath, "utf8");

    // 替换 ArgumentException 中的 message 属性声明
    content = content.replace(
      /(\s+)message!:\s*string;/g,
      "$1declare message: string;",
    );
    content = content.replace(
      "{ AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelToken }",
      "{ AxiosError, type AxiosInstance, type AxiosRequestConfig, type AxiosResponse, type CancelToken }",
    );

    // 写回文件
    fs.writeFileSync(filePath, content, "utf8");

    console.log("✓ API client post-processing completed");
  } catch (error) {
    throw new Error(`Failed to post-process API client: ${error}`);
  }
}

async function generateApiClient(): Promise<void> {
  console.log("Generating API client...");
  try {
    const url = "http://127.0.0.1:5000/GetAPIClientCode";
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(
        `Failed to fetch API client code: ${response.status} ${response.statusText}`,
      );
    }
    const code = await response.text();

    // 写入 APIClient.ts
    const filePath = "src/APIClient.ts";
    fs.writeFileSync(filePath, code, "utf8");
    console.log("✓ API client code fetched and written successfully");

    // 添加后处理步骤
    await postProcessApiClient();
  } catch (error) {
    throw new Error(`Failed to generate API client: ${error}`);
  }
}

async function generateSignalRClient(): Promise<void> {
  console.log("Generating SignalR TypeScript client...");
  try {
    const { stdout, stderr } = await execAsync(
      "dotnet tsrts --project ./server/server.csproj --output ./src/utils/signalR",
    );
    if (stdout) console.log(stdout);
    if (stderr) console.error(stderr);
    console.log("✓ SignalR TypeScript client generated successfully");
  } catch (error) {
    throw new Error(`Failed to generate SignalR client: ${error}`);
  }
}

async function main(): Promise<void> {
  try {
    // Generate SignalR client
    await generateSignalRClient();
    console.log("✓ SignalR TypeScript client generated successfully");

    // Start web frontend first
    await startWeb();
    console.log("✓ Frontend started");

    // Wait a bit for frontend to fully initialize
    await new Promise((resolve) => setTimeout(resolve, 3000));

    // Start server
    await startServer();
    console.log("✓ Backend started");

    // Wait for server to be ready (给服务器额外时间完全启动)
    await new Promise((resolve) => setTimeout(resolve, 2000));

    // Check if swagger endpoint is available
    const serverReady = await waitForServer(
      "http://localhost:5000/swagger/v1/swagger.json",
    );

    if (!serverReady) {
      throw new Error("Server failed to start within the expected time");
    }

    // Generate API client
    await generateApiClient();

    console.log("✓ API generation completed successfully");
  } catch (error) {
    console.error("❌ Error:", error);
    process.exit(1);
  } finally {
    // Always try to stop processes in order: server first, then web
    await stopServer();
    await stopWeb();
  }
}

// 改进的进程终止处理 - 添加防重复执行
let isCleaningUp = false;

const cleanup = async (signal: string) => {
  if (isCleaningUp) {
    console.log("Cleanup already in progress, ignoring signal");
    return;
  }

  isCleaningUp = true;
  console.log(`\nReceived ${signal}, cleaning up...`);

  try {
    await Promise.all([stopServer(), stopWeb()]);
  } catch (error) {
    console.error("Error during cleanup:", error);
  }

  // 立即退出，不等待
  process.exit(0);
};

process.on("SIGINT", () => cleanup("SIGINT"));
process.on("SIGTERM", () => cleanup("SIGTERM"));

// 处理未捕获的异常
process.on("uncaughtException", async (error) => {
  if (isCleaningUp) return;

  console.error("❌ Uncaught exception:", error);
  isCleaningUp = true;

  try {
    await Promise.all([stopServer(), stopWeb()]);
  } catch (cleanupError) {
    console.error("Error during cleanup:", cleanupError);
  }

  process.exit(1);
});

process.on("unhandledRejection", async (reason, promise) => {
  if (isCleaningUp) return;

  console.error("❌ Unhandled rejection at:", promise, "reason:", reason);
  isCleaningUp = true;

  try {
    await Promise.all([stopServer(), stopWeb()]);
  } catch (cleanupError) {
    console.error("Error during cleanup:", cleanupError);
  }

  process.exit(1);
});

main().catch(async (error) => {
  if (isCleaningUp) return;

  console.error("❌ Unhandled error:", error);
  isCleaningUp = true;

  try {
    await Promise.all([stopServer(), stopWeb()]);
  } catch (cleanupError) {
    console.error("Error during cleanup:", cleanupError);
  }

  process.exit(1);
});
