import assert from "node:assert/strict";
import test from "node:test";
import {
  collectXhsMetricsFromMcp,
  resolveCollectionMcpConfig,
  resolveXhsPublicAccountDetails,
  resolveXhsPublicAccountId,
  resolveXhsAccountProfileFromMcp,
  resolveXhsProfileDetailsFromMcp,
  xhsNoteIdFromUrl,
} from "../lib/mcp-collection-client.ts";

function sse(payload, options = {}) {
  return new Response(
    `event: message\ndata: ${JSON.stringify(payload)}\n\n`,
    {
      status: 200,
      ...options,
      headers: {
        "content-type": "text/event-stream",
        ...(options.headers ?? {}),
      },
    },
  );
}

function toolEnvelope(payload, isError = false) {
  return {
    jsonrpc: "2.0",
    id: "tool-call",
    result: {
      isError,
      content: [
        {
          type: "text",
          text: JSON.stringify(payload),
        },
      ],
    },
  };
}

function createFakeMcp(toolResults) {
  let toolIndex = 0;
  const calls = [];
  const fetchImpl = async (url, init) => {
    const body = JSON.parse(init.body);
    calls.push({ url: String(url), body, headers: new Headers(init.headers) });
    if (body.method === "initialize") {
      return sse(
        {
          jsonrpc: "2.0",
          id: body.id,
          result: {
            protocolVersion: "2025-03-26",
            capabilities: { tools: { listChanged: false } },
            serverInfo: { name: "ai-tool-center", version: "test" },
          },
        },
        { headers: { "mcp-session-id": "session-test" } },
      );
    }
    if (body.method === "notifications/initialized") {
      return new Response("", { status: 202 });
    }
    if (body.method === "tools/call") {
      const result = toolResults[toolIndex];
      toolIndex += 1;
      return sse(result);
    }
    throw new Error(`Unexpected MCP method: ${body.method}`);
  };
  return { calls, fetchImpl };
}

test("collects likes, comments and favorites from the verified MCP shape", async () => {
  const { calls, fetchImpl } = createFakeMcp([
    toolEnvelope({
      http_status: 200,
      response: {
        code: 200,
        success: true,
        msg: "获取内容详情成功",
        data: {
          likes: "483",
          comments: "41",
          collects: "519",
        },
      },
    }),
  ]);

  const result = await collectXhsMetricsFromMcp(
    "https://www.xiaohongshu.com/discovery/item/test?xsec_token=valid",
    {
      endpoint: "https://collector.example/mcp",
      key: "test-key",
    },
    fetchImpl,
  );

  assert.deepEqual(result, {
    likes: 483,
    comments: 41,
    collects: 519,
  });
  assert.equal(calls.length, 3);
  assert.equal(calls[2].body.params.name, "fetch_content_detail");
  assert.equal(calls[2].body.params.arguments.request.include_comments, false);
  assert.equal(calls[2].headers.get("mcp-session-id"), "session-test");
  assert.equal(new URL(calls[0].url).searchParams.get("key"), "test-key");
});

test("collects through a stateless MCP server without a session header", async () => {
  const calls = [];
  const fetchImpl = async (_url, init) => {
    const body = JSON.parse(init.body);
    calls.push({ body, headers: new Headers(init.headers) });
    if (body.method === "initialize") {
      return sse({
        jsonrpc: "2.0",
        id: body.id,
        result: {
          protocolVersion: "2025-03-26",
          capabilities: { tools: { listChanged: false } },
          serverInfo: { name: "ai-tool-center", version: "production" },
        },
      });
    }
    if (body.method === "tools/call") {
      return sse(
        toolEnvelope({
          response: {
            code: 200,
            success: true,
            data: { likes: 12, comments: 3, collects: 6 },
          },
        }),
      );
    }
    throw new Error(`Unexpected MCP method: ${body.method}`);
  };

  const result = await collectXhsMetricsFromMcp(
    "https://www.xiaohongshu.com/explore/test",
    { endpoint: "https://collector.example/mcp", key: "test-key" },
    fetchImpl,
  );

  assert.deepEqual(result, { likes: 12, comments: 3, collects: 6 });
  assert.deepEqual(
    calls.map((call) => call.body.method),
    ["initialize", "tools/call"],
  );
  assert.equal(calls[1].headers.get("mcp-session-id"), null);
});

