import { tool } from "@opencode-ai/plugin";
import { MemoryStore } from "../../src/memory/store.js";
import {
  getRuntimeSessionContext,
  setRuntimeSessionContext,
} from "../../src/runtime/sessionContext.js";

const memoryStore = new MemoryStore();
const initializePromise = memoryStore.initialize();

export default tool({
  description:
    "管理长期有效的用户偏好或项目事实。支持 add/list/replace/remove。add 前必须先对同 scope 执行 list 并阅读现有记忆，再决定 add、replace 或 remove；不要跳过读取直接新增。禁止写入 token、password、secret、system prompt 或一次性上下文。scope 仅允许 'user' 或 'workspace'。",
  args: {
    action: tool.schema
      .enum(["add", "list", "replace", "remove"])
      .describe("Memory operation to perform."),
    reason: tool.schema
      .string()
      .describe("Why this memory should be persisted for future requests."),
    scope: tool.schema
      .string()
      .describe(
        "Required exact keyword. Use only 'user' for user-level durable preferences/constraints, or 'workspace' for project/environment durable facts. Do not use 'project', Chinese labels, or any alias.",
      ),
    content: tool.schema
      .string()
      .optional()
      .describe(
        "The durable fact or preference to remember, written as one concise sentence.",
      ),
    target_id: tool.schema
      .string()
      .optional()
      .describe("Stable memory entry id used by replace/remove."),
  },
  async execute(args, context) {
    await initializePromise;
    const sessionContext = getRuntimeSessionContext(context.sessionID);
    if (!sessionContext) {
      throw new Error(`session context not found for ${context.sessionID}`);
    }
    const scope =
      args.scope === "user"
        ? "user"
        : args.scope === "workspace"
          ? "workspace"
          : null;
    if (!scope) {
      return JSON.stringify({
        ok: true,
        kind: "memory",
        decision: "rejected",
        detail: `unsupported scope: ${args.scope}; use exact keyword 'user' or 'workspace'`,
      });
    }
    if (sessionContext.allowLearningWrite === false && args.action !== "list") {
      return JSON.stringify({
        ok: true,
        kind: "memory",
        decision: "rejected",
        detail: "memory writes are disabled for this session",
      });
    }

    const scopeKey =
      scope === "user" ? sessionContext.actorKey : sessionContext.projectKey;
    if (args.action === "list") {
      const readScopes = {
        ...(sessionContext.memoryListReadScopes ?? {}),
        [scope]: true,
      };
      setRuntimeSessionContext({
        ...sessionContext,
        memoryListReadScopes: readScopes,
      });
      return JSON.stringify({
        ok: true,
        kind: "memory",
        decision: "accepted",
        detail: "memory listed",
        items: await memoryStore.list(scope, scopeKey),
        target: scope,
      });
    }

    if (args.action === "add") {
      if (sessionContext.memoryListReadScopes?.[scope] !== true) {
        return JSON.stringify({
          ok: true,
          kind: "memory",
          decision: "rejected",
          detail: `must list ${scope} memory and review existing entries before add`,
          target: scope,
        });
      }
      const result = await memoryStore.upsert(scope, scopeKey, {
        content: args.content ?? "",
        sessionId: sessionContext.clientSessionId,
        source: "tool",
        traceId: sessionContext.traceId,
      });
      if (!result.entry) {
        return JSON.stringify({
          ok: true,
          kind: "memory",
          decision: "rejected",
          detail: "content rejected by persistence policy",
        });
      }
      return JSON.stringify({
        ok: true,
        kind: "memory",
        decision: result.changed ? "accepted" : "deduped",
        detail: result.detail,
        entry: result.entry,
        target: scope,
      });
    }

    if (args.action === "replace") {
      const result = await memoryStore.replace(
        scope,
        scopeKey,
        args.target_id ?? "",
        {
          content: args.content ?? "",
          sessionId: sessionContext.clientSessionId,
          source: "tool",
          traceId: sessionContext.traceId,
        },
      );
      return JSON.stringify({
        ok: true,
        kind: "memory",
        decision: result.changed ? "accepted" : "rejected",
        detail: result.detail,
        target: scope,
      });
    }

    const result = await memoryStore.remove(
      scope,
      scopeKey,
      args.target_id ?? "",
    );
    return JSON.stringify({
      ok: true,
      kind: "memory",
      decision: result.changed ? "accepted" : "rejected",
      detail: result.detail,
      target: scope,
    });
  },
});
