"use strict";
/**
 * Database operations for myCodeBranchDesk
 * SQLite database client and CRUD operations
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.initDatabase = initDatabase;
exports.getWorktrees = getWorktrees;
exports.getRepositories = getRepositories;
exports.getWorktreeById = getWorktreeById;
exports.upsertWorktree = upsertWorktree;
exports.updateWorktreeDescription = updateWorktreeDescription;
exports.updateWorktreeLink = updateWorktreeLink;
exports.updateLastViewedAt = updateLastViewedAt;
exports.getLastAssistantMessageAt = getLastAssistantMessageAt;
exports.createMessage = createMessage;
exports.updateMessageContent = updateMessageContent;
exports.getMessages = getMessages;
exports.getLastUserMessage = getLastUserMessage;
exports.getLastMessage = getLastMessage;
exports.deleteAllMessages = deleteAllMessages;
exports.getSessionState = getSessionState;
exports.updateSessionState = updateSessionState;
exports.setInProgressMessageId = setInProgressMessageId;
exports.clearInProgressMessageId = clearInProgressMessageId;
exports.deleteSessionState = deleteSessionState;
exports.updateLastUserMessage = updateLastUserMessage;
exports.getMessageById = getMessageById;
exports.updatePromptData = updatePromptData;
exports.markPendingPromptsAsAnswered = markPendingPromptsAsAnswered;
exports.updateFavorite = updateFavorite;
exports.updateStatus = updateStatus;
exports.updateCliToolId = updateCliToolId;
exports.getMemosByWorktreeId = getMemosByWorktreeId;
exports.getMemoById = getMemoById;
exports.createMemo = createMemo;
exports.updateMemo = updateMemo;
exports.deleteMemo = deleteMemo;
exports.reorderMemos = reorderMemos;
exports.saveInitialBranch = saveInitialBranch;
exports.getInitialBranch = getInitialBranch;
exports.getWorktreeIdsByRepository = getWorktreeIdsByRepository;
exports.deleteRepositoryWorktrees = deleteRepositoryWorktrees;
exports.deleteWorktreesByIds = deleteWorktreesByIds;
const crypto_1 = require("crypto");
function mapChatMessage(row) {
    return {
        id: row.id,
        worktreeId: row.worktree_id,
        role: row.role,
        content: row.content,
        summary: row.summary || undefined,
        timestamp: new Date(row.timestamp),
        logFileName: row.log_file_name || undefined,
        requestId: row.request_id || undefined,
        messageType: row.message_type || 'normal',
        promptData: row.prompt_data ? JSON.parse(row.prompt_data) : undefined,
        cliToolId: row.cli_tool_id ?? 'claude',
    };
}
/**
 * Initialize database schema
 */
function initDatabase(db) {
    // Create worktrees table
    db.exec(`
    CREATE TABLE IF NOT EXISTS worktrees (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      path TEXT NOT NULL UNIQUE,
      last_message_summary TEXT,
      updated_at INTEGER
    );
  `);
    // Create index for sorting by updated_at
    db.exec(`
    CREATE INDEX IF NOT EXISTS idx_worktrees_updated_at
    ON worktrees(updated_at DESC);
  `);
    // Create chat_messages table
    db.exec(`
    CREATE TABLE IF NOT EXISTS chat_messages (
      id TEXT PRIMARY KEY,
      worktree_id TEXT NOT NULL,
      role TEXT NOT NULL CHECK(role IN ('user', 'assistant')),
      content TEXT NOT NULL,
      summary TEXT,
      timestamp INTEGER NOT NULL,
      log_file_name TEXT,
      request_id TEXT,
      message_type TEXT DEFAULT 'normal',
      prompt_data TEXT,
      cli_tool_id TEXT DEFAULT 'claude',

      FOREIGN KEY (worktree_id) REFERENCES worktrees(id) ON DELETE CASCADE
    );
  `);
    // Create indexes for chat_messages
    db.exec(`
    CREATE INDEX IF NOT EXISTS idx_messages_worktree_time
    ON chat_messages(worktree_id, timestamp DESC);
  `);
    db.exec(`
    CREATE INDEX IF NOT EXISTS idx_messages_request_id
    ON chat_messages(request_id);
  `);
    db.exec(`
    CREATE INDEX IF NOT EXISTS idx_messages_type
    ON chat_messages(message_type, worktree_id);
  `);
    db.exec(`
    CREATE INDEX IF NOT EXISTS idx_messages_cli_tool
    ON chat_messages(worktree_id, cli_tool_id, timestamp DESC);
  `);
    // Create session_states table
    db.exec(`
    CREATE TABLE IF NOT EXISTS session_states (
      worktree_id TEXT NOT NULL,
      cli_tool_id TEXT NOT NULL DEFAULT 'claude',
      last_captured_line INTEGER DEFAULT 0,

      PRIMARY KEY (worktree_id, cli_tool_id),
      FOREIGN KEY (worktree_id) REFERENCES worktrees(id) ON DELETE CASCADE
    );
  `);
}
/**
 * Get latest user message per CLI tool for multiple worktrees (batch query)
 * Optimized to avoid N+1 query problem
 */
