import { Pool } from 'pg';
import { config } from '../config';

const pool = new Pool({ connectionString: config.database.url });

export interface DbExecuteInput {
  operation: 'insert' | 'update' | 'delete' | 'raw';
  table?: string;
  data?: Record<string, any>;
  where?: string;
  rawSql?: string;
  params?: any[];
  datasource?: string;
  timeout?: number;
}

export interface DbExecuteOutput {
  affectedRows: number;
  insertedId?: string;
}

/**
 * Execute a database write operation (INSERT/UPDATE/DELETE).
 */
export async function dbExecute(input: DbExecuteInput): Promise<DbExecuteOutput> {
  const client = await pool.connect();
  try {
    if (input.timeout) {
      await client.query(`SET statement_timeout = ${input.timeout}`);
    }

    let query: string;
    let params: any[] = [];

    switch (input.operation) {
      case 'raw':
        query = input.rawSql || '';
        params = input.params || [];
        break;

      case 'insert': {
        if (!input.table || !input.data) throw new Error('table and data required for insert');
        const keys = Object.keys(input.data);
        const values = Object.values(input.data);
        const placeholders = keys.map((_, i) => `$${i + 1}`);
        query = `INSERT INTO ${input.table} (${keys.join(', ')}) VALUES (${placeholders.join(', ')}) RETURNING id`;
        params = values;
        break;
      }

      case 'update': {
        if (!input.table || !input.data) throw new Error('table and data required for update');
        const entries = Object.entries(input.data);
        const sets = entries.map(([k], i) => `${k} = $${i + 1}`);
        params = entries.map(([, v]) => v);
        query = `UPDATE ${input.table} SET ${sets.join(', ')}`;
        if (input.where) {
          query += ` WHERE ${input.where}`;
        }
        break;
      }

      case 'delete': {
        if (!input.table) throw new Error('table required for delete');
        query = `DELETE FROM ${input.table}`;
        if (input.where) {
          query += ` WHERE ${input.where}`;
        }
        params = input.params || [];
        break;
      }

      default:
        throw new Error(`Unknown operation: ${input.operation}`);
    }

    const result = await client.query(query, params);
    return {
      affectedRows: result.rowCount || 0,
      insertedId: result.rows?.[0]?.id?.toString(),
    };
  } finally {
    client.release();
  }
}
