/**
 * Unit tests for the Reasoning Replay Cache (Issue #1628).
 *
 * Covers: memory cache, DB fallback, hit/miss counters,
 * provider detection, and cleanup behavior.
 */

import { describe, it, before, after } from "node:test";
import assert from "node:assert/strict";

import { mkdtempSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";

process.env.DATA_DIR = mkdtempSync(join(tmpdir(), "omniroute-reasoning-"));
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "reasoning-cache-test-secret";

// ──────────── Direct service import ────────────

import {
  cacheReasoningFromAssistantMessage,
  cacheReasoning,
  cacheReasoningByKey,
  cacheReasoningBatch,
  deleteReasoningCacheEntry,
  getReasoningCacheServiceEntries,
  lookupReasoning,
  recordReplay,
  getReasoningCacheServiceStats,
  clearReasoningCacheAll,
  isDeepSeekReasoningModel,
  requiresReasoningReplay,
  cleanupReasoningCache,
} from "../../open-sse/services/reasoningCache.ts";
import { translateRequest } from "../../open-sse/translator/index.ts";
import { FORMATS } from "../../open-sse/translator/formats.ts";
import { ensureToolCallIds } from "../../open-sse/translator/helpers/toolCallHelper.ts";
import { getDbInstance } from "../../src/lib/db/core.ts";
import { getReasoningCache, setReasoningCache } from "../../src/lib/db/reasoningCache.ts";
import { DELETE, GET } from "../../src/app/api/cache/reasoning/route.ts";
import { createApiKey } from "../../src/lib/db/apiKeys.ts";
import { updateSettings } from "../../src/lib/db/settings";
import {
  clearModelsDevCapabilities,
  saveModelsDevCapabilities,
} from "../../src/lib/modelsDevSync.ts";

function buildCapability(overrides = {}) {
  return {
    tool_call: null,
    reasoning: null,
    attachment: null,
    structured_output: null,
    temperature: null,
    modalities_input: "[]",
    modalities_output: "[]",
    knowledge_cutoff: null,
    release_date: null,
    last_updated: null,
    status: null,
    family: null,
    open_weights: null,
    limit_context: null,
    limit_input: null,
    limit_output: null,
    interleaved_field: null,
    ...overrides,
  };
}

before(async () => {
  await updateSettings({ requireLogin: false });
});

after(async () => {
  await updateSettings({ requireLogin: true });
});

describe("Reasoning Replay Cache — Service Layer", () => {
  before(() => {
    // Start each suite with a clean slate
    clearReasoningCacheAll();
  });

  after(() => {
    clearReasoningCacheAll();
  });

  it("should store and retrieve reasoning by tool_call_id", () => {
    cacheReasoning(
      "call_test_1",
      "deepseek",
      "deepseek-reasoner",
      "The user wants to read the file..."
    );
    const result = lookupReasoning("call_test_1");
    assert.equal(result, "The user wants to read the file...");
    assert.equal(getReasoningCache("call_test_1")?.reasoning, "The user wants to read the file...");
  });

  it("should fall back to SQLite when memory misses", () => {
    clearReasoningCacheAll();
    setReasoningCache("call_db_only", "deepseek", "deepseek-reasoner", "DB-only reasoning");

    assert.equal(lookupReasoning("call_db_only"), "DB-only reasoning");

    const stats = getReasoningCacheServiceStats();
    assert.equal(stats.hits, 1);
    assert.equal(stats.memoryEntries, 1);
    assert.equal(stats.dbEntries, 1);
  });

  it("should return null for unknown tool_call_id", () => {
    const result = lookupReasoning("call_nonexistent");
    assert.equal(result, null);
  });

  it("should return null for empty tool_call_id", () => {
    const result = lookupReasoning("");
    assert.equal(result, null);
  });

  it("should skip caching when reasoning is empty", () => {
    cacheReasoning("call_empty", "deepseek", "deepseek-chat", "");
    const result = lookupReasoning("call_empty");
    assert.equal(result, null);
  });

  it("should cache reasoning for multiple tool_call_ids (batch)", () => {
    cacheReasoningBatch(
      ["call_batch_1", "call_batch_2", "call_batch_3"],
      "deepseek",
      "deepseek-reasoner",
      "Batch reasoning content"
    );
    assert.equal(lookupReasoning("call_batch_1"), "Batch reasoning content");
    assert.equal(lookupReasoning("call_batch_2"), "Batch reasoning content");
    assert.equal(lookupReasoning("call_batch_3"), "Batch reasoning content");
  });

  it("should capture assistant reasoning for all tool_call IDs", () => {
    clearReasoningCacheAll();

    const cached = cacheReasoningFromAssistantMessage(
      {
        role: "assistant",
        reasoning_content: "Captured assistant reasoning",
        tool_calls: [{ id: "call_capture_1" }, { id: "call_capture_2" }],
      },
      "deepseek",
      "deepseek-reasoner"
    );

    assert.equal(cached, 2);
    assert.equal(lookupReasoning("call_capture_1"), "Captured assistant reasoning");
    assert.equal(lookupReasoning("call_capture_2"), "Captured assistant reasoning");
  });

  it("should keep request message cache keys stable when tool call IDs change", () => {
    clearReasoningCacheAll();

    const requestId = "req_reasoning_stable";
    const messageIndex = 2;
    const cacheKey = `${requestId}:${messageIndex}`;
    const body = {
      messages: [
        {
          role: "assistant",
          tool_calls: [
            {
              id: "call_before_normalization",
              type: "function",
              function: { name: "lookup", arguments: { city: "Seoul" } },
            },
          ],
        },
        { role: "tool", content: "Sunny" },
      ],
    };

    cacheReasoning(cacheKey, "deepseek", "deepseek-reasoner", "Stable cached reasoning");
    const originalToolCallId = body.messages[0].tool_calls[0].id;

    ensureToolCallIds(body, { use9CharId: true });

    assert.notEqual(body.messages[0].tool_calls[0].id, originalToolCallId);
    assert.equal(lookupReasoning(cacheKey), "Stable cached reasoning");
  });

  it("should capture provider reasoning alias when reasoning_content is absent", () => {
    clearReasoningCacheAll();

    const cached = cacheReasoningFromAssistantMessage(
      {
        role: "assistant",
        reasoning: "Alias reasoning",
        tool_calls: [{ id: "call_capture_alias" }],
      },
      "kimi",
      "kimi-k2.5"
    );

    assert.equal(cached, 1);
    assert.equal(lookupReasoning("call_capture_alias"), "Alias reasoning");
  });

  it("should cache assistant reasoning without tool calls by request and message index", () => {
    clearReasoningCacheAll();

    const cached = cacheReasoningFromAssistantMessage(
      {
        role: "assistant",
        reasoning_content: "No tool call reasoning",
      },
      "deepseek",
      "deepseek-reasoner",
      { requestId: "req_no_tools", messageIndex: 3 }
    );

    assert.equal(cached, 1);
    assert.equal(lookupReasoning("request:req_no_tools:message:3"), "No tool call reasoning");
  });

  it("should skip assistant reasoning without tool calls when stable key context is absent", () => {
    clearReasoningCacheAll();

    const cached = cacheReasoningFromAssistantMessage(
      {
        role: "assistant",
        reasoning_content: "Missing key context",
      },
      "deepseek",
      "deepseek-reasoner"
    );

    assert.equal(cached, 0);
    assert.equal(lookupReasoning("request:req_missing:message:0"), null);
  });

  it("should store arbitrary reasoning cache keys", () => {
    clearReasoningCacheAll();

    cacheReasoningByKey(
      "request:req_direct:message:1",
      "deepseek",
      "deepseek-reasoner",
      "Keyed plan"
    );

    assert.equal(lookupReasoning("request:req_direct:message:1"), "Keyed plan");
    assert.equal(getReasoningCache("request:req_direct:message:1")?.reasoning, "Keyed plan");
  });

  it("should not overwrite if same tool_call_id is cached again", () => {
    cacheReasoning("call_overwrite", "deepseek", "deepseek-chat", "First reasoning");
    cacheReasoning("call_overwrite", "deepseek", "deepseek-chat", "Updated reasoning");
    // Second write wins (INSERT OR REPLACE)
    const result = lookupReasoning("call_overwrite");
    assert.equal(result, "Updated reasoning");
  });

  it("should track hits and misses correctly", () => {
    clearReasoningCacheAll();

    cacheReasoning("call_hit_test", "deepseek", "deepseek-chat", "test reasoning");

    lookupReasoning("call_hit_test"); // hit
    lookupReasoning("call_hit_test"); // hit
    lookupReasoning("call_miss_test"); // miss

    const stats = getReasoningCacheServiceStats();
    assert.ok(stats.hits >= 2, `Expected at least 2 hits, got ${stats.hits}`);
    assert.ok(stats.misses >= 1, `Expected at least 1 miss, got ${stats.misses}`);
  });

  it("should track replays", () => {
    clearReasoningCacheAll();

    recordReplay();
    recordReplay();
    recordReplay();

    const stats = getReasoningCacheServiceStats();
    assert.ok(stats.replays >= 3, `Expected at least 3 replays, got ${stats.replays}`);
  });

  it("should report correct stats structure", () => {
    clearReasoningCacheAll();

    cacheReasoning("call_stat_1", "deepseek", "deepseek-reasoner", "Reasoning A");
    cacheReasoning("call_stat_2", "kimi", "kimi-k2.5", "Reasoning B from Kimi");

    const stats = getReasoningCacheServiceStats();

    assert.equal(typeof stats.memoryEntries, "number");
    assert.equal(typeof stats.dbEntries, "number");
    assert.equal(typeof stats.totalEntries, "number");
    assert.equal(typeof stats.totalChars, "number");
    assert.equal(typeof stats.hits, "number");
    assert.equal(typeof stats.misses, "number");
    assert.equal(typeof stats.replays, "number");
    assert.equal(typeof stats.replayRate, "string");
    assert.ok(stats.replayRate.endsWith("%"));
    assert.equal(typeof stats.byProvider, "object");
    assert.equal(typeof stats.byModel, "object");
    assert.equal(stats.dbEntries, 2);
    assert.equal(stats.byProvider.deepseek.entries, 1);
    assert.equal(stats.byProvider.kimi.entries, 1);
  });

  it("should list persisted entries for the dashboard API", () => {
    clearReasoningCacheAll();

    cacheReasoning("call_entry_1", "deepseek", "deepseek-reasoner", "Entry reasoning A");
    cacheReasoning("call_entry_2", "kimi", "kimi-k2.5", "Entry reasoning B");

    const deepseekEntries = getReasoningCacheServiceEntries({ provider: "deepseek" }) as Array<{
      toolCallId: string;
      expiresAt: string;
    }>;

    assert.equal(deepseekEntries.length, 1);
    assert.equal(deepseekEntries[0].toolCallId, "call_entry_1");
    assert.doesNotThrow(() => new Date(deepseekEntries[0].expiresAt).toISOString());
  });

  it("should clear all entries", () => {
    cacheReasoning("call_clear_1", "deepseek", "deepseek-chat", "Will be cleared");
    cacheReasoning("call_clear_2", "deepseek", "deepseek-chat", "Also cleared");

    const count = clearReasoningCacheAll();
    assert.ok(count >= 0);

    assert.equal(lookupReasoning("call_clear_1"), null);
    assert.equal(lookupReasoning("call_clear_2"), null);
  });

  it("should delete one entry by tool_call_id", () => {
    clearReasoningCacheAll();

    cacheReasoning("call_delete_1", "deepseek", "deepseek-chat", "Delete me");
    cacheReasoning("call_delete_2", "deepseek", "deepseek-chat", "Keep me");

    assert.equal(deleteReasoningCacheEntry("call_delete_1"), 1);
    assert.equal(lookupReasoning("call_delete_1"), null);
    assert.equal(lookupReasoning("call_delete_2"), "Keep me");
  });

  it("should clear entries by provider only", () => {
    clearReasoningCacheAll();

    cacheReasoning("call_provider_ds", "deepseek", "deepseek-chat", "DeepSeek reasoning");
    cacheReasoning("call_provider_kimi", "kimi", "kimi-k2.5", "Kimi reasoning");

    assert.equal(clearReasoningCacheAll("deepseek"), 1);
    assert.equal(lookupReasoning("call_provider_ds"), null);
    assert.equal(lookupReasoning("call_provider_kimi"), "Kimi reasoning");
  });

  it("should cleanup expired reasoning (no-op when nothing expired)", () => {
    cacheReasoning("call_cleanup_test", "deepseek", "deepseek-chat", "Not expired yet");
    const cleaned = cleanupReasoningCache();
    assert.equal(typeof cleaned, "number");
    // Entry should still be available since TTL is 2 hours
    assert.equal(lookupReasoning("call_cleanup_test"), "Not expired yet");
  });

  it("should not return expired SQLite entries and cleanup should prune them", () => {
    clearReasoningCacheAll();
    setReasoningCache("call_expired", "deepseek", "deepseek-chat", "Expired reasoning", -1_000);

    assert.equal(lookupReasoning("call_expired"), null);
    assert.equal(cleanupReasoningCache(), 1);
    assert.equal(getReasoningCacheServiceStats().dbEntries, 0);
  });

  it("should read and prune legacy ISO expires_at rows", () => {
    clearReasoningCacheAll();

    const db = getDbInstance();
    const futureIso = new Date(Date.now() + 60_000).toISOString();
    const expiredIso = new Date(Date.now() - 60_000).toISOString();
    db.prepare(
      `INSERT INTO reasoning_cache
         (tool_call_id, provider, model, reasoning, char_count, created_at, expires_at)
       VALUES (?, ?, ?, ?, ?, datetime('now'), ?)`
    ).run(
      "call_legacy_iso_active",
      "deepseek",
      "deepseek-chat",
      "Legacy ISO reasoning",
      "Legacy ISO reasoning".length,
      futureIso
    );
    db.prepare(
      `INSERT INTO reasoning_cache
         (tool_call_id, provider, model, reasoning, char_count, created_at, expires_at)
       VALUES (?, ?, ?, ?, ?, datetime('now'), ?)`
    ).run(
      "call_legacy_iso_expired",
      "deepseek",
      "deepseek-chat",
      "Expired legacy ISO reasoning",
      "Expired legacy ISO reasoning".length,
      expiredIso
    );

    assert.equal(lookupReasoning("call_legacy_iso_active"), "Legacy ISO reasoning");
    assert.equal(lookupReasoning("call_legacy_iso_expired"), null);
    const entries = getReasoningCacheServiceEntries({ provider: "deepseek" }) as Array<{
      toolCallId: string;
      expiresAt: string;
    }>;
    assert.equal(
      entries.some((entry) => entry.expiresAt === futureIso),
      true
    );
    assert.equal(cleanupReasoningCache(), 1);
  });
});

describe("Reasoning Replay Cache — Provider Detection", () => {
  it("should detect deepseek as requiring replay", () => {
    assert.equal(requiresReasoningReplay({ provider: "deepseek", model: "deepseek-chat" }), true);
  });

  it("should detect opencode-go as requiring replay", () => {
    assert.equal(requiresReasoningReplay({ provider: "opencode-go", model: "some-model" }), true);
  });

  it("should not replay legacy deepseek-r1 even under replay providers", () => {
    assert.equal(requiresReasoningReplay({ provider: "siliconflow", model: "deepseek-r1" }), false);
  });

  it("should not replay deepseek-r1 model pattern", () => {
    assert.equal(
      requiresReasoningReplay({ provider: "unknown-provider", model: "deepseek-r1" }),
      false
    );
  });

  it("should detect deepseek-reasoner model pattern", () => {
    assert.equal(
      requiresReasoningReplay({ provider: "unknown-provider", model: "deepseek-reasoner" }),
      false
    );
  });

  it("should detect DeepSeek V4 model pattern", () => {
    assert.equal(
      requiresReasoningReplay({ provider: "unknown-provider", model: "deepseek/v4-pro" }),
      true
    );
  });

  it("should detect DeepSeek V4 thinking mode explicitly", () => {
    assert.equal(
      isDeepSeekReasoningModel({
        provider: "unknown-provider",
        model: "deepseek-v4.flash",
        thinkingEnabled: true,
      }),
      true
    );
  });

  it("should NOT detect DeepSeek V4 when thinking mode is disabled", () => {
    assert.equal(
      isDeepSeekReasoningModel({
        provider: "unknown-provider",
        model: "deepseek-v4.flash",
        thinkingEnabled: false,
      }),
      false
    );
  });

  it("should detect kimi-k2 model pattern", () => {
    assert.equal(
      requiresReasoningReplay({ provider: "unknown-provider", model: "kimi-k2.5" }),
      true
    );
  });

  it("should detect qwq model pattern", () => {
    assert.equal(
      requiresReasoningReplay({ provider: "unknown-provider", model: "qwq-32b-preview" }),
      true
    );
  });

  it("should detect qwen-thinking model pattern", () => {
    assert.equal(
      requiresReasoningReplay({ provider: "unknown-provider", model: "qwen3-thinking-235b" }),
      true
    );
  });

  it("should detect GLM thinking model pattern", () => {
    assert.equal(requiresReasoningReplay({ provider: "glm", model: "glm-5-thinking" }), true);
  });

  it("should detect xiaomi-mimo provider", () => {
    // MiMo enforces reasoning_content echo on subsequent turns; without
    // replay the upstream returns 400 "Param Incorrect: The reasoning_content
    // in the thinking mode must be passed back to the API."
    assert.equal(
      requiresReasoningReplay({ provider: "xiaomi-mimo", model: "mimo-v2.5-pro" }),
      true
    );
    assert.equal(requiresReasoningReplay({ provider: "XIAOMI-MIMO", model: "mimo-v2.5" }), true);
  });

  it("should detect mimo-v* model pattern under any provider id", () => {
    assert.equal(
      requiresReasoningReplay({ provider: "unknown-provider", model: "mimo-v2.5-pro" }),
      true
    );
    assert.equal(requiresReasoningReplay({ provider: "unknown-provider", model: "mimo-v3" }), true);
    assert.equal(
      requiresReasoningReplay({ provider: "unknown-provider", model: "MimoV2.5-pro" }),
      true
    );
  });

  it("should NOT detect a generic openai model", () => {
    assert.equal(requiresReasoningReplay({ provider: "openai", model: "gpt-4o" }), false);
  });

  it("should NOT detect claude as requiring replay", () => {
    assert.equal(requiresReasoningReplay({ provider: "anthropic", model: "claude-opus-4" }), false);
  });
});

describe("Reasoning Replay Cache — Translator Replay", () => {
  before(() => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();
  });

  after(() => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();
  });

  function translateWithToolHistory(provider: string, model: string, callId: string) {
    return translateRequest(
      FORMATS.OPENAI,
      FORMATS.OPENAI,
      model,
      {
        messages: [
          { role: "user", content: "use a tool" },
          {
            role: "assistant",
            content: null,
            tool_calls: [
              { id: callId, type: "function", function: { name: "read_file", arguments: "{}" } },
            ],
          },
          { role: "tool", tool_call_id: callId, content: "tool result" },
        ],
      },
      false,
      null,
      provider
    );
  }

  it("should inject cached reasoning for DeepSeek instead of empty fallback", () => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();
    saveModelsDevCapabilities({
      deepseek: {
        "deepseek-reasoner": buildCapability({
          interleaved_field: "reasoning_content",
          reasoning: true,
          tool_call: true,
        }),
      },
    });
    cacheReasoning("call_translate_ds", "deepseek", "deepseek-reasoner", "DeepSeek cached plan");

    const translated = translateWithToolHistory(
      "deepseek",
      "deepseek-reasoner",
      "call_translate_ds"
    );

    assert.equal(translated.messages[1].reasoning_content, "DeepSeek cached plan");
    assert.equal(getReasoningCacheServiceStats().replays, 1);
  });

  it("should preserve client-provided reasoning content", () => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();
    saveModelsDevCapabilities({
      deepseek: {
        "deepseek-reasoner": buildCapability({
          interleaved_field: "reasoning_content",
          reasoning: true,
          tool_call: true,
        }),
      },
    });
    cacheReasoning("call_preserve", "deepseek", "deepseek-reasoner", "Cached reasoning");

    const translated = translateRequest(
      FORMATS.OPENAI,
      FORMATS.OPENAI,
      "deepseek-reasoner",
      {
        messages: [
          { role: "user", content: "use a tool" },
          {
            role: "assistant",
            content: null,
            reasoning_content: "Client reasoning",
            tool_calls: [
              {
                id: "call_preserve",
                type: "function",
                function: { name: "tool", arguments: "{}" },
              },
            ],
          },
        ],
      },
      false,
      null,
      "deepseek"
    );

    assert.equal(translated.messages[1].reasoning_content, "Client reasoning");
    assert.equal(getReasoningCacheServiceStats().replays, 0);
  });

  it("should inject cached reasoning for Qwen and GLM thinking models", () => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();
    saveModelsDevCapabilities({
      qwen: {
        "qwen3-thinking-235b": buildCapability({
          interleaved_field: "reasoning_content",
          reasoning: true,
          tool_call: true,
        }),
      },
      glm: {
        "glm-5-thinking": buildCapability({
          interleaved_field: "reasoning_content",
          reasoning: true,
          tool_call: true,
        }),
      },
    });
    cacheReasoning("call_qwen_think", "qwen", "qwen3-thinking-235b", "Qwen cached plan");
    cacheReasoning("call_glm_think", "glm", "glm-5-thinking", "GLM cached plan");

    const qwen = translateWithToolHistory("qwen", "qwen3-thinking-235b", "call_qwen_think");
    const glm = translateWithToolHistory("glm", "glm-5-thinking", "call_glm_think");

    assert.equal(qwen.messages[1].reasoning_content, "Qwen cached plan");
    assert.equal(glm.messages[1].reasoning_content, "GLM cached plan");
    assert.equal(getReasoningCacheServiceStats().replays, 2);
  });

  it("should not inject reasoning_content for generic non-reasoning providers", () => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();
    cacheReasoning("call_openai", "openai", "gpt-4o", "Should not replay");

    const translated = translateWithToolHistory("openai", "gpt-4o", "call_openai");

    assert.equal(translated.messages[1].reasoning_content, undefined);
    assert.equal(getReasoningCacheServiceStats().replays, 0);
  });

  it("should support the full capture then replay flow", () => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();
    saveModelsDevCapabilities({
      deepseek: {
        "deepseek-reasoner": buildCapability({
          interleaved_field: "reasoning_content",
          reasoning: true,
          tool_call: true,
        }),
      },
    });

    const captured = cacheReasoningFromAssistantMessage(
      {
        role: "assistant",
        reasoning_content: "Full flow cached plan",
        tool_calls: [{ id: "call_full_flow", type: "function" }],
      },
      "deepseek",
      "deepseek-reasoner"
    );

    const translated = translateWithToolHistory("deepseek", "deepseek-reasoner", "call_full_flow");

    assert.equal(captured, 1);
    assert.equal(translated.messages[1].reasoning_content, "Full flow cached plan");
    assert.equal(getReasoningCacheServiceStats().replays, 1);
  });

  it("should strip reasoning_content when model has no interleaved replay signal", () => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();

    const translated = translateRequest(
      FORMATS.OPENAI,
      FORMATS.OPENAI,
      "deepseek-reasoner",
      {
        messages: [
          { role: "user", content: "hello" },
          {
            role: "assistant",
            content: "ok",
            reasoning_content: "should be stripped",
          },
        ],
      },
      false,
      null,
      "deepseek"
    );

    assert.equal(translated.messages[1].reasoning_content, undefined);
  });

  it("should not inject reasoning_content when interleaved field is reasoning_details", () => {
    clearReasoningCacheAll();
    clearModelsDevCapabilities();
    saveModelsDevCapabilities({
      testprovider: {
        "test-reasoning-details": buildCapability({
          interleaved_field: "reasoning_details",
          reasoning: true,
          tool_call: true,
        }),
      },
    });
    cacheReasoning("call_details", "testprovider", "test-reasoning-details", "cached");

    const translated = translateWithToolHistory(
      "testprovider",
      "test-reasoning-details",
      "call_details"
    );

    assert.equal(translated.messages[1].reasoning_content, undefined);
  });
});