function getLastMessagesByCliBatch(db, worktreeIds) {
    if (worktreeIds.length === 0) {
        return new Map();
    }
    // Single query to get latest user message for each worktree/cli_tool combination
    // Uses window function to rank messages and filter to only the latest per group
    const placeholders = worktreeIds.map(() => '?').join(',');
    const stmt = db.prepare(`
    WITH ranked_messages AS (
      SELECT
        worktree_id,
        cli_tool_id,
        content,
        ROW_NUMBER() OVER (
          PARTITION BY worktree_id, cli_tool_id
          ORDER BY timestamp DESC
        ) as rn
      FROM chat_messages
      WHERE worktree_id IN (${placeholders})
        AND role = 'user'
        AND cli_tool_id IN ('claude', 'codex', 'gemini')
    )
    SELECT worktree_id, cli_tool_id, content
    FROM ranked_messages
    WHERE rn = 1
  `);
    const rows = stmt.all(...worktreeIds);
    // Build result map
    const result = new Map();
    // Initialize all worktree IDs with empty objects
    for (const id of worktreeIds) {
        result.set(id, {});
    }
    // Populate with query results
    for (const row of rows) {
        const existing = result.get(row.worktree_id) || {};
        existing[row.cli_tool_id] = row.content.substring(0, 50);
        result.set(row.worktree_id, existing);
    }
    return result;
}
/**
 * Get all worktrees sorted by updated_at (desc)
 * Optionally filter by repository path
 * Includes lastViewedAt and lastAssistantMessageAt for unread tracking
 */
function getWorktrees(db, repositoryPath) {
    let query = `
    SELECT
      w.id, w.name, w.path, w.repository_path, w.repository_name, w.description,
      w.last_user_message, w.last_user_message_at, w.last_message_summary,
      w.updated_at, w.favorite, w.status, w.link, w.cli_tool_id, w.last_viewed_at,
      (SELECT MAX(timestamp) FROM chat_messages
       WHERE worktree_id = w.id AND role = 'assistant') as last_assistant_message_at
    FROM worktrees w
  `;
    const params = [];
    if (repositoryPath) {
        query += ` WHERE w.repository_path = ?`;
        params.push(repositoryPath);
    }
    query += ` ORDER BY w.updated_at DESC NULLS LAST`;
    const stmt = db.prepare(query);
    const rows = stmt.all(...params);
    // Batch fetch last messages for all worktrees (N+1 optimization)
    const worktreeIds = rows.map(row => row.id);
    const lastMessagesByCliMap = getLastMessagesByCliBatch(db, worktreeIds);
    return rows.map((row) => {
        const lastMessagesByCli = lastMessagesByCliMap.get(row.id) || {};
        return {
            id: row.id,
            name: row.name,
            path: row.path,
            repositoryPath: row.repository_path || '',
            repositoryName: row.repository_name || '',
            description: row.description || undefined,
            lastUserMessage: row.last_user_message || undefined,
            lastUserMessageAt: row.last_user_message_at ? new Date(row.last_user_message_at) : undefined,
            lastMessageSummary: row.last_message_summary || undefined,
            lastMessagesByCli,
            updatedAt: row.updated_at ? new Date(row.updated_at) : undefined,
            lastViewedAt: row.last_viewed_at ? new Date(row.last_viewed_at) : undefined,
            lastAssistantMessageAt: row.last_assistant_message_at ? new Date(row.last_assistant_message_at) : undefined,
            favorite: row.favorite === 1,
            status: row.status || null,
            link: row.link || undefined,
            cliToolId: row.cli_tool_id ?? 'claude',
        };
    });
}
/**
 * Get list of unique repositories from worktrees
 */
