import fs from 'node:fs';
import fsp from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import readline from 'node:readline';
import { sessionsDb } from '../../../../modules/database/index.js';
import { extractFirstValidJsonlData, findFilesRecursivelyCreatedAfter, normalizeSessionName, readFileTimestamps, } from '../../../../shared/utils.js';
/**
 * Returns directory entries or an empty list when the folder is missing.
 */
async function listDirectoryEntriesSafe(directoryPath) {
    try {
        return await fsp.readdir(directoryPath, { withFileTypes: true });
    }
    catch {
        return [];
    }
}
/**
 * Session indexer for Cursor transcript artifacts.
 */
export class CursorSessionSynchronizer {
    provider = 'cursor';
    cursorHome = path.join(os.homedir(), '.cursor');
    /**
     * Scans Cursor chats and upserts discovered sessions into DB.
     */
    async synchronize(since, ownerUserId) {
        const projectsDir = path.join(this.cursorHome, 'projects');
        let processed = 0;
        const files = await findFilesRecursivelyCreatedAfter(projectsDir, '.jsonl', since ?? null);
        for (const filePath of files) {
            const parsed = await this.processSessionFile(filePath);
            if (!parsed) {
                continue;
            }
            const timestamps = await readFileTimestamps(filePath);
            sessionsDb.createSession(ownerUserId, parsed.sessionId, this.provider, parsed.projectPath, parsed.sessionName, timestamps.createdAt, timestamps.updatedAt, filePath);
            processed += 1;
        }
        return processed;
    }
    /**
     * Parses and upserts one Cursor session JSONL file.
     */
    async synchronizeFile(filePath, ownerUserId) {
        if (!filePath.endsWith('.jsonl')) {
            return null;
        }
        const parsed = await this.processSessionFile(filePath);
        if (!parsed) {
            return null;
        }
        const timestamps = await readFileTimestamps(filePath);
        return sessionsDb.createSession(ownerUserId, parsed.sessionId, this.provider, parsed.projectPath, parsed.sessionName, timestamps.createdAt, timestamps.updatedAt, filePath);
    }
    /**
     * Extracts project path from Cursor worker.log.
     */
    async extractProjectPathFromWorkerLog(filePath) {
        try {
            const fileStream = fs.createReadStream(filePath, { encoding: 'utf8' });
            const lineReader = readline.createInterface({ input: fileStream, crlfDelay: Infinity });
            for await (const line of lineReader) {
                const match = line.match(/workspacePath=(.*)$/);
                const projectPath = match?.[1]?.trim();
                if (projectPath) {
                    lineReader.close();
                    fileStream.close();
                    return projectPath;
                }
            }
        }
        catch {
            // Missing worker logs are valid for partial or incomplete session data.
        }
        return null;
    }
    /**
     * Extracts session metadata from one Cursor JSONL session file.
     */
    async processSessionFile(filePath) {
        const sessionId = path.basename(filePath, '.jsonl');
        const grandparentDir = path.dirname(path.dirname(path.dirname(filePath)));
        const workerLogPath = path.join(grandparentDir, 'worker.log');
        const projectPath = await this.extractProjectPathFromWorkerLog(workerLogPath);
        if (!projectPath) {
            return null;
        }
        return extractFirstValidJsonlData(filePath, (rawData) => {
            const data = rawData;
            if (data.role !== 'user') {
                return null;
            }
            const text = typeof data.message?.content?.[0]?.text === 'string' ? data.message.content[0].text : '';
            const firstLine = text.replace(/<\/?user_query>/g, '').trim().split('\n')[0];
            return {
                sessionId,
                projectPath,
                sessionName: normalizeSessionName(firstLine, 'Untitled Cursor Session'),
            };
        });
    }
}
//# sourceMappingURL=cursor-session-synchronizer.provider.js.map