import test from "node:test";
import { skipUnlessBetterSqlite3 } from "./helpers/native-binding.mjs";
import assert from "node:assert/strict";
import os from "node:os";
import path from "node:path";
import { mkdtemp, mkdir, stat, writeFile } from "node:fs/promises";
import {
  runArchiveObservationsCliCommand,
  runMemoryTimelineCliCommand,
  runRebuildMemoryLifecycleLedgerCliCommand,
  runRebuildMemoryProjectionCliCommand,
  runRepairMemoryProjectionCliCommand,
  runMigrateObservationsCliCommand,
  runRebuildObservationsCliCommand,
  runVerifyMemoryProjectionCliCommand,
} from "../src/cli.js";

async function writeText(baseDir: string, relPath: string, content: string): Promise<void> {
  const full = path.join(baseDir, relPath);
  await mkdir(path.dirname(full), { recursive: true });
  await writeFile(full, content, "utf-8");
}

test("archive-observations CLI wrapper defaults to dry-run", async () => {
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-cli-archive-observations-"));
  await writeText(
    memoryDir,
    "transcripts/main/default/2026-01-01.jsonl",
    "{\"timestamp\":\"2026-01-01T00:00:00.000Z\"}\n",
  );

  const result = await runArchiveObservationsCliCommand({
    memoryDir,
    retentionDays: 30,
    now: new Date("2026-02-26T12:00:00.000Z"),
  });
  assert.equal(result.dryRun, true);
  assert.equal(result.scannedFiles, 1);
});

test("rebuild-observations CLI wrapper writes only with --write semantics", async () => {
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-cli-rebuild-observations-"));
  await writeText(
    memoryDir,
    "transcripts/main/default/2026-02-25.jsonl",
    JSON.stringify({
      timestamp: "2026-02-25T10:05:00.000Z",
      role: "user",
      content: "u1",
      sessionKey: "agent:main:default",
    }) + "\n",
  );

  const dryRunResult = await runRebuildObservationsCliCommand({ memoryDir });
  assert.equal(dryRunResult.dryRun, true);
  await assert.rejects(() => stat(dryRunResult.outputPath));

  const writeResult = await runRebuildObservationsCliCommand({
    memoryDir,
    write: true,
    now: new Date("2026-02-26T12:00:00.000Z"),
  });
  assert.equal(writeResult.dryRun, false);
  await stat(writeResult.outputPath);
});

test("rebuild-memory-lifecycle-ledger CLI wrapper respects dry-run default and write mode", async () => {
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-cli-rebuild-memory-lifecycle-"));
  await writeText(
    memoryDir,
    "facts/2026-03-08/fact-1.md",
    `---
id: fact-1
category: fact
created: 2026-03-08T00:00:00.000Z
updated: 2026-03-08T01:00:00.000Z
source: test
confidence: 0.8
confidenceTier: implied
tags: ["alpha"]
---

alpha
`,
  );

  const dryRunResult = await runRebuildMemoryLifecycleLedgerCliCommand({ memoryDir });
  assert.equal(dryRunResult.dryRun, true);
  await assert.rejects(() => stat(dryRunResult.outputPath));

  const writeResult = await runRebuildMemoryLifecycleLedgerCliCommand({
    memoryDir,
    write: true,
    now: new Date("2026-03-08T12:00:00.000Z"),
  });
  assert.equal(writeResult.dryRun, false);
  await stat(writeResult.outputPath);
});

test("rebuild-memory-projection CLI wrapper respects dry-run default and write mode", { skip: skipUnlessBetterSqlite3() }, async () => {
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-cli-rebuild-memory-projection-"));
  await writeText(
    memoryDir,
    "facts/2026-03-08/fact-1.md",
    `---
id: fact-1
category: fact
created: 2026-03-08T00:00:00.000Z
updated: 2026-03-08T01:00:00.000Z
source: test
confidence: 0.8
confidenceTier: implied
tags: ["alpha"]
---

alpha
`,
  );

  const dryRunResult = await runRebuildMemoryProjectionCliCommand({ memoryDir });
  assert.equal(dryRunResult.dryRun, true);
  await assert.rejects(() => stat(dryRunResult.outputPath));

  const writeResult = await runRebuildMemoryProjectionCliCommand({
    memoryDir,
    write: true,
    now: new Date("2026-03-08T12:00:00.000Z"),
  });
  assert.equal(writeResult.dryRun, false);
  await stat(writeResult.outputPath);
});