function getRepositories(db) {
    const stmt = db.prepare(`
    SELECT
      repository_path as path,
      repository_name as name,
      COUNT(*) as worktree_count
    FROM worktrees
    WHERE repository_path IS NOT NULL
    GROUP BY repository_path, repository_name
    ORDER BY repository_name ASC
  `);
    const rows = stmt.all();
    return rows.map((row) => ({
        path: row.path,
        name: row.name,
        worktreeCount: row.worktree_count,
    }));
}
/**
 * Get worktree by ID
 * Includes lastViewedAt and lastAssistantMessageAt for unread tracking
 */
function getWorktreeById(db, id) {
    const stmt = db.prepare(`
    SELECT
      w.id, w.name, w.path, w.repository_path, w.repository_name, w.description,
      w.last_user_message, w.last_user_message_at, w.last_message_summary,
      w.updated_at, w.favorite, w.status, w.link, w.cli_tool_id, w.last_viewed_at,
      (SELECT MAX(timestamp) FROM chat_messages
       WHERE worktree_id = w.id AND role = 'assistant') as last_assistant_message_at
    FROM worktrees w
    WHERE w.id = ?
  `);
    const row = stmt.get(id);
    if (!row) {
        return null;
    }
    return {
        id: row.id,
        name: row.name,
        path: row.path,
        repositoryPath: row.repository_path || '',
        repositoryName: row.repository_name || '',
        description: row.description || undefined,
        lastUserMessage: row.last_user_message || undefined,
        lastUserMessageAt: row.last_user_message_at ? new Date(row.last_user_message_at) : undefined,
        lastMessageSummary: row.last_message_summary || undefined,
        updatedAt: row.updated_at ? new Date(row.updated_at) : undefined,
        lastViewedAt: row.last_viewed_at ? new Date(row.last_viewed_at) : undefined,
        lastAssistantMessageAt: row.last_assistant_message_at ? new Date(row.last_assistant_message_at) : undefined,
        favorite: row.favorite === 1,
        status: row.status || null,
        link: row.link || undefined,
        cliToolId: row.cli_tool_id ?? 'claude',
    };
}
/**
 * Insert or update worktree
 */
function upsertWorktree(db, worktree) {
    // First, remove any existing worktree with the same path but different ID
    // This handles cases where the ID generation scheme has changed
    db.prepare('DELETE FROM worktrees WHERE path = ? AND id != ?').run(worktree.path, worktree.id);
    const stmt = db.prepare(`
    INSERT INTO worktrees (
      id, name, path, repository_path, repository_name, description,
      last_user_message, last_user_message_at, last_message_summary, updated_at, cli_tool_id
    )
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ON CONFLICT(id) DO UPDATE SET
      name = excluded.name,
      path = excluded.path,
      repository_path = excluded.repository_path,
      repository_name = excluded.repository_name,
      description = COALESCE(excluded.description, worktrees.description),
      last_user_message = COALESCE(excluded.last_user_message, worktrees.last_user_message),
      last_user_message_at = COALESCE(excluded.last_user_message_at, worktrees.last_user_message_at),
      last_message_summary = COALESCE(excluded.last_message_summary, worktrees.last_message_summary),
      updated_at = COALESCE(excluded.updated_at, worktrees.updated_at),
      cli_tool_id = COALESCE(excluded.cli_tool_id, worktrees.cli_tool_id)
  `);
    stmt.run(worktree.id, worktree.name, worktree.path, worktree.repositoryPath || null, worktree.repositoryName || null, worktree.description || null, worktree.lastUserMessage || null, worktree.lastUserMessageAt?.getTime() || null, worktree.lastMessageSummary || null, worktree.updatedAt?.getTime() || null, worktree.cliToolId || 'claude');
}
/**
 * Update worktree description
 */
function updateWorktreeDescription(db, worktreeId, description) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET description = ?
    WHERE id = ?
  `);
    stmt.run(description || null, worktreeId);
}
/**
 * Update worktree link
 */
function updateWorktreeLink(db, worktreeId, link) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET link = ?
    WHERE id = ?
  `);
    stmt.run(link || null, worktreeId);
}
/**
 * Update worktree's last_viewed_at timestamp
 * Used for unread tracking (Issue #31)
 */
