import * as http from "http";
import * as https from "https";
import * as fs from "fs";
import * as path from "path";

// 配置文件路径
const CONFIG_FILE = path.join(__dirname, "config.json");

// 定义类型
interface RouteConfig {
  [route: string]: string;
}

interface AppConfig {
  /** 为 false 时所有请求走代理，不命中 mock 路由；缺省为 true */
  mockEnabled?: boolean;
  cacheConfig: boolean;
  reloadOnChange: boolean;
  defaultContentType: string;
  proxyPort: number;
  targetHost: string;
  /** 代理转发的目标 HTTPS 端口；缺省 443 */
  targetPort?: number;
}

interface ConfigFile {
  routes: RouteConfig;
  config: AppConfig;
}

// 存储当前的路由配置
let MOCK_ROUTES: RouteConfig = {};
let CONFIG: AppConfig = {
  cacheConfig: true,
  reloadOnChange: true,
  defaultContentType: "application/json",
  proxyPort: 443,
  targetHost: "localhost",
  targetPort: 443,
};

// 过滤掉以 # 开头的路由（视为注释，不参与 mock）
function filterActiveRoutes(routes: RouteConfig): RouteConfig {
  const filtered: RouteConfig = {};
  for (const [route, filePath] of Object.entries(routes)) {
    if (route.startsWith("#")) continue;
    filtered[route] = filePath;
  }
  return filtered;
}

// 加载配置文件
function loadConfig() {
  try {
    if (!fs.existsSync(CONFIG_FILE)) {
      console.warn(`[CONFIG] 配置文件不存在: ${CONFIG_FILE}`);
      console.warn(`[CONFIG] 正在创建默认配置文件...`);

      // 创建默认配置
      const defaultConfig: ConfigFile = {
        routes: {
          "/api2/test": "mock/test.txt",
        },
        config: {
          cacheConfig: true,
          reloadOnChange: true,
          defaultContentType: "application/json",
          proxyPort: 443,
          targetHost: "localhost",
          targetPort: 443,
        },
      };

      // 确保mock目录存在
      const mockDir = path.join(__dirname, "mock");
      if (!fs.existsSync(mockDir)) {
        fs.mkdirSync(mockDir, { recursive: true });
      }

      // 保存配置文件
      fs.writeFileSync(
        CONFIG_FILE,
        JSON.stringify(defaultConfig, null, 2),
        "utf-8",
      );
      console.log(`[CONFIG] 已创建默认配置文件: ${CONFIG_FILE}`);

      // 加载配置（# 开头的路由视为注释，不参与 mock）
      const configData: ConfigFile = JSON.parse(
        fs.readFileSync(CONFIG_FILE, "utf-8"),
      );
      MOCK_ROUTES = filterActiveRoutes(configData.routes || {});
      CONFIG = configData.config || CONFIG;
    } else {
      const configData: ConfigFile = JSON.parse(
        fs.readFileSync(CONFIG_FILE, "utf-8"),
      );
      MOCK_ROUTES = filterActiveRoutes(configData.routes || {});
      CONFIG = configData.config || CONFIG;
      console.log(
        `[CONFIG] 配置文件已加载，共 ${Object.keys(MOCK_ROUTES).length} 个路由${CONFIG.mockEnabled !== false ? "" : "（mock 已关闭，全部走代理）"}`,
      );
    }

    // 验证mock文件是否存在
    validateMockFiles();
  } catch (error) {
    console.error(`[CONFIG] 加载配置文件失败:`, error);
    // 使用默认配置
    MOCK_ROUTES = {
      "/api2/user/list": "mock/user_list.txt",
    };
    CONFIG = {
      cacheConfig: true,
      reloadOnChange: true,
      defaultContentType: "application/json",
      proxyPort: 9443,
      targetHost: "devrmtapp.resmart.cn",
      targetPort: 443,
    };
  }
}

