import assert from "node:assert/strict";
import test from "node:test";
import { env } from "../src/env.js";
import { resetBraveRateLimitStateForTests, searchBrave } from "../src/search/brave.js";

test("searchBrave authenticates, builds filters, and normalizes web results", async () => {
  const originalFetch = globalThis.fetch;
  const originalApiKey = env.BRAVE_SEARCH_API_KEY;
  const fetchCalls: Array<{ input: RequestInfo | URL; init?: RequestInit }> = [];
  resetBraveRateLimitStateForTests();
  env.BRAVE_SEARCH_API_KEY = "test-brave-key";
  globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
    fetchCalls.push({ input, init });
    return new Response(
      JSON.stringify({
        web: {
          results: [
            {
              title: " Brave result ",
              url: "https://docs.example.com/article",
              description: "Main\n snippet",
              extra_snippets: ["Extra snippet one", "Extra snippet two"],
              page_age: "2026-07-18T12:00:00Z",
              profile: { name: "Example Docs" },
            },
            {
              title: "Excluded result",
              url: "https://blocked.example.com/article",
              description: "Should be filtered",
            },
          ],
        },
      }),
      {
        status: 200,
        headers: {
          "content-type": "application/json; charset=utf-8",
          "x-request-id": "brave-request-1",
        },
      }
    );
  }) as typeof fetch;

  try {
    const response = await searchBrave("latest docs", {
      numResults: 5,
      includeDomains: ["https://example.com/path"],
      excludeDomains: ["blocked.example.com"],
    });

    assert.equal(fetchCalls.length, 1);
    const requestUrl = new URL(String(fetchCalls[0]?.input));
    assert.equal(requestUrl.origin + requestUrl.pathname, "https://api.search.brave.com/res/v1/web/search");
    assert.equal(requestUrl.searchParams.get("q"), "latest docs site:example.com -site:blocked.example.com");
    assert.equal(requestUrl.searchParams.get("count"), "5");
    assert.equal(requestUrl.searchParams.get("safesearch"), "moderate");
    assert.equal(requestUrl.searchParams.get("result_filter"), "web");
    assert.equal(requestUrl.searchParams.get("text_decorations"), "false");
    assert.equal(requestUrl.searchParams.get("extra_snippets"), "true");
    assert.equal((fetchCalls[0]?.init?.headers as Record<string, string>)["X-Subscription-Token"], "test-brave-key");

    assert.deepEqual(response, {
      query: "latest docs",
      requestId: "brave-request-1",
      results: [
        {
          title: "Brave result",
          url: "https://docs.example.com/article",
          publishedDate: "2026-07-18T12:00:00Z",
          author: "Example Docs",
          summary: "Main snippet",
          text: "Main snippet\n\nExtra snippet one\n\nExtra snippet two",
          highlights: ["Main snippet", "Extra snippet one", "Extra snippet two"],
        },
      ],
    });
  } finally {
    globalThis.fetch = originalFetch;
    env.BRAVE_SEARCH_API_KEY = originalApiKey;
  }
});

test("searchBrave rejects requests without an API key", async () => {
  const originalApiKey = env.BRAVE_SEARCH_API_KEY;
  resetBraveRateLimitStateForTests();
  env.BRAVE_SEARCH_API_KEY = undefined;
  try {
    await assert.rejects(() => searchBrave("test", { numResults: 1 }), /BRAVE_SEARCH_API_KEY not set/);
  } finally {
    env.BRAVE_SEARCH_API_KEY = originalApiKey;
  }
});

test("searchBrave reports non-JSON responses", async () => {
  const originalFetch = globalThis.fetch;
  const originalApiKey = env.BRAVE_SEARCH_API_KEY;
  resetBraveRateLimitStateForTests();
  env.BRAVE_SEARCH_API_KEY = "test-brave-key";
  globalThis.fetch = (async () =>
    new Response("upstream error", {
      status: 200,
      headers: { "content-type": "text/plain" },
    })) as typeof fetch;

  try {
    await assert.rejects(
      () => searchBrave("test", { numResults: 1 }),
      /Brave Search API returned text\/plain/
    );
  } finally {
    globalThis.fetch = originalFetch;
    env.BRAVE_SEARCH_API_KEY = originalApiKey;
  }
});

test("searchBrave evenly paces concurrent bursts using Brave's shortest policy window", async () => {
  const originalFetch = globalThis.fetch;
  const originalApiKey = env.BRAVE_SEARCH_API_KEY;
  const requestStartedAt: number[] = [];
  resetBraveRateLimitStateForTests();
  env.BRAVE_SEARCH_API_KEY = "test-brave-key";
  globalThis.fetch = (async () => {
    requestStartedAt.push(Date.now());
    return new Response(JSON.stringify({ web: { results: [] } }), {
      status: 200,
      headers: {
        "content-type": "application/json",
        "x-ratelimit-policy": "1;w=1, 2000;w=2678400",
        "x-ratelimit-remaining": "1, 1999",
        "x-ratelimit-reset": "1, 2678400",
      },
    });
  }) as typeof fetch;

  try {
    await Promise.all([
      searchBrave("burst one", { numResults: 1 }),
      searchBrave("burst two", { numResults: 1 }),
      searchBrave("burst three", { numResults: 1 }),
    ]);

    assert.equal(requestStartedAt.length, 3);
    assert.ok(requestStartedAt[1]! - requestStartedAt[0]! >= 1_000);
    assert.ok(requestStartedAt[2]! - requestStartedAt[1]! >= 1_000);
  } finally {
    globalThis.fetch = originalFetch;
    env.BRAVE_SEARCH_API_KEY = originalApiKey;
    resetBraveRateLimitStateForTests();
  }
});