function updateLastViewedAt(db, worktreeId, viewedAt) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET last_viewed_at = ?
    WHERE id = ?
  `);
    stmt.run(viewedAt.toISOString(), worktreeId);
}
/**
 * Get the timestamp of the most recent assistant message for a worktree
 * Used for unread tracking (Issue #31)
 */
function getLastAssistantMessageAt(db, worktreeId) {
    const stmt = db.prepare(`
    SELECT MAX(timestamp) as last_assistant_message_at
    FROM chat_messages
    WHERE worktree_id = ? AND role = 'assistant'
  `);
    const row = stmt.get(worktreeId);
    if (!row || row.last_assistant_message_at === null) {
        return null;
    }
    return new Date(row.last_assistant_message_at);
}
/**
 * Create a new chat message
 */
function createMessage(db, message) {
    const id = (0, crypto_1.randomUUID)();
    const stmt = db.prepare(`
    INSERT INTO chat_messages
    (id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `);
    stmt.run(id, message.worktreeId, message.role, message.content, message.summary || null, message.timestamp.getTime(), message.logFileName || null, message.requestId || null, message.messageType || 'normal', message.promptData ? JSON.stringify(message.promptData) : null, message.cliToolId || 'claude');
    // Update worktree's updated_at timestamp
    updateWorktreeTimestamp(db, message.worktreeId, message.timestamp);
    // If this is a user message, update last_user_message
    if (message.role === 'user') {
        updateLastUserMessage(db, message.worktreeId, message.content, message.timestamp);
    }
    return { id, ...message };
}
function updateMessageContent(db, messageId, content, options) {
    const assignments = ['content = ?'];
    const params = [content];
    if (options?.summary !== undefined) {
        assignments.push('summary = ?');
        params.push(options.summary ?? null);
    }
    if (options?.logFileName !== undefined) {
        assignments.push('log_file_name = ?');
        params.push(options.logFileName ?? null);
    }
    if (options?.requestId !== undefined) {
        assignments.push('request_id = ?');
        params.push(options.requestId ?? null);
    }
    const stmt = db.prepare(`
    UPDATE chat_messages
    SET ${assignments.join(', ')}
    WHERE id = ?
  `);
    stmt.run(...params, messageId);
}
/**
 * Get messages for a worktree, optionally filtered by CLI tool
 */
function getMessages(db, worktreeId, before, limit = 50, cliToolId) {
    let query = `
    SELECT id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id
    FROM chat_messages
    WHERE worktree_id = ? AND (? IS NULL OR timestamp < ?)
  `;
    const params = [worktreeId, before?.getTime() || null, before?.getTime() || null];
    // Add CLI tool filter if specified
    if (cliToolId) {
        query += ` AND cli_tool_id = ?`;
        params.push(cliToolId);
    }
    query += ` ORDER BY timestamp DESC LIMIT ?`;
    params.push(limit);
    const stmt = db.prepare(query);
    const rows = stmt.all(...params);
    return rows.map(mapChatMessage);
}
/**
 * Fetch the most recent user-authored message for a worktree.
 */
function getLastUserMessage(db, worktreeId) {
    const stmt = db.prepare(`
    SELECT id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id
    FROM chat_messages
    WHERE worktree_id = ? AND role = 'user'
    ORDER BY timestamp DESC
    LIMIT 1
  `);
    const row = stmt.get(worktreeId);
    return row ? mapChatMessage(row) : null;
}
/**
 * Fetch the most recent message for a worktree (any role).
 * Used to determine if waiting for Claude's response.
 */
function getLastMessage(db, worktreeId) {
    const stmt = db.prepare(`
    SELECT id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id
    FROM chat_messages
    WHERE worktree_id = ?
    ORDER BY timestamp DESC
    LIMIT 1
  `);
    const row = stmt.get(worktreeId);
    return row ? mapChatMessage(row) : null;
}
/**
 * Delete all messages for a worktree
 * Used when killing a session to clear message history
 * Note: Log files are preserved for historical reference
 */
function deleteAllMessages(db, worktreeId) {
    const stmt = db.prepare(`
    DELETE FROM chat_messages
    WHERE worktree_id = ?
  `);
    stmt.run(worktreeId);
    console.log(`[deleteAllMessages] Deleted all messages for worktree: ${worktreeId}`);
}
/**
 * Get session state for a worktree
 */
function getSessionState(db, worktreeId, cliToolId = 'claude') {
    const stmt = db.prepare(`
    SELECT worktree_id, cli_tool_id, last_captured_line, in_progress_message_id
    FROM session_states
    WHERE worktree_id = ? AND cli_tool_id = ?
  `);
    const row = stmt.get(worktreeId, cliToolId);
    if (!row) {
        return null;
    }
    return {
        worktreeId: row.worktree_id,
        cliToolId: row.cli_tool_id,
        lastCapturedLine: row.last_captured_line,
        inProgressMessageId: row.in_progress_message_id || null,
    };
}
/**
 * Update session state for a worktree
 */
function updateSessionState(db, worktreeId, cliToolId, lastCapturedLine) {
    const stmt = db.prepare(`
    INSERT INTO session_states (worktree_id, cli_tool_id, last_captured_line)
    VALUES (?, ?, ?)
    ON CONFLICT(worktree_id, cli_tool_id) DO UPDATE SET
      last_captured_line = excluded.last_captured_line
  `);
    stmt.run(worktreeId, cliToolId, lastCapturedLine);
}
/**
 * Set the in-progress message ID for a session
 */
function setInProgressMessageId(db, worktreeId, cliToolId, messageId) {
    const stmt = db.prepare(`
    INSERT INTO session_states (worktree_id, cli_tool_id, last_captured_line, in_progress_message_id)
    VALUES (?, ?, 0, ?)
    ON CONFLICT(worktree_id, cli_tool_id) DO UPDATE SET
      in_progress_message_id = excluded.in_progress_message_id
  `);
    stmt.run(worktreeId, cliToolId, messageId);
}
/**
 * Clear the in-progress message ID for a session
 */
function clearInProgressMessageId(db, worktreeId, cliToolId) {
    setInProgressMessageId(db, worktreeId, cliToolId, null);
}
/**
 * Delete session state for a worktree
 * Called when a session is killed or reset
 */
function deleteSessionState(db, worktreeId, cliToolId) {
    if (cliToolId) {
        const stmt = db.prepare(`
      DELETE FROM session_states
      WHERE worktree_id = ? AND cli_tool_id = ?
    `);
        stmt.run(worktreeId, cliToolId);
    }
    else {
        const stmt = db.prepare(`
      DELETE FROM session_states
      WHERE worktree_id = ?
    `);
        stmt.run(worktreeId);
    }
}
/**
 * Update worktree's updated_at timestamp
 * @private
 */
function updateWorktreeTimestamp(db, worktreeId, timestamp) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET updated_at = ?
    WHERE id = ?
  `);
    stmt.run(timestamp.getTime(), worktreeId);
}
/**
 * Update worktree's last user message
 */
