/**
 * UOK Memory Integration Tests
 *
 * Verify that UOK records unit outcomes in memory for learning.
 * Tests cover: success/failure recording, graceful degradation, pattern quality.
 */

import { beforeEach, describe, expect, it, vi } from "vitest";
import { recordUnitOutcomeInMemory } from "../uok/unit-runtime.js";

// Mock memory store and DB
vi.mock("../memory-store.js", () => ({
	createMemory: vi.fn().mockResolvedValue(undefined),
	getRelevantMemoriesRanked: vi.fn().mockResolvedValue([]),
}));

vi.mock("../sf-db.js", () => ({
	isDbAvailable: vi.fn().mockReturnValue(true),
	getSlice: vi.fn().mockResolvedValue(null),
}));

import * as memoryStore from "../memory-store.js";
import * as sfDb from "../sf-db.js";

function expectMemoryCreate(fields) {
	expect(memoryStore.createMemory).toHaveBeenCalledWith(
		expect.objectContaining(fields),
	);
}

describe("UOK Memory Integration", () => {
	beforeEach(() => {
		vi.clearAllMocks();
		sfDb.isDbAvailable.mockReturnValue(true);
	});

	describe("recordUnitOutcomeInMemory", () => {
		it("records_successful_unit_completion_as_pattern", async () => {
			const unit = { type: "execute-task", id: "M001-S01-T01" };
			const status = "completed";
			const result = { outcome: "all tests passed" };

			await recordUnitOutcomeInMemory(unit, status, result);

			expectMemoryCreate({
				category: "pattern",
				content:
					"Unit type 'execute-task' succeeded with outcome: all tests passed",
				confidence: 0.9,
				source_unit_type: "execute-task",
				source_unit_id: "M001-S01-T01",
			});
		});

		it("records_failed_unit_completion_as_pattern", async () => {
			const unit = { type: "research-slice", id: "M001-S02" };
			const status = "failed";
			const result = { error: "timeout after 5 minutes" };

			await recordUnitOutcomeInMemory(unit, status, result);

			expectMemoryCreate({
				category: "pattern",
				content:
					"Unit type 'research-slice' failed with status: failed (timeout after 5 minutes)",
				confidence: 0.5,
				source_unit_type: "research-slice",
				source_unit_id: "M001-S02",
			});
		});

		it("uses_lower_confidence_for_failures", async () => {
			const unit = { type: "test-unit" };
			const successCall = () =>
				recordUnitOutcomeInMemory(unit, "completed", {});
			const failureCall = () => recordUnitOutcomeInMemory(unit, "failed", {});

			await successCall();
			await failureCall();

			const successConfidence =
				memoryStore.createMemory.mock.calls[0][0].confidence;
			const failureConfidence =
				memoryStore.createMemory.mock.calls[1][0].confidence;

			expect(successConfidence).toBe(0.9);
			expect(failureConfidence).toBe(0.5);
		});

		it("degrades_gracefully_when_db_unavailable", async () => {
			sfDb.isDbAvailable.mockReturnValue(false);
			const unit = { type: "test-unit" };

			// Should not throw
			await expect(
				recordUnitOutcomeInMemory(unit, "completed", {}),
			).resolves.toBeUndefined();

			// Should not call memory store
			expect(memoryStore.createMemory).not.toHaveBeenCalled();
		});

		it("degrades_gracefully_when_memory_store_errors", async () => {
			memoryStore.createMemory.mockRejectedValueOnce(
				new Error("DB connection failed"),
			);
			const unit = { type: "test-unit" };

			// Should not throw
			await expect(
				recordUnitOutcomeInMemory(unit, "completed", {}),
			).resolves.toBeUndefined();
		});

		it("handles_blocked_status_as_failure", async () => {
			const unit = { type: "research-task" };
			const status = "blocked";
			const result = { error: "gate evaluation failed" };

			await recordUnitOutcomeInMemory(unit, status, result);

			expectMemoryCreate({
				category: "pattern",
				content: expect.stringContaining("blocked"),
				confidence: 0.5,
			});
		});

		it("handles_stale_status_as_failure", async () => {
			const unit = { type: "long-running-task" };
			const status = "stale";
			const result = { error: "timeout" };

			await recordUnitOutcomeInMemory(unit, status, result);

			expectMemoryCreate({
				category: "pattern",
				content: expect.stringContaining("stale"),
				confidence: 0.5,
			});
		});

		it("extracts_unitType_from_unitType_property", async () => {
			const unit = { unitType: "plan-milestone" };
			const status = "completed";

			await recordUnitOutcomeInMemory(unit, status, {});

			expectMemoryCreate({
				category: "pattern",
				content: expect.stringContaining("plan-milestone"),
				confidence: 0.9,
				source_unit_type: "plan-milestone",
			});
		});

		it("defaults_to_unknown_if_no_type_provided", async () => {
			const unit = {};
			const status = "completed";

			await recordUnitOutcomeInMemory(unit, status, {});

			expectMemoryCreate({
				category: "pattern",
				content: expect.stringContaining("unknown"),
				confidence: 0.9,
				source_unit_type: "unknown",
			});
		});

		it("uses_status_as_outcome_when_result_outcome_missing", async () => {
			const unit = { type: "test-unit" };
			const status = "completed";
			const result = {};

			await recordUnitOutcomeInMemory(unit, status, result);

			expectMemoryCreate({
				category: "pattern",
				content: "Unit type 'test-unit' succeeded with outcome: completed",
				confidence: 0.9,
			});
		});

		it("categorizes_all_patterns_as_pattern_category", async () => {
			const unit = { type: "unit1" };

			await recordUnitOutcomeInMemory(unit, "completed", {});
			await recordUnitOutcomeInMemory(unit, "failed", {});
			await recordUnitOutcomeInMemory(unit, "blocked", {});

			for (const call of memoryStore.createMemory.mock.calls) {
				expect(call[0].category).toBe("pattern");
			}
		});

		it("logs_different_errors_in_failure_patterns", async () => {
			const unit = { type: "test-unit" };

			await recordUnitOutcomeInMemory(unit, "failed", {
				error: "timeout",
			});
			await recordUnitOutcomeInMemory(unit, "failed", { error: "auth failed" });

			const call1 = memoryStore.createMemory.mock.calls[0][0].content;
			const call2 = memoryStore.createMemory.mock.calls[1][0].content;

			expect(call1).toContain("timeout");
			expect(call2).toContain("auth failed");
		});

		it("handles_undefined_result_gracefully", async () => {
			const unit = { type: "test-unit" };
			const status = "completed";

			// Should not throw with undefined result
			await expect(
				recordUnitOutcomeInMemory(unit, status, undefined),
			).resolves.toBeUndefined();

			expect(memoryStore.createMemory).toHaveBeenCalled();
		});

		it("stores_pattern_in_correct_category", async () => {
			const unit = { type: "any-unit" };

			await recordUnitOutcomeInMemory(unit, "completed", {});

			const categoryArg = memoryStore.createMemory.mock.calls[0][0].category;
			expect(categoryArg).toBe("pattern");
		});

		it("produces_meaningful_pattern_descriptions", async () => {
			const unit = { type: "code-review", id: "M001-S03" };
			const result = { outcome: "3 files reviewed, 2 issues found" };

			await recordUnitOutcomeInMemory(unit, "completed", result);

			const pattern = memoryStore.createMemory.mock.calls[0][0].content;
			expect(pattern).toMatch(/code-review/);
			expect(pattern).toMatch(/succeeded/);
			expect(pattern).toMatch(/3 files reviewed/);
		});
	});

	describe("Integration with UOK lifecycle", () => {
		it("does_not_block_on_memory_errors", async () => {
			memoryStore.createMemory.mockImplementationOnce(() => {
				// Simulate slow memory operation
				return new Promise((resolve) => setTimeout(resolve, 100));
			});

			const unit = { type: "fast-unit" };
			const start = Date.now();

			await recordUnitOutcomeInMemory(unit, "completed", {});

			const _elapsed = Date.now() - start;
			// Should complete (duration doesn't matter much in test)
			expect(memoryStore.createMemory).toHaveBeenCalled();
		});

		it("processes_multiple_outcomes_independently", async () => {
			const units = [{ type: "type1" }, { type: "type2" }, { type: "type3" }];

			for (const unit of units) {
				await recordUnitOutcomeInMemory(unit, "completed", {});
			}

			expect(memoryStore.createMemory).toHaveBeenCalledTimes(3);
		});

		it("preserves_unit_information_in_pattern", async () => {
			const unit = { type: "specific-task-type", id: "M001-S01-T05" };
			await recordUnitOutcomeInMemory(unit, "completed", {
				outcome: "very specific outcome",
			});

			const pattern = memoryStore.createMemory.mock.calls[0][0].content;
			expect(pattern).toContain("specific-task-type");
		});
	});
});
