import { mkdtemp, rm } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { openDatabase, closeDatabase } from "../../database.js";
import { createProject, getProject, getProjectByPath, listProjects, updateProjectLastOpened, deleteProject, } from "../projects.js";
describe("projects repository", () => {
    let tempDir;
    let dbPath;
    beforeEach(async () => {
        tempDir = await mkdtemp(join(tmpdir(), "pocketcoder-projects-test-"));
        dbPath = join(tempDir, "daemon.db");
        closeDatabase();
        openDatabase(dbPath);
    });
    afterEach(async () => {
        closeDatabase();
        await rm(tempDir, { recursive: true, force: true });
    });
    it("should create project with generated UUID", () => {
        const project = createProject("my-app", "/home/user/my-app");
        expect(project.project_id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
        expect(project.name).toBe("my-app");
        expect(project.path).toBe("/home/user/my-app");
        expect(project.created_at).toBeDefined();
    });
    it("should get project by ID", () => {
        const created = createProject("test-proj", "/tmp/test-proj");
        const fetched = getProject(created.project_id);
        expect(fetched).not.toBeNull();
        expect(fetched.project_id).toBe(created.project_id);
        expect(fetched.name).toBe("test-proj");
        expect(fetched.path).toBe("/tmp/test-proj");
    });
    it("should get project by path", () => {
        createProject("by-path", "/home/user/by-path");
        const found = getProjectByPath("/home/user/by-path");
        expect(found).not.toBeNull();
        expect(found.name).toBe("by-path");
    });
    it("should list all projects", () => {
        createProject("alpha", "/tmp/alpha");
        createProject("beta", "/tmp/beta");
        createProject("gamma", "/tmp/gamma");
        const projects = listProjects();
        expect(projects).toHaveLength(3);
        // Ordered by name
        expect(projects.map((p) => p.name)).toEqual(["alpha", "beta", "gamma"]);
    });
    it("should update last_opened_at timestamp", () => {
        const project = createProject("open-test", "/tmp/open-test");
        expect(project.last_opened_at).toBeNull();
        updateProjectLastOpened(project.project_id);
        const updated = getProject(project.project_id);
        expect(updated.last_opened_at).not.toBeNull();
    });
    it("should delete project and cascade related data", () => {
        const project = createProject("to-delete", "/tmp/to-delete");
        // Insert related rows to verify cascade
        const db = openDatabase();
        db.prepare("INSERT INTO fs_state (project_id, last_seq) VALUES (?, 0)").run(project.project_id);
        db.prepare("INSERT INTO command_runs (request_id, project_id, command) VALUES (?, ?, ?)").run("req-1", project.project_id, "echo hello");
        deleteProject(project.project_id);
        expect(getProject(project.project_id)).toBeNull();
        // Verify cascaded deletes
        const fsState = db
            .prepare("SELECT * FROM fs_state WHERE project_id = ?")
            .get(project.project_id);
        expect(fsState).toBeUndefined();
        const cmdRun = db
            .prepare("SELECT * FROM command_runs WHERE project_id = ?")
            .get(project.project_id);
        expect(cmdRun).toBeUndefined();
    });
    it("should return null for non-existent project", () => {
        expect(getProject("non-existent-id")).toBeNull();
        expect(getProjectByPath("/non/existent/path")).toBeNull();
    });
    it("should enforce unique path constraint", () => {
        createProject("first", "/tmp/unique-path");
        expect(() => createProject("second", "/tmp/unique-path")).toThrow();
    });
});
//# sourceMappingURL=projects.test.js.map