function updateLastUserMessage(db, worktreeId, message, timestamp) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET last_user_message = ?,
        last_user_message_at = ?
    WHERE id = ?
  `);
    // Truncate message to 200 characters
    const truncatedMessage = message.substring(0, 200);
    stmt.run(truncatedMessage, timestamp.getTime(), worktreeId);
}
/**
 * Get message by ID
 */
function getMessageById(db, messageId) {
    const stmt = db.prepare(`
    SELECT id, worktree_id, role, content, summary, timestamp, log_file_name, request_id, message_type, prompt_data, cli_tool_id
    FROM chat_messages
    WHERE id = ?
  `);
    const row = stmt.get(messageId);
    if (!row) {
        return null;
    }
    return mapChatMessage(row);
}
/**
 * Update prompt data for a message
 */
function updatePromptData(db, messageId, promptData) {
    const stmt = db.prepare(`
    UPDATE chat_messages
    SET prompt_data = ?
    WHERE id = ?
  `);
    stmt.run(JSON.stringify(promptData), messageId);
}
/**
 * Mark all pending prompts as answered for a worktree/CLI tool
 * This is called when we detect Claude has started processing (new response detected)
 * which means any pending prompts must have been answered via terminal
 */
function markPendingPromptsAsAnswered(db, worktreeId, cliToolId) {
    // Find all pending prompt messages for this worktree/CLI tool
    const selectStmt = db.prepare(`
    SELECT id, prompt_data
    FROM chat_messages
    WHERE worktree_id = ?
      AND cli_tool_id = ?
      AND message_type = 'prompt'
      AND json_extract(prompt_data, '$.status') = 'pending'
    ORDER BY timestamp DESC
  `);
    const rows = selectStmt.all(worktreeId, cliToolId);
    if (rows.length === 0) {
        return 0;
    }
    // Update each pending prompt to answered
    const updateStmt = db.prepare(`
    UPDATE chat_messages
    SET prompt_data = ?
    WHERE id = ?
  `);
    let updatedCount = 0;
    for (const row of rows) {
        try {
            const promptData = JSON.parse(row.prompt_data);
            promptData.status = 'answered';
            promptData.answer = '(answered via terminal)';
            promptData.answeredAt = new Date().toISOString();
            updateStmt.run(JSON.stringify(promptData), row.id);
            updatedCount++;
        }
        catch {
            // Skip if prompt_data is invalid JSON
        }
    }
    return updatedCount;
}
/**
 * Update favorite status for a worktree
 */
function updateFavorite(db, id, favorite) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET favorite = ?
    WHERE id = ?
  `);
    stmt.run(favorite ? 1 : 0, id);
}
/**
 * Update status for a worktree
 */
