/**
 * Integration tests for Memory CRUD, Relations, Search, and Wiki-Links.
 *
 * Covers the full lifecycle of all memory MCP tools:
 *   harmony_remember → harmony_recall → harmony_update_memory → harmony_forget
 *   harmony_relate → harmony_memory_search → harmony_vault_index → harmony_resolve_links
 *
 * Prerequisites:
 *   1. `supabase db push` (migrations applied)
 *   2. MCP server configured with valid API key
 *   3. Active workspace and project set
 *
 * Run with: bun test packages/mcp-server/src/__tests__/integration-memory-crud.test.ts
 */

import { afterAll, describe, expect, test } from "bun:test";
import { getClient } from "../api-client.js";
import {
  getActiveProjectId,
  getActiveWorkspaceId,
  isConfigured,
  loadConfig,
} from "../config.js";

// Track entities for cleanup
const createdEntityIds: string[] = [];
const createdRelationIds: string[] = [];

// Skip all tests if MCP server isn't configured
const configured = (() => {
  try {
    loadConfig();
    return isConfigured() && !!getActiveWorkspaceId();
  } catch {
    return false;
  }
})();

const describeIf = configured ? describe : describe.skip;

function getWorkspaceId(): string {
  return getActiveWorkspaceId()!;
}
function getProjectId(): string | undefined {
  return getActiveProjectId() || undefined;
}
function getScope(): "project" | "workspace" {
  return getProjectId() ? "project" : "workspace";
}

// Cleanup (generous timeout for many API calls)
afterAll(async () => {
  if (!configured) return;
  const client = getClient();

  for (const id of createdRelationIds) {
    try {
      await client.deleteMemoryRelation(id);
    } catch {}
  }
  for (const id of createdEntityIds) {
    try {
      await client.deleteMemoryEntity(id);
    } catch {}
  }
}, 30000);

// ============================================================
// 1. Entity CRUD Round-Trip
// ============================================================

