/**
 * SQLite Interactive Session Repository Implementation
 *
 * Implements IInteractiveSessionRepository using SQLite database.
 * Uses prepared statements to prevent SQL injection.
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { injectable } from 'tsyringe';
import { toDatabase, fromDatabase, } from '../persistence/sqlite/mappers/interactive-session.mapper.js';
let SQLiteInteractiveSessionRepository = class SQLiteInteractiveSessionRepository {
    db;
    constructor(db) {
        this.db = db;
    }
    async create(session) {
        const row = toDatabase(session);
        this.db
            .prepare(`INSERT INTO interactive_sessions
          (id, feature_id, status, started_at, stopped_at, last_activity_at, created_at, updated_at)
         VALUES
          (@id, @feature_id, @status, @started_at, @stopped_at, @last_activity_at, @created_at, @updated_at)`)
            .run(row);
    }
    async findById(id) {
        const row = this.db.prepare('SELECT * FROM interactive_sessions WHERE id = ?').get(id);
        return row ? fromDatabase(row) : null;
    }
    async findByFeatureId(featureId) {
        const row = this.db
            .prepare('SELECT * FROM interactive_sessions WHERE feature_id = ? ORDER BY created_at DESC LIMIT 1')
            .get(featureId);
        return row ? fromDatabase(row) : null;
    }
    async findAllActive() {
        const rows = this.db
            .prepare(`SELECT * FROM interactive_sessions WHERE status IN ('booting','ready')`)
            .all();
        return rows.map(fromDatabase);
    }
    async updateStatus(id, status, stoppedAt) {
        this.db
            .prepare(`UPDATE interactive_sessions
         SET status = @status, stopped_at = @stopped_at, updated_at = @updated_at
         WHERE id = @id`)
            .run({
            id,
            status,
            stopped_at: stoppedAt ? stoppedAt.getTime() : null,
            updated_at: Date.now(),
        });
    }
    async updateLastActivity(id, lastActivityAt) {
        this.db
            .prepare(`UPDATE interactive_sessions
         SET last_activity_at = @last_activity_at, updated_at = @updated_at
         WHERE id = @id`)
            .run({ id, last_activity_at: lastActivityAt.getTime(), updated_at: Date.now() });
    }
    async markAllActiveStopped() {
        this.db
            .prepare(`UPDATE interactive_sessions
         SET status = 'stopped', updated_at = ?
         WHERE status IN ('booting','ready')`)
            .run(Date.now());
    }
    async countActiveSessions() {
        const result = this.db
            .prepare(`SELECT COUNT(*) as count FROM interactive_sessions WHERE status IN ('booting','ready')`)
            .get();
        return result.count;
    }
    async updateAgentSessionId(id, agentSessionId) {
        this.db
            .prepare(`UPDATE interactive_sessions SET agent_session_id = @agent_session_id, updated_at = @updated_at WHERE id = @id`)
            .run({ id, agent_session_id: agentSessionId, updated_at: Date.now() });
    }
    async getAgentSessionId(id) {
        const row = this.db
            .prepare('SELECT agent_session_id FROM interactive_sessions WHERE id = ?')
            .get(id);
        return row?.agent_session_id ?? null;
    }
    async findLatestAgentSessionIdForFeature(featureId) {
        // Return the most recent NON-NULL agent_session_id for this feature
        // across ALL session rows, regardless of status. Ordering by
        // created_at DESC ensures we pick up the latest successful boot
        // even if an intervening session failed to capture an
        // agentSessionId.
        const row = this.db
            .prepare(`SELECT agent_session_id
         FROM interactive_sessions
         WHERE feature_id = ?
           AND agent_session_id IS NOT NULL
         ORDER BY created_at DESC
         LIMIT 1`)
            .get(featureId);
        return row?.agent_session_id ?? null;
    }
    async updateTurnStatus(id, turnStatus) {
        this.db
            .prepare(`UPDATE interactive_sessions SET turn_status = @turn_status, updated_at = @updated_at WHERE id = @id`)
            .run({ id, turn_status: turnStatus, updated_at: Date.now() });
    }
    async getTurnStatuses(featureIds) {
        const result = new Map();
        if (featureIds.length === 0)
            return result;
        // Use a single query with placeholders for all feature IDs.
        // For each feature, get the most recent session's turn_status.
        const placeholders = featureIds.map(() => '?').join(',');
        const rows = this.db
            .prepare(`SELECT feature_id, turn_status FROM interactive_sessions
         WHERE feature_id IN (${placeholders})
           AND status IN ('booting','ready')
         ORDER BY created_at DESC`)
            .all(...featureIds);
        // First row per feature wins (most recent due to ORDER BY)
        for (const row of rows) {
            if (!result.has(row.feature_id)) {
                result.set(row.feature_id, row.turn_status);
            }
        }
        return result;
    }
    async getAllActiveTurnStatuses() {
        const result = new Map();
        const rows = this.db
            .prepare(`SELECT feature_id, turn_status FROM interactive_sessions
         WHERE status IN ('booting','ready')
           AND turn_status != 'idle'
         ORDER BY created_at DESC`)
            .all();
        for (const row of rows) {
            if (!result.has(row.feature_id)) {
                result.set(row.feature_id, row.turn_status);
            }
        }
        return result;
    }
    async accumulateUsage(id, usage) {
        this.db
            .prepare(`UPDATE interactive_sessions SET
           total_cost_usd = total_cost_usd + @cost_usd,
           total_input_tokens = total_input_tokens + @input_tokens,
           total_output_tokens = total_output_tokens + @output_tokens,
           total_turns = total_turns + @turns,
           updated_at = @updated_at
         WHERE id = @id`)
            .run({
            id,
            cost_usd: usage.costUsd,
            input_tokens: usage.inputTokens,
            output_tokens: usage.outputTokens,
            turns: usage.turns,
            updated_at: Date.now(),
        });
    }
    async getUsage(id) {
        const row = this.db
            .prepare('SELECT total_cost_usd, total_input_tokens, total_output_tokens, total_turns FROM interactive_sessions WHERE id = ?')
            .get(id);
        if (!row)
            return null;
        return {
            totalCostUsd: row.total_cost_usd,
            totalInputTokens: row.total_input_tokens,
            totalOutputTokens: row.total_output_tokens,
            totalTurns: row.total_turns,
        };
    }
};
SQLiteInteractiveSessionRepository = __decorate([
    injectable(),
    __metadata("design:paramtypes", [Object])
], SQLiteInteractiveSessionRepository);
export { SQLiteInteractiveSessionRepository };