function updateStatus(db, id, status) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET status = ?
    WHERE id = ?
  `);
    stmt.run(status, id);
}
/**
 * Update CLI tool ID for a worktree
 */
function updateCliToolId(db, id, cliToolId) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET cli_tool_id = ?
    WHERE id = ?
  `);
    stmt.run(cliToolId, id);
}
/**
 * Map database row to WorktreeMemo model
 */
function mapMemoRow(row) {
    return {
        id: row.id,
        worktreeId: row.worktree_id,
        title: row.title,
        content: row.content,
        position: row.position,
        createdAt: new Date(row.created_at),
        updatedAt: new Date(row.updated_at),
    };
}
/**
 * Get all memos for a worktree, sorted by position
 */
function getMemosByWorktreeId(db, worktreeId) {
    const stmt = db.prepare(`
    SELECT id, worktree_id, title, content, position, created_at, updated_at
    FROM worktree_memos
    WHERE worktree_id = ?
    ORDER BY position ASC
  `);
    const rows = stmt.all(worktreeId);
    return rows.map(mapMemoRow);
}
/**
 * Get a memo by ID
 *
 * @param db - Database instance
 * @param memoId - ID of the memo
 * @returns Memo or null if not found
 */
function getMemoById(db, memoId) {
    const stmt = db.prepare(`
    SELECT id, worktree_id, title, content, position, created_at, updated_at
    FROM worktree_memos
    WHERE id = ?
  `);
    const row = stmt.get(memoId);
    return row ? mapMemoRow(row) : null;
}
/**
 * Create a new memo for a worktree
 *
 * @param db - Database instance
 * @param worktreeId - ID of the worktree
 * @param options - Memo options (title, content, position)
 * @returns Created memo
 */
function createMemo(db, worktreeId, options) {
    const id = (0, crypto_1.randomUUID)();
    const now = Date.now();
    const title = options.title ?? 'Memo';
    const content = options.content ?? '';
    const stmt = db.prepare(`
    INSERT INTO worktree_memos (id, worktree_id, title, content, position, created_at, updated_at)
    VALUES (?, ?, ?, ?, ?, ?, ?)
  `);
    stmt.run(id, worktreeId, title, content, options.position, now, now);
    return {
        id,
        worktreeId,
        title,
        content,
        position: options.position,
        createdAt: new Date(now),
        updatedAt: new Date(now),
    };
}
/**
 * Update an existing memo
 *
 * @param db - Database instance
 * @param memoId - ID of the memo to update
 * @param updates - Fields to update (title and/or content)
 */
function updateMemo(db, memoId, updates) {
    const now = Date.now();
    const assignments = ['updated_at = ?'];
    const params = [now];
    if (updates.title !== undefined) {
        assignments.push('title = ?');
        params.push(updates.title);
    }
    if (updates.content !== undefined) {
        assignments.push('content = ?');
        params.push(updates.content);
    }
    params.push(memoId);
    const stmt = db.prepare(`
    UPDATE worktree_memos
    SET ${assignments.join(', ')}
    WHERE id = ?
  `);
    stmt.run(...params);
}
/**
 * Delete a memo by ID
 *
 * @param db - Database instance
 * @param memoId - ID of the memo to delete
 */