describeIf("Entity CRUD Round-Trip", () => {
  let entityId: string;

  test("CREATE: harmony_remember creates entity with all fields", async () => {
    const client = getClient();

    const result = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "pattern",
      scope: getScope(),
      memory_tier: "reference",
      title: "[TEST-CRUD] Unique pattern alpha-bravo-42",
      content: "This is a test pattern for CRUD round-trip testing.",
      confidence: 0.85,
      tags: ["test", "crud", "integration"],
      metadata: { source: "test-suite", version: 1 },
      agent_identifier: "test-runner",
    });

    const entity = result.entity as Record<string, unknown>;
    expect(entity.id).toBeTruthy();
    expect(entity.title).toBe("[TEST-CRUD] Unique pattern alpha-bravo-42");
    expect(entity.type).toBe("pattern");
    expect(entity.scope).toBe(getScope());
    expect(entity.memory_tier).toBe("reference");
    expect(entity.confidence).toBe(0.85);
    expect(entity.tags).toEqual(["test", "crud", "integration"]);
    expect((entity.metadata as Record<string, unknown>).source).toBe(
      "test-suite",
    );
    expect(entity.agent_identifier).toBe("test-runner");

    entityId = entity.id as string;
    createdEntityIds.push(entityId);
  });

  test("READ: getMemoryEntity returns the created entity", async () => {
    const client = getClient();
    const result = await client.getMemoryEntity(entityId);
    const entity = result.entity as Record<string, unknown>;

    expect(entity.id).toBe(entityId);
    expect(entity.title).toBe("[TEST-CRUD] Unique pattern alpha-bravo-42");
    expect(entity.content).toContain("CRUD round-trip");
  });

  test("READ: listMemoryEntities with type filter finds entity", async () => {
    const client = getClient();
    const result = await client.listMemoryEntities({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "pattern",
      agent_identifier: "test-runner",
      limit: 50,
    });

    const found = result.entities.find(
      (e: unknown) => (e as Record<string, unknown>).id === entityId,
    );
    expect(found).toBeTruthy();
  });

  test("READ: listMemoryEntities with tag filter finds entity", async () => {
    const client = getClient();
    const result = await client.listMemoryEntities({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      tags: ["crud"],
      agent_identifier: "test-runner",
      limit: 50,
    });

    const found = result.entities.find(
      (e: unknown) => (e as Record<string, unknown>).id === entityId,
    );
    expect(found).toBeTruthy();
  });

  test("READ: listMemoryEntities with min_confidence filters correctly", async () => {
    const client = getClient();

    // Should find it (0.85 >= 0.8)
    const resultHigh = await client.listMemoryEntities({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      min_confidence: 0.8,
      agent_identifier: "test-runner",
      limit: 50,
    });
    const foundHigh = resultHigh.entities.find(
      (e: unknown) => (e as Record<string, unknown>).id === entityId,
    );
    expect(foundHigh).toBeTruthy();

    // Should NOT find it (0.85 < 0.9)
    const resultVeryHigh = await client.listMemoryEntities({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      min_confidence: 0.9,
      agent_identifier: "test-runner",
      limit: 50,
    });
    const foundVeryHigh = resultVeryHigh.entities.find(
      (e: unknown) => (e as Record<string, unknown>).id === entityId,
    );
    expect(foundVeryHigh).toBeFalsy();
  });

  test("UPDATE: harmony_update_memory modifies entity", async () => {
    const client = getClient();

    const result = await client.updateMemoryEntity(entityId, {
      title: "[TEST-CRUD] Updated pattern alpha-bravo-42",
      confidence: 0.95,
      tags: ["test", "crud", "updated"],
      metadata: { source: "test-suite", version: 2, updated: true },
    });

    const entity = result.entity as Record<string, unknown>;
    expect(entity.title).toBe("[TEST-CRUD] Updated pattern alpha-bravo-42");
    expect(entity.confidence).toBe(0.95);
    expect(entity.tags).toEqual(["test", "crud", "updated"]);
    expect((entity.metadata as Record<string, unknown>).version).toBe(2);
    expect((entity.metadata as Record<string, unknown>).updated).toBe(true);
  });

  test("UPDATE: updated_at is newer after update", async () => {
    const client = getClient();
    const result = await client.getMemoryEntity(entityId);
    const entity = result.entity as Record<string, unknown>;

    const updatedAt = new Date(entity.updated_at as string).getTime();
    const createdAt = new Date(entity.created_at as string).getTime();
    expect(updatedAt).toBeGreaterThanOrEqual(createdAt);
  });

  test("DELETE: harmony_forget removes entity", async () => {
    const client = getClient();
    const result = await client.deleteMemoryEntity(entityId);
    expect(result.success).toBe(true);

    // Remove from cleanup list since it's already deleted
    const idx = createdEntityIds.indexOf(entityId);
    if (idx >= 0) createdEntityIds.splice(idx, 1);

    // Verify it's gone
    try {
      await client.getMemoryEntity(entityId);
      // If we get here, entity still exists - fail
      expect(true).toBe(false);
    } catch (e) {
      // Expected: 404 or similar
      expect(e).toBeTruthy();
    }
  });
});

// ============================================================
// 2. All Entity Types
// ============================================================

describeIf("All 13 Entity Types", () => {
  const allTypes = [
    "agent",
    "task",
    "decision",
    "context",
    "pattern",
    "error",
    "solution",
    "preference",
    "relationship",
    "commitment",
    "lesson",
    "project",
    "handoff",
  ] as const;

  for (const type of allTypes) {
    test(`create entity with type="${type}"`, async () => {
      const client = getClient();
      const result = await client.createMemoryEntity({
        workspace_id: getWorkspaceId(),
        project_id: getProjectId(),
        type,
        scope: getScope(),
        title: `[TEST-TYPE] ${type} entity`,
        content: `Testing entity type: ${type}`,
        agent_identifier: "test-runner",
      });

      const entity = result.entity as Record<string, unknown>;
      expect(entity.id).toBeTruthy();
      expect(entity.type).toBe(type);
      createdEntityIds.push(entity.id as string);
    });
  }
});

// ============================================================
// 3. Scope Validation
// ============================================================

