import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { Pool } from "pg";
import { logger } from "../monitoring/logger.js";
class PostgresAdapter {
  pool;
  config;
  isInitialized = false;
  constructor(config) {
    this.config = {
      ...config,
      vectorDimensions: config.vectorDimensions || 1536
      // OpenAI ada-002 dimensions
    };
    this.pool = new Pool(this.config);
  }
  async connect() {
    try {
      await this.pool.connect();
      await this.initialize();
      this.isInitialized = true;
      logger.info("PostgreSQL connected successfully");
    } catch (error) {
      logger.error(
        "Failed to connect to PostgreSQL",
        error instanceof Error ? error : void 0
      );
      throw error;
    }
  }
  async disconnect() {
    await this.pool.end();
    this.isInitialized = false;
    logger.info("PostgreSQL disconnected");
  }
  async execute(query, params) {
    try {
      const result = await this.pool.query(query, params);
      return {
        rows: result.rows,
        rowCount: result.rowCount || 0,
        fields: result.fields?.map((f) => ({
          name: f.name,
          type: f.dataTypeID.toString()
        }))
      };
    } catch (error) {
      logger.error(
        "Query execution failed",
        error instanceof Error ? error : new Error(String(error)),
        { query }
      );
      throw error;
    }
  }
  async beginTransaction() {
    await this.execute("BEGIN");
  }
  async commit() {
    await this.execute("COMMIT");
  }
  async rollback() {
    await this.execute("ROLLBACK");
  }
  isConnected() {
    return this.isInitialized;
  }
  async initialize() {
    await this.createBaseSchema();
    if (this.config.enableTimescale) {
      await this.enableTimescale();
    }
    if (this.config.enablePgvector) {
      await this.enablePgvector();
    }
  }
  async createBaseSchema() {
    const queries = [
      // Projects table
      `CREATE TABLE IF NOT EXISTS projects (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        name VARCHAR(255) NOT NULL,
        path TEXT NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        metadata JSONB
      )`,
      // Sessions table
      `CREATE TABLE IF NOT EXISTS sessions (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
        branch VARCHAR(255),
        started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        ended_at TIMESTAMP,
        metadata JSONB
      )`,
      // Traces table
      `CREATE TABLE IF NOT EXISTS traces (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        session_id UUID REFERENCES sessions(id) ON DELETE CASCADE,
        timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        type VARCHAR(100) NOT NULL,
        data JSONB NOT NULL,
        metadata JSONB
      )`,
      // Context frames table
      `CREATE TABLE IF NOT EXISTS context_frames (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
        branch VARCHAR(255),
        content TEXT NOT NULL,
        summary TEXT,
        timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        type VARCHAR(100) NOT NULL,
        metadata JSONB
      )`,
      // Decisions table
      `CREATE TABLE IF NOT EXISTS decisions (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
        session_id UUID REFERENCES sessions(id) ON DELETE CASCADE,
        decision TEXT NOT NULL,
        rationale TEXT,
        timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        metadata JSONB
      )`
    ];
    for (const query of queries) {
      await this.execute(query);
    }
    const indexes = [
      `CREATE INDEX IF NOT EXISTS idx_traces_session_timestamp 
       ON traces(session_id, timestamp)`,
      `CREATE INDEX IF NOT EXISTS idx_context_project_branch 
       ON context_frames(project_id, branch)`,
      `CREATE INDEX IF NOT EXISTS idx_traces_type 
       ON traces(type)`,
      `CREATE INDEX IF NOT EXISTS idx_context_frames_timestamp 
       ON context_frames(timestamp)`,
      `CREATE INDEX IF NOT EXISTS idx_decisions_project_session 
       ON decisions(project_id, session_id)`
    ];
    for (const index of indexes) {
      await this.execute(index);
    }
  }
  async enableTimescale() {
    try {
      await this.execute("CREATE EXTENSION IF NOT EXISTS timescaledb");
      await this.execute(`
        SELECT create_hypertable('traces', 'timestamp',
          if_not_exists => TRUE,
          chunk_time_interval => INTERVAL '1 day'
        )
      `);
      await this.execute(`
        SELECT create_hypertable('context_frames', 'timestamp',
          if_not_exists => TRUE,
          chunk_time_interval => INTERVAL '7 days'
        )
      `);
      logger.info("TimescaleDB extension enabled");
    } catch (error) {
      logger.warn(
        "Failed to enable TimescaleDB",
        error instanceof Error ? error : void 0
      );
    }
  }
  async enablePgvector() {
    try {
      await this.execute("CREATE EXTENSION IF NOT EXISTS vector");
      await this.execute(`
        ALTER TABLE context_frames 
        ADD COLUMN IF NOT EXISTS embedding vector(${this.config.vectorDimensions})
      `);
      await this.execute(`
        ALTER TABLE traces 
        ADD COLUMN IF NOT EXISTS embedding vector(${this.config.vectorDimensions})
      `);
      await this.execute(`
        CREATE INDEX IF NOT EXISTS idx_context_embedding 
        ON context_frames 
        USING ivfflat (embedding vector_cosine_ops)
        WITH (lists = 100)
      `);
      logger.info("pgvector extension enabled");
    } catch (error) {
      logger.warn(
        "Failed to enable pgvector",
        error instanceof Error ? error : void 0
      );
    }
  }
  // Data access methods
  async saveTrace(trace) {
    await this.execute(
      `INSERT INTO traces (id, session_id, timestamp, type, data, metadata)
       VALUES ($1, $2, $3, $4, $5, $6)`,
      [
        trace.id,
        trace.sessionId,
        trace.timestamp,
        trace.type,
        JSON.stringify(trace.data),
        trace.metadata ? JSON.stringify(trace.metadata) : null
      ]
    );
  }
  async saveContext(context) {
    await this.execute(
      `INSERT INTO context_frames (id, project_id, branch, content, timestamp, type, metadata)
       VALUES ($1, $2, $3, $4, $5, $6, $7)`,
      [
        context.id,
        context.projectId,
        context.branch || null,
        context.content,
        context.timestamp,
        context.type,
        context.metadata ? JSON.stringify(context.metadata) : null
      ]
    );
  }
  async getRecentTraces(sessionId, limit = 100) {
    const result = await this.execute(
      `SELECT * FROM traces 
       WHERE session_id = $1 
       ORDER BY timestamp DESC 
       LIMIT $2`,
      [sessionId, limit]
    );
    return result.rows.map((row) => ({
      id: row.id,
      sessionId: row.session_id,
      timestamp: row.timestamp,
      type: row.type,
      data: row.data,
      metadata: row.metadata
    }));
  }
  async getRecentContext(projectId, branch, limit = 50) {
    const query = branch ? `SELECT * FROM context_frames 
         WHERE project_id = $1 AND branch = $2 
         ORDER BY timestamp DESC 
         LIMIT $3` : `SELECT * FROM context_frames 
         WHERE project_id = $1 
         ORDER BY timestamp DESC 
         LIMIT $2`;
    const params = branch ? [projectId, branch, limit] : [projectId, limit];
    const result = await this.execute(query, params);
    return result.rows.map((row) => ({
      id: row.id,
      projectId: row.project_id,
      branch: row.branch,
      content: row.content,
      timestamp: row.timestamp,
      type: row.type,
      metadata: row.metadata
    }));
  }
  // Hybrid SQLite/PostgreSQL migration helper
  async migrateFromSQLite(sqliteDb) {
    logger.info("Starting migration from SQLite to PostgreSQL");
    try {
      await this.beginTransaction();
      const projects = sqliteDb.prepare("SELECT * FROM projects").all();
      for (const project of projects) {
        await this.execute(
          "INSERT INTO projects (id, name, path, created_at, updated_at, metadata) VALUES ($1, $2, $3, $4, $5, $6)",
          [
            project.id,
            project.name,
            project.path,
            project.created_at,
            project.updated_at,
            project.metadata
          ]
        );
      }
      const sessions = sqliteDb.prepare("SELECT * FROM sessions").all();
      for (const session of sessions) {
        await this.execute(
          "INSERT INTO sessions (id, project_id, branch, started_at, ended_at, metadata) VALUES ($1, $2, $3, $4, $5, $6)",
          [
            session.id,
            session.project_id,
            session.branch,
            session.started_at,
            session.ended_at,
            session.metadata
          ]
        );
      }
      const traceCount = sqliteDb.prepare("SELECT COUNT(*) as count FROM traces").get();
      const batchSize = 1e3;
      for (let offset = 0; offset < traceCount.count; offset += batchSize) {
        const traces = sqliteDb.prepare("SELECT * FROM traces LIMIT ? OFFSET ?").all(batchSize, offset);
        for (const trace of traces) {
          await this.execute(
            "INSERT INTO traces (id, session_id, timestamp, type, data, metadata) VALUES ($1, $2, $3, $4, $5, $6)",
            [
              trace.id,
              trace.session_id,
              trace.timestamp,
              trace.type,
              trace.data,
              trace.metadata
            ]
          );
        }
        logger.info(
          `Migrated ${offset + traces.length}/${traceCount.count} traces`
        );
      }
      const contexts = sqliteDb.prepare("SELECT * FROM context_frames").all();
      for (const context of contexts) {
        await this.execute(
          "INSERT INTO context_frames (id, project_id, branch, content, summary, timestamp, type, metadata) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
          [
            context.id,
            context.project_id,
            context.branch,
            context.content,
            context.summary,
            context.timestamp,
            context.type,
            context.metadata
          ]
        );
      }
      await this.commit();
      logger.info("Migration completed successfully");
    } catch (error) {
      await this.rollback();
      logger.error(
        "Migration failed",
        error instanceof Error ? error : void 0
      );
      throw error;
    }
  }
}
export {
  PostgresAdapter
};
//# sourceMappingURL=postgres-adapter.js.map
