/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const { MemoryStore } = ChromeUtils.importESModule(
  "moz-src:///browser/components/aiwindow/services/MemoryStore.sys.mjs"
);

add_task(async function test_init_empty_state() {
  // First init should succeed and not throw.
  await MemoryStore.ensureInitialized();

  let memories = await MemoryStore.getMemories();
  equal(memories.length, 0, "New store should start with no memories");

  const meta = await MemoryStore.getMeta();
  equal(
    meta.last_history_memory_ts,
    0,
    "Default last_history_memory_ts should be 0"
  );
  equal(meta.last_chat_memory_ts, 0, "Default last_chat_memory_ts should be 0");
});

add_task(async function test_addMemory() {
  await MemoryStore.ensureInitialized();

  const memory1 = await MemoryStore.addMemory({
    memory_summary: "i love driking coffee",
    category: "Food & Drink",
    intent: "Plan / Organize",
    score: 3,
  });

  equal(
    memory1.memory_summary,
    "i love driking coffee",
    "memory summary should match input"
  );
  equal(memory1.category, "Food & Drink", "Category should match input");
  equal(memory1.intent, "Plan / Organize", "Intent should match with input");
  equal(memory1.score, 3, "Score should match input");
  await MemoryStore.hardDeleteMemory(memory1.id);
});

add_task(async function test_addMemory_and_upsert_by_content() {
  await MemoryStore.ensureInitialized();

  const memory1 = await MemoryStore.addMemory({
    memory_summary: "trip plans to Italy",
    category: "Travel & Transportation",
    intent: "Plan / Organize",
    score: 3,
  });

  ok(memory1.id, "Memory should have an id");
  equal(
    memory1.memory_summary,
    "trip plans to Italy",
    "Memory summary should be stored"
  );

  // Add another memory with same (summary, category, intent) – should upsert, not duplicate.
  const memory2 = await MemoryStore.addMemory({
    memory_summary: "trip plans to Italy",
    category: "Travel & Transportation",
    intent: "Plan / Organize",
    score: 5,
  });

  equal(
    memory1.id,
    memory2.id,
    "Same (summary, category, intent) should produce same deterministic id"
  );
  equal(
    memory2.score,
    5,
    "Second addMemory call for same id should update score"
  );

  const memories = await MemoryStore.getMemories();
  equal(memories.length, 1, "Store should still have only one memory");
  await MemoryStore.hardDeleteMemory(memory1.id);
});

add_task(async function test_addMemory_different_intent_produces_new_id() {
  await MemoryStore.ensureInitialized();

  const a = await MemoryStore.addMemory({
    memory_summary: "trip plans to Italy",
    category: "Travel & Transportation",
    intent: "trip_planning",
    score: 3,
  });

  const b = await MemoryStore.addMemory({
    memory_summary: "trip plans to Italy",
    category: "Travel & Transportation",
    intent: "travel_budgeting",
    score: 4,
  });

  notEqual(a.id, b.id, "Different intent should yield different ids");

  const memories = await MemoryStore.getMemories();
  equal(
    memories.length == 2,
    true,
    "Store should contain at least two memories now"
  );
});

add_task(async function test_updateMemory_and_soft_delete() {
  await MemoryStore.ensureInitialized();

  const memory = await MemoryStore.addMemory({
    memory_summary: "debug memory",
    category: "debug",
    intent: "Monitor / Track",
    score: 1,
  });

  const updated = await MemoryStore.updateMemory(memory.id, {
    score: 4,
  });
  equal(updated.score, 4, "updateMemory should update fields");

  const deleted = await MemoryStore.softDeleteMemory(memory.id);

  ok(deleted, "softDeleteMemory should return the updated memory");
  equal(
    deleted.is_deleted,
    true,
    "Soft-deleted memory should have is_deleted = true"
  );

  const nonDeleted = await MemoryStore.getMemories();
  const notFound = nonDeleted.find(i => i.id === memory.id);
  equal(
    notFound,
    undefined,
    "Soft-deleted memory should be filtered out by getMemories()"
  );
});

add_task(async function test_hard_delete() {
  await MemoryStore.ensureInitialized();

  const memory = await MemoryStore.addMemory({
    memory_summary: "to be hard deleted",
    category: "debug",
    intent: "Monitor / Track",
    score: 2,
  });

  let memories = await MemoryStore.getMemories();
  const beforeCount = memories.length;

  const removed = await MemoryStore.hardDeleteMemory(memory.id);
  equal(
    removed,
    true,
    "hardDeleteMemory should return true when removing existing memory"
  );

  memories = await MemoryStore.getMemories();
  const afterCount = memories.length;

  equal(
    beforeCount - 1,
    afterCount,
    "hardDeleteMemory should physically remove entry from array"
  );
});

add_task(async function test_updateMeta_and_persistence_roundtrip() {
  await MemoryStore.ensureInitialized();

  const now = Date.now();

  await MemoryStore.updateMeta({
    last_history_memory_ts: now,
  });

  let meta = await MemoryStore.getMeta();
  equal(
    meta.last_history_memory_ts,
    now,
    "updateMeta should update last_history_memory_ts"
  );
  equal(
    meta.last_chat_memory_ts,
    0,
    "updateMeta should not touch last_chat_memory_ts when not provided"
  );

  const chatTime = now + 1000;
  await MemoryStore.updateMeta({
    last_chat_memory_ts: chatTime,
  });

  meta = await MemoryStore.getMeta();
  equal(
    meta.last_history_memory_ts,
    now,
    "last_history_memory_ts should remain unchanged when only chat ts updated"
  );
  equal(
    meta.last_chat_memory_ts,
    chatTime,
    "last_chat_memory_ts should be updated"
  );

  // Force a write to disk.
  await MemoryStore.testOnlyFlush();

  // Simulate a fresh import by reloading module.
  // This uses the xpcshell helper to bypass module caching.
  const { MemoryStore: FreshStore } = ChromeUtils.importESModule(
    "moz-src:///browser/components/aiwindow/services/MemoryStore.sys.mjs",
    { ignoreCache: true }
  );

  await FreshStore.ensureInitialized();

  const meta2 = await FreshStore.getMeta();
  equal(
    meta2.last_history_memory_ts,
    now,
    "last_history_memory_ts should survive roundtrip to disk"
  );
  equal(
    meta2.last_chat_memory_ts,
    chatTime,
    "last_chat_memory_ts should survive roundtrip to disk"
  );

  const memories = await FreshStore.getMemories();
  ok(Array.isArray(memories), "Memories should be an array after reload");
});