describeIf("Scope Validation", () => {
  test("project scope requires project_id", async () => {
    const client = getClient();
    const projectId = getProjectId();

    if (projectId) {
      // With project_id, project scope works
      const result = await client.createMemoryEntity({
        workspace_id: getWorkspaceId(),
        project_id: projectId,
        type: "context",
        scope: "project",
        title: "[TEST-SCOPE] Project scoped entity",
        content: "Testing project scope.",
        agent_identifier: "test-runner",
      });
      const entity = result.entity as Record<string, unknown>;
      expect(entity.scope).toBe("project");
      createdEntityIds.push(entity.id as string);
    }
  });

  test("workspace scope works without project_id", async () => {
    const client = getClient();
    const result = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      type: "context",
      scope: "workspace",
      title: "[TEST-SCOPE] Workspace scoped entity",
      content: "Testing workspace scope.",
      agent_identifier: "test-runner",
    });

    const entity = result.entity as Record<string, unknown>;
    expect(entity.scope).toBe("workspace");
    createdEntityIds.push(entity.id as string);
  });

  for (const scope of ["private", "global"] as const) {
    test(`${scope} scope creates successfully`, async () => {
      const client = getClient();
      const result = await client.createMemoryEntity({
        workspace_id: getWorkspaceId(),
        project_id: getProjectId(),
        type: "context",
        scope,
        title: `[TEST-SCOPE] ${scope} scoped entity`,
        content: `Testing ${scope} scope.`,
        agent_identifier: "test-runner",
      });

      const entity = result.entity as Record<string, unknown>;
      expect(entity.scope).toBe(scope);
      createdEntityIds.push(entity.id as string);
    });
  }
});

// ============================================================
// 4. Relations CRUD
// ============================================================

describeIf("Relation CRUD", () => {
  let sourceId: string;
  let targetId: string;
  let relationId: string;

  test("setup: create two entities", async () => {
    const client = getClient();

    const source = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "error",
      scope: getScope(),
      title: "[TEST-REL] Source error entity",
      content: "An error for relation testing.",
      agent_identifier: "test-runner",
    });
    sourceId = (source.entity as Record<string, unknown>).id as string;
    createdEntityIds.push(sourceId);

    const target = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "solution",
      scope: getScope(),
      title: "[TEST-REL] Target solution entity",
      content: "A solution for relation testing.",
      agent_identifier: "test-runner",
    });
    targetId = (target.entity as Record<string, unknown>).id as string;
    createdEntityIds.push(targetId);
  });

  test("CREATE: harmony_relate creates relation", async () => {
    const client = getClient();
    const result = await client.createMemoryRelation({
      source_id: sourceId,
      target_id: targetId,
      relation_type: "resolved_by",
      confidence: 0.9,
    });

    const rel = result.relation as Record<string, unknown>;
    expect(rel.id).toBeTruthy();
    expect(rel.relation_type).toBe("resolved_by");
    relationId = rel.id as string;
    createdRelationIds.push(relationId);
  });

  test("READ: getRelatedEntities shows the relation", async () => {
    const client = getClient();
    const result = await client.getRelatedEntities(sourceId);

    expect(result.outgoing.length).toBeGreaterThan(0);
    const found = result.outgoing.find((r: unknown) => {
      const rel = r as Record<string, unknown>;
      const target = rel.target as Record<string, unknown> | undefined;
      return target?.id === targetId || rel.target_id === targetId;
    });
    expect(found).toBeTruthy();
  });

  test("READ: target entity shows incoming relation", async () => {
    const client = getClient();
    const result = await client.getRelatedEntities(targetId);

    expect(result.incoming.length).toBeGreaterThan(0);
    const found = result.incoming.find((r: unknown) => {
      const rel = r as Record<string, unknown>;
      const source = rel.source as Record<string, unknown> | undefined;
      return source?.id === sourceId || rel.source_id === sourceId;
    });
    expect(found).toBeTruthy();
  });

  test("all 8 relation types are valid", async () => {
    const client = getClient();

    // Create a second target for the other relation types
    const target2 = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "pattern",
      scope: getScope(),
      title: "[TEST-REL] Extra target for relation types",
      content: "Testing all relation types.",
      agent_identifier: "test-runner",
    });
    const target2Id = (target2.entity as Record<string, unknown>).id as string;
    createdEntityIds.push(target2Id);

    const types = [
      "learned_from",
      "contradicts",
      "supports",
      "depends_on",
      "part_of",
      "caused_by",
      "relates_to",
    ] as const;

    // Run in parallel (semaphore limits to 3 concurrent)
    const _results = await Promise.all(
      types.map((relType) =>
        client
          .createMemoryRelation({
            source_id: sourceId,
            target_id: target2Id,
            relation_type: relType,
          })
          .then((result) => {
            const rel = result.relation as Record<string, unknown>;
            expect(rel.id).toBeTruthy();
            expect(rel.relation_type).toBe(relType);
            createdRelationIds.push(rel.id as string);
          }),
      ),
    );
  }, 15000);

  test("duplicate relation type between same entities is rejected", async () => {
    const client = getClient();

    let threw = false;
    try {
      // Already created resolved_by between sourceId → targetId
      // Use a short timeout since retries would be wasteful here
      await Promise.race([
        client.createMemoryRelation({
          source_id: sourceId,
          target_id: targetId,
          relation_type: "resolved_by",
        }),
        new Promise((_, reject) =>
          setTimeout(() => reject(new Error("timeout")), 3000),
        ),
      ]);
    } catch (_e) {
      threw = true;
    }
    // Either the API rejected it or we timed out (retry on 409) - both acceptable
    expect(threw).toBe(true);
  });

  test("DELETE: deleteMemoryRelation removes relation", async () => {
    const client = getClient();
    const result = await client.deleteMemoryRelation(relationId);
    expect(result.success).toBe(true);

    // Remove from cleanup
    const idx = createdRelationIds.indexOf(relationId);
    if (idx >= 0) createdRelationIds.splice(idx, 1);

    // Verify it's gone from outgoing
    const related = await client.getRelatedEntities(sourceId);
    const found = related.outgoing.find((r: unknown) => {
      const rel = r as Record<string, unknown>;
      return rel.id === relationId;
    });
    expect(found).toBeFalsy();
  });
});