function deleteMemo(db, memoId) {
    const stmt = db.prepare(`
    DELETE FROM worktree_memos
    WHERE id = ?
  `);
    stmt.run(memoId);
}
/**
 * Reorder memos for a worktree
 *
 * Uses a two-step approach to handle UNIQUE constraint on (worktree_id, position):
 * 1. Set all positions to negative values (temporary)
 * 2. Set new positions from the provided order
 *
 * @param db - Database instance
 * @param worktreeId - ID of the worktree
 * @param memoIds - Array of memo IDs in the desired order
 */
function reorderMemos(db, worktreeId, memoIds) {
    if (memoIds.length === 0) {
        return;
    }
    const now = Date.now();
    db.transaction(() => {
        // Step 1: Set all positions to negative values (to avoid UNIQUE constraint violations)
        const resetStmt = db.prepare(`
      UPDATE worktree_memos
      SET position = -1 - position
      WHERE id = ?
    `);
        for (const memoId of memoIds) {
            resetStmt.run(memoId);
        }
        // Step 2: Set new positions based on array order
        const updateStmt = db.prepare(`
      UPDATE worktree_memos
      SET position = ?, updated_at = ?
      WHERE id = ?
    `);
        memoIds.forEach((memoId, index) => {
            updateStmt.run(index, now, memoId);
        });
    })();
}
// ============================================================
// Initial Branch Operations (Issue #111)
// ============================================================
/**
 * Save initial branch for a worktree (at session start)
 * Issue #111: Branch visualization feature
 *
 * @param db - Database instance
 * @param worktreeId - ID of the worktree
 * @param branchName - Branch name to save
 *
 * @remarks
 * Uses prepared statement for SQL injection prevention
 * Called from send/route.ts after startSession()
 */
function saveInitialBranch(db, worktreeId, branchName) {
    const stmt = db.prepare(`
    UPDATE worktrees
    SET initial_branch = ?
    WHERE id = ?
  `);
    stmt.run(branchName, worktreeId);
}
/**
 * Get initial branch for a worktree
 * Issue #111: Branch visualization feature
 *
 * @param db - Database instance
 * @param worktreeId - ID of the worktree
 * @returns Branch name or null if not recorded
 */
function getInitialBranch(db, worktreeId) {
    const stmt = db.prepare(`
    SELECT initial_branch
    FROM worktrees
    WHERE id = ?
  `);
    const row = stmt.get(worktreeId);
    return row?.initial_branch ?? null;
}
// ============================================================
// Repository Delete Operations (Issue #69)
// ============================================================
/**
 * Get all worktree IDs for a given repository path
 *
 * @param db - Database instance
 * @param repositoryPath - Path of the repository
 * @returns Array of worktree IDs
 */
function getWorktreeIdsByRepository(db, repositoryPath) {
    const stmt = db.prepare(`
    SELECT id FROM worktrees WHERE repository_path = ?
  `);
    const rows = stmt.all(repositoryPath);
    return rows.map(r => r.id);
}
/**
 * Delete all worktrees for a given repository path
 * Related data (chat_messages, session_states, worktree_memos) will be
 * automatically deleted via CASCADE foreign key constraints.
 *
 * @param db - Database instance
 * @param repositoryPath - Path of the repository to delete
 * @returns Object containing the count of deleted worktrees
 */
function deleteRepositoryWorktrees(db, repositoryPath) {
    const stmt = db.prepare(`
    DELETE FROM worktrees WHERE repository_path = ?
  `);
    const result = stmt.run(repositoryPath);
    return { deletedCount: result.changes };
}
/**
 * Delete worktrees by their IDs
 * Related data (chat_messages, session_states, worktree_memos) will be
 * automatically deleted via CASCADE foreign key constraints.
 *
 * @param db - Database instance
 * @param worktreeIds - Array of worktree IDs to delete
 * @returns Object containing the count of deleted worktrees
 */
function deleteWorktreesByIds(db, worktreeIds) {
    if (worktreeIds.length === 0) {
        return { deletedCount: 0 };
    }
    const placeholders = worktreeIds.map(() => '?').join(',');
    const stmt = db.prepare(`
    DELETE FROM worktrees WHERE id IN (${placeholders})
  `);
    const result = stmt.run(...worktreeIds);
    return { deletedCount: result.changes };
}