describe("Reasoning Replay Cache — API Route", () => {
  let managementApiKey: string;

  before(() => {
    clearReasoningCacheAll();
  });

  before(async () => {
    const created = await createApiKey("reasoning-cache-route-test", "machine-reasoning", [
      "manage",
    ]);
    managementApiKey = created.key;
  });

  after(() => {
    clearReasoningCacheAll();
  });

  function authedRequest(url: string): Request {
    return new Request(url, {
      headers: { authorization: `Bearer ${managementApiKey}` },
    });
  }

  it("should return stats and entries from GET", async () => {
    clearReasoningCacheAll();
    cacheReasoning("call_api_get", "deepseek", "deepseek-reasoner", "API visible reasoning");

    const response = await GET(
      authedRequest("http://localhost/api/cache/reasoning?provider=deepseek") as never
    );
    const body = await response.json();

    assert.equal(response.status, 200);
    assert.equal(body.stats.dbEntries, 1);
    assert.equal(body.entries.length, 1);
    assert.equal(body.entries[0].toolCallId, "call_api_get");
  });

  it("should delete a single entry by toolCallId", async () => {
    clearReasoningCacheAll();
    cacheReasoning("call_api_delete_1", "deepseek", "deepseek-reasoner", "Delete API");
    cacheReasoning("call_api_delete_2", "deepseek", "deepseek-reasoner", "Keep API");

    const response = await DELETE(
      authedRequest("http://localhost/api/cache/reasoning?toolCallId=call_api_delete_1") as never
    );
    const body = await response.json();

    assert.equal(response.status, 200);
    assert.equal(body.scope, "toolCallId");
    assert.equal(body.cleared, 1);
    assert.equal(lookupReasoning("call_api_delete_1"), null);
    assert.equal(lookupReasoning("call_api_delete_2"), "Keep API");
  });

  it("should delete entries by provider", async () => {
    clearReasoningCacheAll();
    cacheReasoning("call_api_provider_ds", "deepseek", "deepseek-reasoner", "Delete provider");
    cacheReasoning("call_api_provider_kimi", "kimi", "kimi-k2.5", "Keep provider");

    const response = await DELETE(
      authedRequest("http://localhost/api/cache/reasoning?provider=deepseek") as never
    );
    const body = await response.json();

    assert.equal(response.status, 200);
    assert.equal(body.scope, "provider");
    assert.equal(body.cleared, 1);
    assert.equal(lookupReasoning("call_api_provider_ds"), null);
    assert.equal(lookupReasoning("call_api_provider_kimi"), "Keep provider");
  });
});