// ============================================================
// 5. Search (Full-Text)
// ============================================================

describeIf("Full-Text Search", () => {
  let searchEntityId: string;

  test("setup: create searchable entity with unique term", async () => {
    const client = getClient();
    const result = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "solution",
      scope: getScope(),
      memory_tier: "reference",
      title: "[TEST-SEARCH] Zebra quuxplonk algorithm",
      content:
        "A unique solution describing the zebra quuxplonk algorithm for distributed systems.",
      confidence: 0.9,
      tags: ["test", "search", "algorithm"],
      agent_identifier: "test-runner",
    });
    searchEntityId = (result.entity as Record<string, unknown>).id as string;
    createdEntityIds.push(searchEntityId);
  });

  test("harmony_memory_search finds entity by unique term", async () => {
    const client = getClient();
    const result = await client.searchMemoryEntities(
      getWorkspaceId(),
      "quuxplonk",
      { project_id: getProjectId(), limit: 10 },
    );

    expect(result.entities.length).toBeGreaterThan(0);
    const found = result.entities.find(
      (e: unknown) => (e as Record<string, unknown>).id === searchEntityId,
    );
    expect(found).toBeTruthy();
  });

  test("search with type filter narrows results", async () => {
    const client = getClient();

    // Should find it (type=solution)
    const resultSolution = await client.searchMemoryEntities(
      getWorkspaceId(),
      "quuxplonk",
      { project_id: getProjectId(), type: "solution", limit: 10 },
    );
    const found = resultSolution.entities.find(
      (e: unknown) => (e as Record<string, unknown>).id === searchEntityId,
    );
    expect(found).toBeTruthy();

    // Should NOT find it (type=error)
    const resultError = await client.searchMemoryEntities(
      getWorkspaceId(),
      "quuxplonk",
      { project_id: getProjectId(), type: "error", limit: 10 },
    );
    const notFound = resultError.entities.find(
      (e: unknown) => (e as Record<string, unknown>).id === searchEntityId,
    );
    expect(notFound).toBeFalsy();
  });

  test("search with no results returns empty array", async () => {
    const client = getClient();
    const result = await client.searchMemoryEntities(
      getWorkspaceId(),
      "xyznonexistenttermthatnobodywouldevercreate999",
      { project_id: getProjectId(), limit: 10 },
    );

    expect(result.entities).toHaveLength(0);
  });

  test("markdown search returns text content", async () => {
    const client = getClient();
    const markdown = await client.searchMemoryEntitiesMarkdown(
      getWorkspaceId(),
      "quuxplonk",
      { project_id: getProjectId(), limit: 10 },
    );

    expect(typeof markdown).toBe("string");
    expect(markdown.length).toBeGreaterThan(0);
    expect(markdown).toContain("quuxplonk");
  });
});

// ============================================================
// 6. Vault Index
// ============================================================