test("memory-timeline CLI wrapper reads rows from the derived projection store", { skip: skipUnlessBetterSqlite3() }, async () => {
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-cli-memory-timeline-"));
  await writeText(
    memoryDir,
    "facts/2026-03-08/fact-1.md",
    `---
id: fact-1
category: fact
created: 2026-03-08T00:00:00.000Z
updated: 2026-03-08T01:00:00.000Z
source: test
confidence: 0.8
confidenceTier: implied
tags: ["alpha"]
---

alpha
`,
  );
  await runRebuildMemoryProjectionCliCommand({
    memoryDir,
    write: true,
    now: new Date("2026-03-08T12:00:00.000Z"),
  });

  const rows = await runMemoryTimelineCliCommand({
    memoryDir,
    memoryId: "fact-1",
  });
  assert.deepEqual(rows.map((row) => row.eventType), ["created", "updated"]);
});

test("verify-memory-projection and repair-memory-projection CLI wrappers detect and repair drift", { skip: skipUnlessBetterSqlite3() }, async () => {
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-cli-verify-memory-projection-"));
  await writeText(
    memoryDir,
    "facts/2026-03-08/fact-1.md",
    `---
id: fact-1
category: fact
created: 2026-03-08T00:00:00.000Z
updated: 2026-03-08T01:00:00.000Z
source: test
confidence: 0.8
confidenceTier: implied
tags: ["alpha"]
---

alpha
`,
  );
  await runRebuildMemoryProjectionCliCommand({
    memoryDir,
    write: true,
    now: new Date("2026-03-08T02:00:00.000Z"),
  });

  await writeText(
    memoryDir,
    "facts/2026-03-08/fact-2.md",
    `---
id: fact-2
category: fact
created: 2026-03-08T00:00:00.000Z
updated: 2026-03-08T03:00:00.000Z
source: test
confidence: 0.8
confidenceTier: implied
tags: ["beta"]
---

beta
`,
  );

  const verify = await runVerifyMemoryProjectionCliCommand({ memoryDir });
  assert.equal(verify.ok, false);
  assert.deepEqual(verify.missingCurrentMemoryIds, ["fact-2"]);

  const dryRunRepair = await runRepairMemoryProjectionCliCommand({ memoryDir });
  assert.equal(dryRunRepair.dryRun, true);
  assert.equal(dryRunRepair.repaired, false);

  const writeRepair = await runRepairMemoryProjectionCliCommand({
    memoryDir,
    write: true,
    now: new Date("2026-03-08T04:00:00.000Z"),
  });
  assert.equal(writeRepair.dryRun, false);
  assert.equal(writeRepair.repaired, true);

  const verifiedAfter = await runVerifyMemoryProjectionCliCommand({ memoryDir });
  assert.equal(verifiedAfter.ok, true);
});

test("migrate-observations CLI wrapper respects dry-run default and write mode", async () => {
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-cli-migrate-observations-"));
  await writeText(
    memoryDir,
    "state/observation-ledger/legacy.jsonl",
    JSON.stringify({
      session: "agent:main:default",
      timestamp: "2026-02-25T10:05:00.000Z",
      role: "user",
    }) + "\n",
  );

  const dryRunResult = await runMigrateObservationsCliCommand({ memoryDir });
  assert.equal(dryRunResult.dryRun, true);
  await assert.rejects(() => stat(dryRunResult.outputPath));

  const writeResult = await runMigrateObservationsCliCommand({
    memoryDir,
    write: true,
    now: new Date("2026-02-26T12:00:00.000Z"),
  });
  assert.equal(writeResult.dryRun, false);
  await stat(writeResult.outputPath);
});
