import { spawn, type ChildProcess } from "node:child_process";
import { mkdirSync, writeFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { defineConfig, type Plugin } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import { componentTagger } from "lovable-tagger";
import {
  getSupervisorManagementStatus,
  readAutomationSupervisorState,
  resolveAutomationControlConfig,
} from "./automation/control/dev-supervisor-state";

const projectRoot = path.dirname(fileURLToPath(import.meta.url));
const automationControlConfig = resolveAutomationControlConfig(process.env, projectRoot);
const automationPort = automationControlConfig.port;
const automationTarget = process.env.VITE_AUTOMATION_BASE_URL ?? `http://127.0.0.1:${automationPort}`;
const automationTargetUrl = new URL(automationTarget);
const automationControlOrigin = automationTargetUrl.origin;
const automationControlHost = automationTargetUrl.hostname;
const automationControlRuntimeDir = automationControlConfig.runtimeDir;
const automationRestartSignalFile = automationControlConfig.restartSignalFile;
const automationSupervisorStateFile = automationControlConfig.supervisorStateFile;
const canStartAutomationService = ["127.0.0.1", "localhost", "::1"].includes(automationControlHost)
  && !automationControlConfig.portConfigError;
const AUTOMATION_CONTROL_PREFIX = "/__automation-control";
const AUTOMATION_STARTUP_WINDOW_MS = 20_000;

type AutomationControlStatus = "online" | "offline" | "starting" | "restart-sent" | "unmanaged" | "unsupported";

function writeJsonResponse(res: NodeJS.WritableStream & { statusCode: number; setHeader(name: string, value: string): void; end(body: string): void }, statusCode: number, payload: Record<string, unknown>) {
  res.statusCode = statusCode;
  res.setHeader("Content-Type", "application/json; charset=utf-8");
  res.end(JSON.stringify(payload));
}

async function isAutomationServiceResponsive() {
  try {
    const response = await fetch(`${automationControlOrigin}/api/state`, {
      signal: AbortSignal.timeout(1500),
    });
    return response.ok;
  } catch {
    return false;
  }
}

function createAutomationControlPlugin(): Plugin {
  let automationChild: ChildProcess | null = null;
  let lastLaunchRequestedAt = 0;

  function hasTrackedChild() {
    return Boolean(automationChild && automationChild.exitCode === null && !automationChild.killed);
  }

  function logAutomationOutput(level: "log" | "error", chunk: Buffer) {
    const lines = chunk.toString().split(/\r?\n/).map((line) => line.trimEnd()).filter(Boolean);
    for (const line of lines) {
      console[level](`[automation-control] ${line}`);
    }
  }

  function bindAutomationChild(child: ChildProcess) {
    automationChild = child;
    lastLaunchRequestedAt = Date.now();

    child.stdout?.on("data", (chunk: Buffer) => {
      logAutomationOutput("log", chunk);
    });

    child.stderr?.on("data", (chunk: Buffer) => {
      logAutomationOutput("error", chunk);
    });

    child.on("error", (error) => {
      if (automationChild === child) {
        automationChild = null;
      }
      console.error(`[automation-control] 启动失败: ${error.message}`);
    });

    child.on("exit", (code, signal) => {
      if (automationChild === child) {
        automationChild = null;
      }
      console.log(`[automation-control] 自动化服务进程退出 (code=${code ?? "null"}, signal=${signal ?? "null"})`);
    });
  }

  function spawnAutomationChild() {
    const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
    const child = spawn(npmCommand, ["run", "dev:api"], {
      cwd: projectRoot,
      env: {
        ...process.env,
        AUTOMATION_PORT: automationPort,
      },
      stdio: ["ignore", "pipe", "pipe"],
    });

    bindAutomationChild(child);
    return child;
  }

  function requestAutomationSupervisorRestart() {
    mkdirSync(automationControlRuntimeDir, { recursive: true });
    writeFileSync(automationRestartSignalFile, JSON.stringify({ requestedAt: new Date().toISOString() }));
    return "已向自动化服务守护进程发送重启请求";
  }

  function readSupervisorManagementStatus() {
    const supervisorState = readAutomationSupervisorState(automationSupervisorStateFile);
    return getSupervisorManagementStatus(supervisorState);
  }

  async function buildStatusPayload() {
    if (automationControlConfig.portConfigError) {
      return {
        status: "unsupported" as AutomationControlStatus,
        canStart: false,
        message: automationControlConfig.portConfigError,
        target: automationControlOrigin,
        checkedAt: new Date().toISOString(),
      };
    }

    const online = await isAutomationServiceResponsive();
    const trackedChildAlive = hasTrackedChild();
    const startupAge = Date.now() - lastLaunchRequestedAt;
    const startupInProgress = trackedChildAlive && startupAge < AUTOMATION_STARTUP_WINDOW_MS;
    const startupTimedOut = trackedChildAlive && !startupInProgress;

    let status: AutomationControlStatus = "offline";
    let canStart = canStartAutomationService;
    let message = `自动化服务离线，目标地址 ${automationControlOrigin}`;

    if (online) {
      const supervisorManagementStatus = readSupervisorManagementStatus();
      if (supervisorManagementStatus.managed) {
        status = "online";
        canStart = canStartAutomationService;
        message = `自动化服务在线，目标地址 ${automationControlOrigin}`;
      } else {
        status = "unmanaged";
        canStart = false;
        message = supervisorManagementStatus.reason;
      }
    } else if (!canStartAutomationService) {
      message = `当前自动化服务目标为 ${automationControlOrigin}，前端仅支持拉起本机服务`;
      canStart = false;
    } else if (startupInProgress) {
      status = "starting";
      message = "正在启动自动化服务，请稍候";
    } else if (startupTimedOut) {
      message = "自动化服务启动超时，请查看当前 Vite 开发终端日志";
    }

    return {
      status,
      canStart,
      message,
      target: automationControlOrigin,
      checkedAt: new Date().toISOString(),
    };
  }

  return {
    name: "automation-control-plugin",
    apply: "serve",
    configureServer(server) {
      server.middlewares.use(async (req, res, next) => {
        const requestPath = req.url?.split("?")[0] ?? "";

        if (!requestPath.startsWith(AUTOMATION_CONTROL_PREFIX)) {
          next();
          return;
        }

        if (requestPath === `${AUTOMATION_CONTROL_PREFIX}/status` && req.method === "GET") {
          writeJsonResponse(res, 200, await buildStatusPayload());
          return;
        }

        if (requestPath === `${AUTOMATION_CONTROL_PREFIX}/start` && req.method === "POST") {
          if (!canStartAutomationService) {
            writeJsonResponse(res, automationControlConfig.portConfigError ? 409 : 400, {
              error: automationControlConfig.portConfigError ?? `当前自动化服务目标为 ${automationControlOrigin}，无法从前端拉起非本机服务`,
            });
            return;
          }

          if (await isAutomationServiceResponsive()) {
            const statusPayload = await buildStatusPayload();
            const statusCode = statusPayload.status === "unmanaged" ? 409 : 200;
            writeJsonResponse(res, statusCode, {
              ...statusPayload,
              message: statusPayload.status === "unmanaged" ? statusPayload.message : "自动化服务已在线，无需重复启动",
            });
            return;
          }

          if (hasTrackedChild()) {
            const startupAge = Date.now() - lastLaunchRequestedAt;
            if (startupAge < AUTOMATION_STARTUP_WINDOW_MS) {
              writeJsonResponse(res, 202, {
                ...(await buildStatusPayload()),
                status: "starting",
                message: "自动化服务正在启动，请稍候",
              });
              return;
            }

            writeJsonResponse(res, 409, {
              error: "检测到已有自动化服务启动进程未就绪，请先查看当前 Vite 开发终端日志",
            });
            return;
          }

          spawnAutomationChild();

          writeJsonResponse(res, 202, {
            status: "starting",
            canStart: true,
            message: "已发送启动请求，正在拉起自动化服务",
            target: automationControlOrigin,
            checkedAt: new Date().toISOString(),
          });
          return;
        }

        if (requestPath === `${AUTOMATION_CONTROL_PREFIX}/restart` && req.method === "POST") {
          if (!canStartAutomationService) {
            writeJsonResponse(res, automationControlConfig.portConfigError ? 409 : 400, {
              status: automationControlConfig.portConfigError ? "unsupported" : "unmanaged",
              canStart: false,
              error: automationControlConfig.portConfigError ?? `当前自动化服务目标为 ${automationControlOrigin}，无法从前端重启非本机服务`,
              message: automationControlConfig.portConfigError ?? `当前自动化服务目标为 ${automationControlOrigin}，无法从前端重启非本机服务`,
              target: automationControlOrigin,
              checkedAt: new Date().toISOString(),
            });
            return;
          }

          try {
            if (await isAutomationServiceResponsive()) {
              const supervisorManagementStatus = readSupervisorManagementStatus();
              if (!supervisorManagementStatus.managed) {
                writeJsonResponse(res, 409, {
                  status: "unmanaged",
                  canStart: false,
                  message: supervisorManagementStatus.reason,
                  error: supervisorManagementStatus.reason,
                  target: automationControlOrigin,
                  checkedAt: new Date().toISOString(),
                });
                return;
              }

              const message = requestAutomationSupervisorRestart();
              writeJsonResponse(res, 202, {
                status: "restart-sent",
                canStart: true,
                message,
                target: automationControlOrigin,
                checkedAt: new Date().toISOString(),
              });
              return;
            }

            if (hasTrackedChild()) {
              const startupAge = Date.now() - lastLaunchRequestedAt;
              if (startupAge < AUTOMATION_STARTUP_WINDOW_MS) {
                writeJsonResponse(res, 202, {
                  ...(await buildStatusPayload()),
                  status: "starting",
                  message: "自动化服务正在启动，请稍候",
                });
                return;
              }

              writeJsonResponse(res, 409, {
                error: "检测到已有自动化服务启动进程未就绪，请先查看当前 Vite 开发终端日志",
              });
              return;
            }

            spawnAutomationChild();
            writeJsonResponse(res, 202, {
              ...(await buildStatusPayload()),
              status: "starting",
              message: "自动化服务当前离线，已发送重新拉起请求",
            });
            return;
          } catch (error) {
            writeJsonResponse(res, 500, {
              error: error instanceof Error ? error.message : String(error),
            });
            return;
          }
        }

        writeJsonResponse(res, 404, { error: "未找到自动化服务控制接口" });
      });

      server.httpServer?.once("close", () => {
        if (hasTrackedChild()) {
          automationChild?.kill("SIGTERM");
        }
      });
    },
  };
}

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
  server: {
    host: "::",
    port: 8080,
    hmr: {
      overlay: false,
    },
    watch: {
      ignored: ["**/automation/**", "**/chatbot/**", "**/dist/**"],
    },
    proxy: {
      "/api": {
        target: automationTarget,
        changeOrigin: true,
      },
    },
  },
  plugins: [react(), createAutomationControlPlugin(), mode === "development" && componentTagger()].filter(Boolean),
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
    dedupe: ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime", "@tanstack/react-query", "@tanstack/query-core"],
  },
}));
