// ====== 1. 引入和设置 ======
import Fastify from 'fastify';
import mongoPlugin from '@fastify/mongodb';
import { ObjectId } from 'mongodb';
import { request as undiciRequest } from 'undici';

const fastify = Fastify({
  logger: true, // 启用日志记录
});


// 你的 MongoDB 连接字符串
const mongoConnectionString = "mongodb://mongo_c6bNmG:mongo_tyNkXh@83.229.121.44:27017/todo_app_fastify?authSource=admin";

// ====== 2. 注册 MongoDB 插件 ======
// fastify.register() 是 Fastify 插件系统的核心
// 我们在这里告诉 Fastify：“请加载 @fastify/mongodb 插件，
// 并使用这个连接字符串去连接数据库。”
fastify.register(mongoPlugin, {
  forceClose: true, // 在应用关闭时强制关闭连接
  url: mongoConnectionString,
});
// 插件注册后，Fastify 的实例上会多出一个 `mongo` 对象 (`fastify.mongo`)
// 我们可以通过它来访问数据库和 ObjectId 等工具。

// ====== 3. 创建 CRUD 路由 ======
// 我们将创建一个简单的 "items" 集合来存放商品

fastify.get('/', async (request, reply) => {
  return { message: '欢迎来到 Fastify 核心功能示例!'};
})

const createUserSchema = {
  // body 部分定义了对 POST 请求体的验证规则
  body: {
    type: 'object',
    required: ['name', 'email'], // name 和 email 字段是必需的
    properties: {
      name: { type: 'string' },
      email: { type: 'string', format: 'email' }, // 甚至可以验证 email 格式
    },
  },
  //response 部分定义了响应的格式，Fastify 会用它来极速序列化 JSON
  response: {
    201: { // 201 状态码对应的响应格式
      type: 'object',
      properties: {
        _id: { type: 'string' },
        name: { type: 'string' },
        email: { type: 'string' },
      },
      // 建议明确哪些字段是必须返回的
      required: ['_id', 'name', 'email'],
    },
  },
};

// --- CREATE (增) ---
// 创建一个新商品
fastify.post('/users',{ schema : createUserSchema}, async (request, reply) => {
  // `fastify.mongo.db` 指向你连接的那个数据库实例 (my-beginner-db)
  const itemsCollection = fastify.mongo.db.collection('items');
  
  // request.body 包含了 POST 请求发来的 JSON 数据
  const newUsers = request.body;
  
  // 调用 MongoDB 的 insertOne 方法插入数据
  const result = await itemsCollection.insertOne(newUsers);
  fastify.log.info({ msg: '用户创建成功', result: result });
  
  if (!result.acknowledged) {
    return reply.status(500).send({ message: 'Failed to insert user into database' });
  }

  // 关键修改：我们需要构建一个对象，使其结构精确匹配 response.201 schema
  const responsePayload = {
    _id: result.insertedId.toString(), // 将 ObjectId 转换为字符串
    name: newUsers.name,           // 从原始请求体中获取 name
    email: newUsers.email,         // 从原始请求体中获取 email
  };

  // 现在 responsePayload 的结构完全符合 response.201 schema
  return reply.status(201).send(responsePayload); // 发送这个符合 schema 的对象
});



// --- 正确实现的 Hook ---
fastify.addHook('onRequest', async (request, reply) => {
  // 这个钩子会在每个请求匹配到路由之前执行
  fastify.log.info(`收到一个 ${request.method} 请求，访问路径: ${request.url}`);

  // --- 转发到 Gotify ---
  const gotifyPayload = {
    title: "新请求通知",
    message: `收到 ${request.method} 请求,ip ${request.ip}路径: ${request.url}`,
    priority: 5,
  };

  fastify.log.info("准备向 Gotify 发送通知...");

  // 2.【关键】采用“即发即忘”模式，不要使用 await 来阻塞主流程
  undiciRequest('https://gotify.zotv.ru/message?token=A1wFaeaj-VskqyF', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(gotifyPayload),
  })
  .then(response => {
    // 可选：如果成功，可以在后台记录一下
    // 注意：这里的 .statusCode 是 undici v5 及更早版本的用法，新版可能不同
    if (response.statusCode >= 200 && response.statusCode < 300) {
      fastify.log.info("Gotify 通知发送成功！");
    } else {
      fastify.log.warn(`Gotify 通知发送异常，状态码: ${response.statusCode}`);
    }
    // 消耗掉响应体，防止内存泄漏
    return response.body.dump();
  })
  .catch(error => {
    // 3.【关键】必须捕获错误，否则一个失败的通知会让你的整个服务器进程崩溃！
    fastify.log.error({ msg: 'Gotify 通知发送失败', err: error });
  });

  // 4.【关键】注意，这里没有 await，钩子函数会立即执行完毕，不会等待通知结果
});

// --- READ (查) ---
// 获取所有商品
fastify.get('/users', async (request, reply) => {
  const itemsCollection = fastify.mongo.db.collection('items');
  const items = await itemsCollection.find({}).toArray();
  return items;
});

// 获取单个商品 (通过 ID)
fastify.get('/items/:id', async (request, reply) => {
  const itemsCollection = fastify.mongo.db.collection('items');
  
  // **关键点**: MongoDB 的 `_id` 是一个特殊的 ObjectId 类型, 不是普通字符串。
  // 我们需要从 fastify.mongo 获取 ObjectId 构造函数来转换 URL 中的 id 参数。
  const { ObjectId } = fastify.mongo;
  const idToFind = new ObjectId(request.params.id);

  const item = await itemsCollection.findOne({ _id: idToFind });

  if (!item) {
    return reply.status(404).send({ error: '商品未找到' });
  }
  return item;
});

// --- UPDATE (改) ---
// 更新一个商品
fastify.put('/items/:id', async (request, reply) => {
  const itemsCollection = fastify.mongo.db.collection('items');
  const { ObjectId } = fastify.mongo;
  const idToUpdate = new ObjectId(request.params.id);
  
  const updateData = request.body;
  
  const result = await itemsCollection.updateOne(
    { _id: idToUpdate }, // 筛选条件
    { $set: updateData } // 更新操作
  );
  
  if (result.modifiedCount === 0) {
     return reply.status(404).send({ error: '未找到商品或无需更新' });
  }

  return { message: '商品更新成功' };
});

// --- DELETE (删) ---
// 删除一个商品
fastify.delete('/items/:id', async (request, reply) => {
  const itemsCollection = fastify.mongo.db.collection('items');
  const { ObjectId } = fastify.mongo;
  const idToDelete = new ObjectId(request.params.id);
  
  const result = await itemsCollection.deleteOne({ _id: idToDelete });
  
  if (result.deletedCount === 0) {
    return reply.status(404).send({ error: '商品未找到' });
  }

  // 204 No Content 是一个常见的成功删除的响应
  return reply.status(204).send(idToDelete);
});


// ====== 4. 启动服务器 ======
const start = async () => {
  try {
    await fastify.listen({ port: 3000, host: '0.0.0.0' });
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();