describeIf("Vault Index", () => {
  test("vault index returns entities", async () => {
    const client = getClient();

    let result: { entities: unknown[]; count: number };
    try {
      result = await client.getVaultIndex({
        workspace_id: getWorkspaceId(),
        project_id: getProjectId(),
        limit: 10,
      });
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      if (msg.includes("Unknown endpoint")) {
        console.log("Skipping: vault index endpoint not deployed");
        return;
      }
      throw e;
    }

    expect(result.entities).toBeDefined();
    expect(Array.isArray(result.entities)).toBe(true);
  });

  test("vault index with type filter returns only matching type", async () => {
    const client = getClient();

    // First create a known entity
    const createResult = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "preference",
      scope: getScope(),
      title: "[TEST-INDEX] Preference for vault index test",
      content: "Testing vault index filtering.",
      agent_identifier: "test-runner",
    });
    createdEntityIds.push(
      (createResult.entity as Record<string, unknown>).id as string,
    );

    let result: { entities: unknown[]; count: number };
    try {
      result = await client.getVaultIndex({
        workspace_id: getWorkspaceId(),
        project_id: getProjectId(),
        type: "preference",
        limit: 50,
      });
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      if (msg.includes("Unknown endpoint")) return;
      throw e;
    }

    // All returned entities should be of type 'preference'
    for (const entity of result.entities) {
      expect((entity as Record<string, unknown>).type).toBe("preference");
    }
  });

  test("vault index markdown returns table format", async () => {
    const client = getClient();

    try {
      const markdown = await client.getVaultIndexMarkdown({
        workspace_id: getWorkspaceId(),
        project_id: getProjectId(),
        limit: 10,
      });

      expect(typeof markdown).toBe("string");
      // Markdown table should contain pipe separators
      if (markdown.length > 0) {
        expect(markdown).toContain("|");
      }
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      if (msg.includes("Unknown endpoint")) return;
      throw e;
    }
  });
});

// ============================================================
// 7. Wiki-Link Resolution
// ============================================================

describeIf("Wiki-Link Resolution", () => {
  test("resolveLinks processes entities with [[wiki-links]]", async () => {
    const client = getClient();

    // Create an entity with a wiki-link in its content
    const targetResult = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "pattern",
      scope: getScope(),
      title: "[TEST-WIKI] Target pattern for linking",
      content: "This is the target entity.",
      agent_identifier: "test-runner",
    });
    const targetId = (targetResult.entity as Record<string, unknown>)
      .id as string;
    createdEntityIds.push(targetId);

    const sourceResult = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "lesson",
      scope: getScope(),
      title: "[TEST-WIKI] Source with wiki-link",
      content:
        "Learned from [[[TEST-WIKI] Target pattern for linking]] that patterns are useful.",
      agent_identifier: "test-runner",
    });
    const sourceId = (sourceResult.entity as Record<string, unknown>)
      .id as string;
    createdEntityIds.push(sourceId);

    // Resolve links
    try {
      const result = await client.resolveLinks({
        workspace_id: getWorkspaceId(),
        project_id: getProjectId(),
      });

      expect(result).toBeTruthy();
      // The result should report resolved/unresolved counts
      expect(typeof result.resolved).toBe("number");
      expect(typeof result.unresolved).toBe("number");
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      if (msg.includes("Unknown endpoint")) {
        console.log("Skipping: resolve-links endpoint not deployed");
        return;
      }
      throw e;
    }
  });
});

// ============================================================
// 8. Touch (Access Tracking)
// ============================================================

describeIf("Access Tracking", () => {
  test("touchMemoryEntity increments access count", async () => {
    const client = getClient();

    // Create entity
    const result = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "context",
      scope: getScope(),
      title: "[TEST-TOUCH] Access tracking test",
      content: "Testing access count increment.",
      agent_identifier: "test-runner",
    });
    const entityId = (result.entity as Record<string, unknown>).id as string;
    createdEntityIds.push(entityId);

    // Touch it (endpoint may not be deployed)
    try {
      const touchResult = await client.touchMemoryEntity(entityId);
      expect(touchResult.success).toBe(true);

      // Verify access_count increased
      const readResult = await client.getMemoryEntity(entityId);
      const entity = readResult.entity as Record<string, unknown>;
      expect(entity.access_count).toBeGreaterThanOrEqual(1);
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      if (msg.includes("Unknown endpoint")) {
        console.log("Skipping: touch endpoint not deployed");
        return;
      }
      throw e;
    }
  });
});

// ============================================================
// 9. Edge Cases
// ============================================================