test("searchBrave adapts its pacing to a 50 request-per-second Search plan", async () => {
  const originalFetch = globalThis.fetch;
  const originalApiKey = env.BRAVE_SEARCH_API_KEY;
  const requestStartedAt: number[] = [];
  resetBraveRateLimitStateForTests();
  env.BRAVE_SEARCH_API_KEY = "test-brave-key";
  globalThis.fetch = (async () => {
    requestStartedAt.push(Date.now());
    return new Response(JSON.stringify({ web: { results: [] } }), {
      status: 200,
      headers: {
        "content-type": "application/json",
        "x-ratelimit-policy": "50;w=1, 0;w=2678400",
        "x-ratelimit-remaining": "49, 0",
        "x-ratelimit-reset": "1, 2678400",
      },
    });
  }) as typeof fetch;

  try {
    await searchBrave("learn upgraded policy", { numResults: 1 });
    await Promise.all(Array.from({ length: 8 }, (_, index) => searchBrave(`fast burst ${index}`, { numResults: 1 })));

    assert.equal(requestStartedAt.length, 9);
    const burstStartedAt = requestStartedAt.slice(1);
    for (let index = 1; index < burstStartedAt.length; index += 1) {
      assert.ok(burstStartedAt[index]! - burstStartedAt[index - 1]! >= 18);
    }
    assert.ok(burstStartedAt.at(-1)! - burstStartedAt[0]! < 500);
  } finally {
    globalThis.fetch = originalFetch;
    env.BRAVE_SEARCH_API_KEY = originalApiKey;
    resetBraveRateLimitStateForTests();
  }
});

test("searchBrave retries 429 responses after the burst window resets", async () => {
  const originalFetch = globalThis.fetch;
  const originalApiKey = env.BRAVE_SEARCH_API_KEY;
  let fetchCount = 0;
  resetBraveRateLimitStateForTests();
  env.BRAVE_SEARCH_API_KEY = "test-brave-key";
  globalThis.fetch = (async () => {
    fetchCount += 1;
    const rateLimitHeaders = {
      "content-type": "application/json",
      "x-ratelimit-policy": "1;w=1, 2000;w=2678400",
      "x-ratelimit-remaining": fetchCount === 1 ? "0, 1999" : "1, 1998",
      "x-ratelimit-reset": "1, 2678400",
    };
    if (fetchCount === 1) {
      return new Response(JSON.stringify({ error: { detail: "Rate limit exceeded" } }), {
        status: 429,
        headers: rateLimitHeaders,
      });
    }
    return new Response(JSON.stringify({ web: { results: [] } }), { status: 200, headers: rateLimitHeaders });
  }) as typeof fetch;

  try {
    const startedAt = Date.now();
    await searchBrave("retry burst", { numResults: 1 });
    assert.equal(fetchCount, 2);
    assert.ok(Date.now() - startedAt >= 1_000);
  } finally {
    globalThis.fetch = originalFetch;
    env.BRAVE_SEARCH_API_KEY = originalApiKey;
    resetBraveRateLimitStateForTests();
  }
});

test("searchBrave does not wait for exhausted long-term quotas", async () => {
  const originalFetch = globalThis.fetch;
  const originalApiKey = env.BRAVE_SEARCH_API_KEY;
  resetBraveRateLimitStateForTests();
  env.BRAVE_SEARCH_API_KEY = "test-brave-key";
  globalThis.fetch = (async () =>
    new Response(JSON.stringify({ error: { detail: "Quota exceeded" } }), {
      status: 429,
      headers: {
        "content-type": "application/json",
        "x-ratelimit-policy": "1;w=1, 2000;w=2678400",
        "x-ratelimit-remaining": "0, 0",
        "x-ratelimit-reset": "1, 100000",
      },
    })) as typeof fetch;

  try {
    const startedAt = Date.now();
    await assert.rejects(
      () => searchBrave("quota exhausted", { numResults: 1 }),
      /rate limit quota is exhausted beyond the retry window/
    );
    assert.ok(Date.now() - startedAt < 1_000);
  } finally {
    globalThis.fetch = originalFetch;
    env.BRAVE_SEARCH_API_KEY = originalApiKey;
    resetBraveRateLimitStateForTests();
  }
});

test("searchBrave blocks locally after a successful request exhausts the long-term quota", async () => {
  const originalFetch = globalThis.fetch;
  const originalApiKey = env.BRAVE_SEARCH_API_KEY;
  let fetchCount = 0;
  resetBraveRateLimitStateForTests();
  env.BRAVE_SEARCH_API_KEY = "test-brave-key";
  globalThis.fetch = (async () => {
    fetchCount += 1;
    return new Response(JSON.stringify({ web: { results: [] } }), {
      status: 200,
      headers: {
        "content-type": "application/json",
        "x-ratelimit-policy": "1;w=1, 2000;w=2678400",
        "x-ratelimit-remaining": "0, 0",
        "x-ratelimit-reset": "1, 100000",
      },
    });
  }) as typeof fetch;

  try {
    await searchBrave("last allowed query", { numResults: 1 });
    await assert.rejects(
      () => searchBrave("over quota query", { numResults: 1 }),
      /long-term quota is exhausted/
    );
    assert.equal(fetchCount, 1);
  } finally {
    globalThis.fetch = originalFetch;
    env.BRAVE_SEARCH_API_KEY = originalApiKey;
    resetBraveRateLimitStateForTests();
  }
});
