// Cache backend — semantic cache for LLM responses
import type { EffectBackend } from "../../../../src/core/effects/backend";
import type { State } from "../../../../src/core/eval/machine";
import type { OpCall } from "../../../../src/core/effects/opcall";
import type { Val } from "../../../../src/core/eval/values";

export class CacheBackend implements EffectBackend {
  readonly ops = [
    "cache.get.op", "cache.set.op", "cache.has.op",
    "cache.stats.op", "cache.clear.op",
  ] as const;

  async handle(_state: State, opcall: OpCall): Promise<State> {
    if (opcall.op === "cache.get.op") {
      const promptArg = opcall.args[0];
      const prompt = promptArg?.tag === "Str" ? promptArg.s : "";

      const { semanticCache } = await import("./semanticCache");
      const entry = semanticCache.get(prompt);

      if (entry) {
        return opcall.resumption.invoke({ tag: "Str", s: entry.response } as Val) as State;
      } else {
        return opcall.resumption.invoke({ tag: "Bool", b: false } as Val) as State;
      }
    }

    if (opcall.op === "cache.set.op") {
      const promptArg = opcall.args[0];
      const responseArg = opcall.args[1];
      const modelArg = opcall.args[2];

      const prompt = promptArg?.tag === "Str" ? promptArg.s : "";
      const response = responseArg?.tag === "Str" ? responseArg.s : "";
      const model = modelArg?.tag === "Str" ? modelArg.s : "unknown";

      const { semanticCache } = await import("./semanticCache");
      semanticCache.set(prompt, response, model);

      return opcall.resumption.invoke({ tag: "Unit" } as Val) as State;
    }

    if (opcall.op === "cache.has.op") {
      const promptArg = opcall.args[0];
      const prompt = promptArg?.tag === "Str" ? promptArg.s : "";

      const { semanticCache } = await import("./semanticCache");
      const has = semanticCache.has(prompt);

      return opcall.resumption.invoke({ tag: "Bool", b: has } as Val) as State;
    }

    if (opcall.op === "cache.stats.op") {
      const { semanticCache } = await import("./semanticCache");
      const stats = semanticCache.stats();

      const result: Val = {
        tag: "Map",
        entries: [
          [{ tag: "Str", s: "hits" }, { tag: "Num", n: stats.hits }],
          [{ tag: "Str", s: "misses" }, { tag: "Num", n: stats.misses }],
          [{ tag: "Str", s: "entries" }, { tag: "Num", n: stats.entries }],
          [{ tag: "Str", s: "savedCalls" }, { tag: "Num", n: stats.savedCalls }],
          [{ tag: "Str", s: "hitRate" }, { tag: "Num", n: stats.hitRate }],
        ]
      } as Val;

      return opcall.resumption.invoke(result) as State;
    }

    if (opcall.op === "cache.clear.op") {
      const { semanticCache } = await import("./semanticCache");
      semanticCache.clear();

      return opcall.resumption.invoke({ tag: "Unit" } as Val) as State;
    }

    throw new Error(`CacheBackend: unhandled op ${opcall.op}`);
  }
}