describeIf("Edge Cases", () => {
  test("entity with minimal fields (just required)", async () => {
    const client = getClient();
    const result = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      type: "context",
      scope: "workspace",
      title: "[TEST-EDGE] Minimal entity",
      content: "Minimal.",
      agent_identifier: "test-runner",
    });

    const entity = result.entity as Record<string, unknown>;
    expect(entity.id).toBeTruthy();
    expect(entity.confidence).toBe(1.0); // Default
    expect(entity.tags).toEqual([]); // Default
    createdEntityIds.push(entity.id as string);
  });

  test("entity with empty tags array", async () => {
    const client = getClient();
    const result = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      type: "context",
      scope: "workspace",
      title: "[TEST-EDGE] Empty tags",
      content: "No tags.",
      tags: [],
      agent_identifier: "test-runner",
    });

    const entity = result.entity as Record<string, unknown>;
    expect(entity.tags).toEqual([]);
    createdEntityIds.push(entity.id as string);
  });

  test("entity with confidence at boundaries (0.0 and 1.0)", async () => {
    const client = getClient();

    const low = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      type: "context",
      scope: "workspace",
      title: "[TEST-EDGE] Zero confidence",
      content: "Low confidence.",
      confidence: 0.0,
      agent_identifier: "test-runner",
    });
    expect((low.entity as Record<string, unknown>).confidence).toBe(0);
    createdEntityIds.push((low.entity as Record<string, unknown>).id as string);

    const high = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      type: "context",
      scope: "workspace",
      title: "[TEST-EDGE] Max confidence",
      content: "High confidence.",
      confidence: 1.0,
      agent_identifier: "test-runner",
    });
    expect((high.entity as Record<string, unknown>).confidence).toBe(1.0);
    createdEntityIds.push(
      (high.entity as Record<string, unknown>).id as string,
    );
  });

  test("deleting entity cascades relations", async () => {
    const client = getClient();

    // Create two entities with a relation
    const a = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "error",
      scope: getScope(),
      title: "[TEST-CASCADE] Entity A",
      content: "Will be deleted.",
      agent_identifier: "test-runner",
    });
    const aId = (a.entity as Record<string, unknown>).id as string;

    const b = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "solution",
      scope: getScope(),
      title: "[TEST-CASCADE] Entity B",
      content: "Target of relation.",
      agent_identifier: "test-runner",
    });
    const bId = (b.entity as Record<string, unknown>).id as string;
    createdEntityIds.push(bId);

    const _rel = await client.createMemoryRelation({
      source_id: aId,
      target_id: bId,
      relation_type: "resolved_by",
    });

    // Delete entity A - relation should cascade
    await client.deleteMemoryEntity(aId);

    // Verify entity B has no incoming relations from A
    const related = await client.getRelatedEntities(bId);
    const found = related.incoming.find((r: unknown) => {
      const item = r as Record<string, unknown>;
      const source = item.source as Record<string, unknown> | undefined;
      return source?.id === aId || item.source_id === aId;
    });
    expect(found).toBeFalsy();
  });

  test("update non-existent entity returns error", async () => {
    const client = getClient();
    const fakeId = "00000000-0000-0000-0000-000000000000";

    try {
      await client.updateMemoryEntity(fakeId, { title: "Should fail" });
      expect(true).toBe(false);
    } catch (e) {
      expect(e).toBeTruthy();
    }
  });

  test("delete non-existent entity returns error", async () => {
    const client = getClient();
    const fakeId = "00000000-0000-0000-0000-000000000000";

    try {
      await client.deleteMemoryEntity(fakeId);
      expect(true).toBe(false);
    } catch (e) {
      expect(e).toBeTruthy();
    }
  });

  test("relation with non-existent source entity fails", async () => {
    const client = getClient();
    const fakeId = "00000000-0000-0000-0000-000000000000";

    // Create a valid target
    const target = await client.createMemoryEntity({
      workspace_id: getWorkspaceId(),
      project_id: getProjectId(),
      type: "context",
      scope: getScope(),
      title: "[TEST-EDGE] Valid target for bad relation",
      content: "Target.",
      agent_identifier: "test-runner",
    });
    const targetId = (target.entity as Record<string, unknown>).id as string;
    createdEntityIds.push(targetId);

    try {
      await client.createMemoryRelation({
        source_id: fakeId,
        target_id: targetId,
        relation_type: "relates_to",
      });
      expect(true).toBe(false);
    } catch (e) {
      expect(e).toBeTruthy();
    }
  });
});