test("resolves the real XHS account profile from a submitted note link", async () => {
  const { calls, fetchImpl } = createFakeMcp([
    toolEnvelope({
      response: {
        code: 200,
        success: true,
        data: {
          note_detail: {
            products: [
              {
                content_tags: [
                  {
                    notes: [
                      {
                        ip_location: "重庆",
                        note_id: "6a671108000000000f004bef",
                        user: {
                          nickname: "N我的麻辣烫好了吗",
                          profile_url:
                            "https://www.xiaohongshu.com/user/profile/6905cbca0000000037009f49",
                          red_id: "94329495984",
                          user_id: "6905cbca0000000037009f49",
                        },
                      },
                    ],
                  },
                ],
              },
            ],
          },
        },
      },
    }),
    toolEnvelope({
      response: {
        code: 200,
        success: true,
        data: {
          fans_count: "734",
        },
      },
    }),
  ]);

  const profile = await resolveXhsAccountProfileFromMcp(
    "https://www.xiaohongshu.com/discovery/item/6a671108000000000f004bef",
    "回填昵称",
    {
      endpoint: "https://collector.example/mcp",
      key: "test-key",
    },
    fetchImpl,
  );

  assert.deepEqual(profile, {
    platformUid: "6905cbca0000000037009f49",
    nickname: "N我的麻辣烫好了吗",
    profileUrl:
      "https://www.xiaohongshu.com/user/profile/6905cbca0000000037009f49",
    redId: "94329495984",
    ipLocation: "重庆",
    followers: 734,
  });
  assert.equal(calls.length, 4);
  assert.equal(
    calls[2].body.params.name,
    "collect_xhs_wen_note_detail",
  );
  assert.equal(
    calls[2].body.params.arguments.request.note_id,
    "6a671108000000000f004bef",
  );
  assert.equal(calls[3].body.params.name, "parse_xhs_user_summary");
  assert.equal(
    calls[3].body.params.arguments.request.url,
    "https://www.xiaohongshu.com/user/profile/6905cbca0000000037009f49",
  );
  assert.equal(
    xhsNoteIdFromUrl(
      "https://www.xiaohongshu.com/explore/6a671108000000000f004bef",
    ),
    "6a671108000000000f004bef",
  );
});

test("resolves followers directly from the supported XHS user summary tool", async () => {
  const { calls, fetchImpl } = createFakeMcp([
    toolEnvelope({
      response: {
        code: 200,
        success: true,
        msg: "用户摘要解析成功",
        data: {
          user: {
            fansCount: 6,
            ipLocation: "福建",
            nickname: "555 五",
            userId: "1020668113",
          },
        },
      },
    }),
  ]);

  const details = await resolveXhsProfileDetailsFromMcp(
    "https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e",
    {
      endpoint: "https://collector.example/mcp",
      key: "test-key",
    },
    fetchImpl,
  );

  assert.deepEqual(details, {
    nickname: "555 五",
    followers: 6,
    redId: "1020668113",
    ipLocation: "福建",
  });
  assert.equal(calls[2].body.params.name, "parse_xhs_user_summary");
});

test("resolves an xhslink short URL before requesting the author profile", async () => {
  const fakeMcp = createFakeMcp([
    toolEnvelope({
      response: {
        code: 200,
        success: true,
        data: {
          note_detail: {
            note_id: "6a572da40000000021018bd2",
            ip_location: "上海",
            user: {
              nickname: "短链作者",
              user_id: "6905cbca0000000037009f49",
            },
          },
        },
      },
    }),
    toolEnvelope({
      response: {
        code: 200,
        success: true,
        data: {
          red_id: "1020668113",
          followers: "1.2万",
        },
      },
    }),
  ]);
  const fetchImpl = async (url, init) => {
    if (String(url) === "http://xhslink.cn/o/AJFyP5dnj7O") {
      return new Response(null, {
        status: 302,
        headers: {
          location:
            "https://www.xiaohongshu.com/discovery/item/6a572da40000000021018bd2?xsec_token=valid",
        },
      });
    }
    return fakeMcp.fetchImpl(url, init);
  };

  const profile = await resolveXhsAccountProfileFromMcp(
    "http://xhslink.cn/o/AJFyP5dnj7O",
    "回填昵称",
    {
      endpoint: "https://collector.example/mcp",
      key: "test-key",
    },
    fetchImpl,
  );

  assert.equal(profile.nickname, "短链作者");
  assert.equal(profile.platformUid, "6905cbca0000000037009f49");
  assert.equal(profile.redId, "1020668113");
  assert.equal(profile.followers, 12_000);
  assert.equal(
    profile.profileUrl,
    "https://www.xiaohongshu.com/user/profile/6905cbca0000000037009f49",
  );
  assert.equal(
    fakeMcp.calls[2].body.params.arguments.request.note_id,
    "6a572da40000000021018bd2",
  );
});