// 验证mock文件是否存在
function validateMockFiles() {
  console.log(`[CONFIG] 验证mock文件...`);
  let missingFiles: Array<{
    route: string;
    filePath: string;
    fullPath: string;
  }> = [];

  for (const [route, filePath] of Object.entries(MOCK_ROUTES)) {
    const fullPath = path.join(__dirname, filePath);
    if (!fs.existsSync(fullPath)) {
      missingFiles.push({ route, filePath, fullPath });
      console.warn(
        `[CONFIG]  警告: mock文件不存在 - ${filePath} (用于路由: ${route})`,
      );
    }
  }

  if (missingFiles.length > 0) {
    console.log(
      `[CONFIG] 缺少 ${missingFiles.length} 个mock文件，请创建这些文件`,
    );
  } else {
    console.log(`[CONFIG] 所有mock文件验证通过`);
  }
}

// 检查是否为mock路由的函数
function isMockRoute(requestPath: string): boolean {
  if (CONFIG.mockEnabled === false) return false;
  return MOCK_ROUTES.hasOwnProperty(requestPath);
}

// 获取mock文件路径
function getMockFilePath(requestPath: string): string {
  return MOCK_ROUTES[requestPath];
}

// 代理服务器
const proxyServer = http.createServer((clientReq, clientRes) => {
  // 解析客户端请求的 URL
  const parsedUrl = new URL(`http://localhost${clientReq.url!}`);
  const requestPath = parsedUrl.pathname;

  // 管理接口：保留路径，不参与代理转发
  if (requestPath === "/__reload-config") {
    if (clientReq.method !== "POST") {
      clientRes.writeHead(405, {
        "Content-Type": "application/json",
        Allow: "POST",
      });
      clientRes.end(
        JSON.stringify({
          success: false,
          error: "Method Not Allowed",
          allow: ["POST"],
        }),
      );
      return;
    }

    try {
      const oldCount = Object.keys(MOCK_ROUTES).length;
      loadConfig();
      const newCount = Object.keys(MOCK_ROUTES).length;

      clientRes.writeHead(200, { "Content-Type": "application/json" });
      clientRes.end(
        JSON.stringify({
          success: true,
          message: "Configuration reloaded successfully",
          routesCount: newCount,
          routesChanged: newCount - oldCount,
        }),
      );
      console.log(
        `[ADMIN] 通过API重新加载配置 (路由数: ${oldCount} -> ${newCount})`,
      );
    } catch (error) {
      clientRes.writeHead(500, { "Content-Type": "application/json" });
      clientRes.end(
        JSON.stringify({
          success: false,
          error: (error as Error).message,
        }),
      );
    }
    return;
  }

  if (requestPath === "/__config") {
    if (clientReq.method !== "GET") {
      clientRes.writeHead(405, {
        "Content-Type": "application/json",
        Allow: "GET",
      });
      clientRes.end(
        JSON.stringify({
          success: false,
          error: "Method Not Allowed",
          allow: ["GET"],
        }),
      );
      return;
    }

    try {
      clientRes.writeHead(200, { "Content-Type": "application/json" });
      clientRes.end(
        JSON.stringify(
          {
            routes: MOCK_ROUTES,
            config: CONFIG,
            timestamp: new Date().toISOString(),
            totalRoutes: Object.keys(MOCK_ROUTES).length,
          },
          null,
          2,
        ),
      );
    } catch (error) {
      clientRes.writeHead(500, { "Content-Type": "application/json" });
      clientRes.end(
        JSON.stringify({
          success: false,
          error: (error as Error).message,
        }),
      );
    }
    return;
  }

  // 检查是否为需要mock的路由
  if (isMockRoute(requestPath)) {
    const mockFile = getMockFilePath(requestPath);
    console.log(`[MOCK] 拦截路由: ${requestPath} -> 使用文件: ${mockFile}`);

    try {
      // 构建完整的文件路径
      const mockFilePath = path.join(__dirname, mockFile);

      // 检查文件是否存在
      if (!fs.existsSync(mockFilePath)) {
        console.error(`[MOCK] Mock文件不存在: ${mockFilePath}`);
        clientRes.writeHead(404, { "Content-Type": "application/json" });
        clientRes.end(
          JSON.stringify({
            error: "Mock file not found",
            route: requestPath,
            file: mockFile,
            timestamp: new Date().toISOString(),
          }),
        );
        return;
      }

      // 读取本地mock文件
      const mockData = fs.readFileSync(mockFilePath, "utf-8");

      // 设置响应头
      const contentType = CONFIG.defaultContentType || "application/json";
      clientRes.writeHead(200, {
        "Content-Type": contentType,
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
        "Access-Control-Allow-Headers": "Content-Type",
        "X-Mock-Source": mockFile,
        "X-Mock-Timestamp": new Date().toISOString(),
      });

      // 返回mock数据
      clientRes.end(mockData);
      console.log(`[MOCK] 成功返回mock数据: ${mockFile}`);
    } catch (error) {
      console.error(`[MOCK] 读取mock文件失败: ${mockFile}`, error);
      clientRes.writeHead(500, { "Content-Type": "application/json" });
      clientRes.end(
        JSON.stringify({
          error: "Failed to read mock data",
          route: requestPath,
          file: mockFile,
          message: (error as Error).message,
          timestamp: new Date().toISOString(),
        }),
      );
    }
    return; // 直接返回，不转发到目标服务器
  }

  // 如果不是mock路由，正常代理转发
  console.log(`[PROXY] 转发请求: ${requestPath}`);

  const targetPort = CONFIG.targetPort ?? 443;

  // 目标服务器的选项
  const options: http.RequestOptions = {
    hostname: CONFIG.targetHost,
    port: targetPort,
    method: clientReq.method,
    path: parsedUrl.pathname + parsedUrl.search,
    headers: {
      ...clientReq.headers,
      host: CONFIG.targetHost,
    },
  };

  // 创建到目标服务器的 HTTPS 请求
  const proxyReq = https.request(options, (proxyRes) => {
    // 将目标服务器的响应头复制到客户端响应
    clientRes.writeHead(proxyRes.statusCode!, proxyRes.headers);
    // 将目标服务器的响应数据管道传输到客户端
    proxyRes.pipe(clientRes);
  });

  // 错误处理
  proxyReq.on("error", (err) => {
    console.error("Proxy request error:", err);
    clientRes.writeHead(500, { "Content-Type": "application/json" });
    clientRes.end(
      JSON.stringify({
        error: "Proxy error",
        message: err.message,
        timestamp: new Date().toISOString(),
      }),
    );
  });

  // 将客户端请求体管道传输到代理请求
  clientReq.pipe(proxyReq);
});

