"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const git_1 = require("../../utils/git");
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const uuid_1 = require("uuid");
const simple_git_1 = require("simple-git");
const database_helper_js_1 = require("../../test-helpers/database-helper.js");
describe('Git Integration Tests', () => {
    let dbManager;
    let gitOps;
    let tempDbPath;
    let tempRepoPath;
    let db;
    let git; // Track git instance for cleanup
    beforeEach(async () => {
        tempDbPath = path.join(os.tmpdir(), `test-git-${Date.now()}.db`);
        tempRepoPath = path.join(os.tmpdir(), `test-repo-${Date.now()}`);
        dbManager = database_helper_js_1.TestDatabaseHelper.createTestDatabase();
        db = dbManager.getDatabase();
        // Create and initialize a real git repo for testing
        fs.mkdirSync(tempRepoPath, { recursive: true });
        git = (0, simple_git_1.simpleGit)(tempRepoPath);
        await git.init();
        await git.addConfig('user.name', 'Test User');
        await git.addConfig('user.email', 'test@example.com');
        // Create initial commit
        fs.writeFileSync(path.join(tempRepoPath, 'README.md'), '# Test Repo');
        await git.add('.');
        await git.commit('Initial commit');
        gitOps = new git_1.GitOperations(tempRepoPath);
    });
    afterEach(async () => {
        // Clean up git processes first
        if (git) {
            try {
                // Clear any pending git operations
                git.removeAllListeners?.();
            }
            catch (error) {
                console.warn('Error cleaning up git:', error);
            }
        }
        // Clean up databases
        await database_helper_js_1.TestDatabaseHelper.cleanupAll();
        // Clean up temp directories and files
        try {
            database_helper_js_1.TestDatabaseHelper.cleanupDbFiles(tempDbPath);
            fs.rmSync(tempRepoPath, { recursive: true, force: true });
        }
        catch (error) {
            console.warn('Error cleaning up temp files:', error);
        }
        git = null;
    });
    describe('context_git_commit', () => {
        it('should automatically save context on commit', async () => {
            const sessionId = (0, uuid_1.v4)();
            db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(sessionId, 'Git Test Session');
            // Add context items
            const items = [
                { key: 'current_task', value: 'Implementing git integration', priority: 'high' },
                { key: 'decision', value: 'Use simple-git library', priority: 'normal' },
            ];
            items.forEach(item => {
                db.prepare('INSERT INTO context_items (id, session_id, key, value, priority) VALUES (?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), sessionId, item.key, item.value, item.priority);
            });
            // Make a change and commit
            fs.writeFileSync(path.join(tempRepoPath, 'test.txt'), 'test content');
            const git = (0, simple_git_1.simpleGit)(tempRepoPath);
            await git.add('.');
            const commitResult = await git.commit('Test commit');
            // Simulate auto-save on commit
            const checkpointId = (0, uuid_1.v4)();
            const gitInfo = await gitOps.getGitInfo();
            db.prepare('INSERT INTO checkpoints (id, session_id, name, description, git_status, git_branch) VALUES (?, ?, ?, ?, ?, ?)').run(checkpointId, sessionId, `Git commit: ${commitResult.commit}`, 'Auto-saved on git commit', gitInfo.status, gitInfo.branch);
            // Link context items
            const contextItems = db
                .prepare('SELECT id FROM context_items WHERE session_id = ?')
                .all(sessionId);
            contextItems.forEach((item) => {
                db.prepare('INSERT INTO checkpoint_items (id, checkpoint_id, context_item_id) VALUES (?, ?, ?)').run((0, uuid_1.v4)(), checkpointId, item.id);
            });
            // Verify checkpoint was created
            const checkpoint = db
                .prepare('SELECT * FROM checkpoints WHERE id = ?')
                .get(checkpointId);
            expect(checkpoint).toBeDefined();
            expect(checkpoint.name).toContain('Git commit:');
            expect(checkpoint.git_branch).toBeTruthy();
        });
        it('should capture git status in checkpoint', async () => {
            const sessionId = (0, uuid_1.v4)();
            db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(sessionId, 'Status Test');
            // Create some changes
            fs.writeFileSync(path.join(tempRepoPath, 'modified.txt'), 'original');
            const git = (0, simple_git_1.simpleGit)(tempRepoPath);
            await git.add('.');
            await git.commit('Add file');
            // Modify file
            fs.writeFileSync(path.join(tempRepoPath, 'modified.txt'), 'changed');
            // Create new file
            fs.writeFileSync(path.join(tempRepoPath, 'new.txt'), 'new content');
            // Stage one file
            await git.add('modified.txt');
            // Get git info
            const gitInfo = await gitOps.getGitInfo();
            // Create checkpoint with git status
            const checkpointId = (0, uuid_1.v4)();
            db.prepare('INSERT INTO checkpoints (id, session_id, name, git_status, git_branch) VALUES (?, ?, ?, ?, ?)').run(checkpointId, sessionId, 'Status Checkpoint', gitInfo.status, gitInfo.branch);
            const checkpoint = db
                .prepare('SELECT * FROM checkpoints WHERE id = ?')
                .get(checkpointId);
            expect(checkpoint.git_status).toContain('modified.txt');
            // Parse the status to check properly
            const status = JSON.parse(checkpoint.git_status);
            expect(status.not_added).toContain('new.txt');
            expect(checkpoint.git_branch).toBe('master'); // Default branch name
        });
        it('should handle commits with message containing context summary', async () => {
            const sessionId = (0, uuid_1.v4)();
            db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(sessionId, 'Commit Message Test');
            // Add context items that should be in commit message
            const tasks = [
                { key: 'task1', value: 'Fixed authentication bug' },
                { key: 'task2', value: 'Added user validation' },
            ];
            tasks.forEach(task => {
                db.prepare('INSERT INTO context_items (id, session_id, key, value, category) VALUES (?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), sessionId, task.key, task.value, 'task');
            });
            // Generate commit message with context
            const completedTasks = db
                .prepare('SELECT value FROM context_items WHERE session_id = ? AND category = ?')
                .all(sessionId, 'task');
            const commitMessage = [
                'Feature: User authentication improvements',
                '',
                'Tasks completed:',
                ...completedTasks.map((t) => `- ${t.value}`),
                '',
                '[Context saved by MCP Memory Keeper]',
            ].join('\n');
            // Make change and commit
            fs.writeFileSync(path.join(tempRepoPath, 'auth.js'), 'auth code');
            const git = (0, simple_git_1.simpleGit)(tempRepoPath);
            await git.add('.');
            const commitResult = await git.commit(commitMessage);
            expect(commitResult.commit).toBeTruthy();
            // Verify commit message
            const log = await git.log(['-1']);
            expect(log.latest).toBeDefined();
            expect(log.latest?.message || log.latest?.hash).toBeDefined();
            // The actual message should be in the latest entry
        });
        it('should link commits to sessions', async () => {
            const sessionId = (0, uuid_1.v4)();
            db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(sessionId, 'Linked Commit Test');
            // Make multiple commits
            const git = (0, simple_git_1.simpleGit)(tempRepoPath);
            const commits = [];
            for (let i = 0; i < 3; i++) {
                fs.writeFileSync(path.join(tempRepoPath, `file${i}.txt`), `content ${i}`);
                await git.add('.');
                const result = await git.commit(`Commit ${i}`);
                commits.push(result.commit);
                // Link commit to session - store commit hash in description
                const checkpointId = (0, uuid_1.v4)();
                db.prepare('INSERT INTO checkpoints (id, session_id, name, description) VALUES (?, ?, ?, ?)').run(checkpointId, sessionId, `Commit ${i}`, `Commit hash: ${result.commit}`);
            }
            // Query commits for session - using description field instead of metadata
            const sessionCommits = db
                .prepare(`SELECT * FROM checkpoints 
         WHERE session_id = ? 
         AND description LIKE 'Commit hash:%'
         ORDER BY created_at`)
                .all(sessionId);
            expect(sessionCommits).toHaveLength(3);
            sessionCommits.forEach((checkpoint, i) => {
                // Extract commit hash from description
                const match = checkpoint.description.match(/Commit hash: (.+)/);
                expect(match).toBeTruthy();
                expect(match[1]).toBe(commits[i]);
            });
        });
    });
    describe('Git error handling', () => {
        it('should handle non-git directories gracefully', async () => {
            const nonGitPath = path.join(os.tmpdir(), `non-git-${Date.now()}`);
            fs.mkdirSync(nonGitPath, { recursive: true });
            const nonGitOps = new git_1.GitOperations(nonGitPath);
            const info = await nonGitOps.getGitInfo();
            expect(info.isGitRepo).toBe(false);
            expect(info.status.toLowerCase()).toContain('not a git repository');
            fs.rmSync(nonGitPath, { recursive: true, force: true });
        });
        it('should handle git operation failures', async () => {
            // Test with invalid commit (no changes)
            const result = await gitOps.safeCommit('Empty commit');
            expect(result.success).toBe(false);
            expect(result.error).toContain('No changes to commit');
        });
    });
});