test("uses the public note author when MCP profile lookup fails", async () => {
  const fakeMcp = createFakeMcp([
    toolEnvelope(
      {
        response: {
          code: 500,
          success: false,
          msg: "作者详情暂时不可用",
        },
      },
      true,
    ),
  ]);
  const fetchImpl = async (url, init) => {
    if (String(url) === "http://xhslink.cn/o/AJFyP5dnj7O") {
      return new Response(
        '<script>window.__STATE__={&quot;noteData&quot;:{&quot;desc&quot;:&quot;测试&quot;,&quot;user&quot;:{&quot;userId&quot;:&quot;5fb21d32000000000101c23e&quot;,&quot;nickName&quot;:&quot;555 五&quot;}}}</script>',
        {
          status: 200,
          headers: {
            "content-type": "text/html; charset=utf-8",
            location:
              "https://www.xiaohongshu.com/discovery/item/6a572da40000000021018bd2?xsec_token=valid",
          },
        },
      );
    }
    if (
      String(url) ===
      "https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e"
    ) {
      return new Response(
        '<script>{"redId":"1020668113","interactions":[{"name":"粉丝","count":"6","i18nCount":"6"}]}</script>',
        { status: 200 },
      );
    }
    return fakeMcp.fetchImpl(url, init);
  };

  const profile = await resolveXhsAccountProfileFromMcp(
    "http://xhslink.cn/o/AJFyP5dnj7O",
    "回填昵称",
    {
      endpoint: "https://collector.example/mcp",
      key: "test-key",
    },
    fetchImpl,
  );

  assert.deepEqual(profile, {
    platformUid: "5fb21d32000000000101c23e",
    nickname: "555 五",
    profileUrl:
      "https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e",
    redId: "1020668113",
    ipLocation: "待识别",
    followers: 6,
  });
  assert.equal(
    fakeMcp.calls[2].body.params.name,
    "collect_xhs_wen_note_detail",
  );
});

test("reads the user-visible Xiaohongshu number from a public profile", async () => {
  const fetchImpl = async () =>
    new Response(
      '<div class="redId">小红书号：1020668113</div><script>{"redId":"1020668113","interactions":[{"name":"粉丝","count":"10+","i18nCount":"10+"}]}</script>',
      { status: 200 },
    );
  const accountId = await resolveXhsPublicAccountId(
    "https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e",
    fetchImpl,
  );
  const details = await resolveXhsPublicAccountDetails(
    "https://www.xiaohongshu.com/user/profile/5fb21d32000000000101c23e",
    fetchImpl,
  );

  assert.equal(accountId, "1020668113");
  assert.deepEqual(details, {
    nickname: "",
    redId: "1020668113",
    followers: 10,
    ipLocation: "",
  });
});

test("falls back to parse_xhs_note when the primary tool fails", async () => {
  const { calls, fetchImpl } = createFakeMcp([
    toolEnvelope(
      {
        response: {
          code: 400,
          success: false,
          msg: "获取内容详情失败",
          data: null,
        },
      },
      true,
    ),
    toolEnvelope({
      response: {
        code: 200,
        success: true,
        data: {
          likes: "1.2万",
          comments: 32,
          collects: "2,345",
        },
      },
    }),
  ]);

  const result = await collectXhsMetricsFromMcp(
    "https://www.xiaohongshu.com/explore/test",
    {
      endpoint: "https://collector.example/mcp?key=test-key",
    },
    fetchImpl,
  );

  assert.deepEqual(result, {
    likes: 12_000,
    comments: 32,
    collects: 2_345,
  });
  assert.equal(calls[3].body.params.name, "parse_xhs_note");
});

test("requires the MCP key without sending a network request", async () => {
  let requested = false;
  await assert.rejects(
    collectXhsMetricsFromMcp(
      "https://www.xiaohongshu.com/explore/test",
      resolveCollectionMcpConfig({}),
      async () => {
        requested = true;
        return new Response();
      },
    ),
    /MCP采集密钥未配置/,
  );
  assert.equal(requested, false);
});

test("rebuilds the MCP session after a gateway session miss", async () => {
  let initializeCount = 0;
  const fetchImpl = async (_url, init) => {
    const body = JSON.parse(init.body);
    if (body.method === "initialize") {
      initializeCount += 1;
      return sse(
        {
          jsonrpc: "2.0",
          id: body.id,
          result: {
            protocolVersion: "2025-03-26",
            capabilities: { tools: { listChanged: false } },
            serverInfo: { name: "ai-tool-center", version: "test" },
          },
        },
        {
          headers: {
            "mcp-session-id": `session-${initializeCount}`,
          },
        },
      );
    }
    if (
      body.method === "notifications/initialized" &&
      initializeCount === 1
    ) {
      return Response.json(
        {
          jsonrpc: "2.0",
          id: "server-error",
          error: { code: -32600, message: "Session not found" },
        },
        { status: 404 },
      );
    }
    if (body.method === "notifications/initialized") {
      return new Response("", { status: 202 });
    }
    if (body.method === "tools/call") {
      return sse(
        toolEnvelope({
          response: {
            code: 200,
            success: true,
            data: { likes: 8, comments: 2, collects: 5 },
          },
        }),
      );
    }
    throw new Error(`Unexpected MCP method: ${body.method}`);
  };

  const result = await collectXhsMetricsFromMcp(
    "https://www.xiaohongshu.com/explore/test",
    {
      endpoint: "https://collector.example/mcp",
      key: "test-key",
    },
    fetchImpl,
  );

  assert.deepEqual(result, { likes: 8, comments: 2, collects: 5 });
  assert.equal(initializeCount, 2);
});