// 初始化：第一次加载配置
loadConfig();

// 如果配置了文件监视，则监听配置文件变化
if (CONFIG.reloadOnChange) {
  fs.watchFile(CONFIG_FILE, (curr, prev) => {
    console.log(`[CONFIG] 配置文件已修改，重新加载...`);
    try {
      const oldRoutesCount = Object.keys(MOCK_ROUTES).length;
      loadConfig();
      const newRoutesCount = Object.keys(MOCK_ROUTES).length;
      console.log(
        `[CONFIG] 配置重载完成 (路由数: ${oldRoutesCount} -> ${newRoutesCount})`,
      );
    } catch (error) {
      console.error(`[CONFIG] 重新加载配置文件失败:`, error);
    }
  });
  console.log(`[CONFIG] 已启用配置文件监视: ${CONFIG_FILE}`);
}

proxyServer.listen(CONFIG.proxyPort, "0.0.0.0", () => {
  const targetPort = CONFIG.targetPort ?? 443;
  console.log(`========================================`);
  console.log(`代理服务器运行在: http://localhost:${CONFIG.proxyPort}`);
  console.log(
    `目标服务器: https://${CONFIG.targetHost}${targetPort !== 443 ? `:${targetPort}` : ""}`,
  );
  console.log(`配置文件: ${CONFIG_FILE}`);
  console.log(
    `已配置Mock路由: ${Object.keys(MOCK_ROUTES).length} 个${CONFIG.mockEnabled !== false ? "" : "（当前 mockEnabled=false，未生效）"}`,
  );
  console.log(`========================================`);
  console.log(`管理接口:`);
  console.log(
    `  GET http://localhost:${CONFIG.proxyPort}/__config    查看当前配置`,
  );
  console.log(
    `  POST http://localhost:${CONFIG.proxyPort}/__reload-config 重新加载配置`,
  );
  console.log(`========================================`);
  console.log(`Mock路由列表:`);

  for (const [route, file] of Object.entries(MOCK_ROUTES)) {
    const filePath = path.join(__dirname, file);
    const exists = fs.existsSync(filePath) ? "✓" : "✗";
    console.log(`  ${exists} ${route} -> ${file}`);
  }
  console.log(`========================================`);
});
