/**
 * Step Executor: db_query
 * Run a parameterized read-only SQL query against local Postgres.
 * Useful for trend analysis, history lookups, aggregations.
 *
 * Config:
 *   query: SQL string with $1, $2 etc. placeholders
 *   params: array of template strings for parameter values
 *   output_key: context key to store results (default: 'query_result')
 *   single_row: if true, store only first row instead of array
 *
 * Security: Only SELECT statements allowed. No mutations.
 */

import { registerStepExecutor } from '../pipeline-engine';
import { postgresClient } from '../postgres-client';
import { StepExecutorResult, PipelineStep, PipelineContext } from '../../types/pipeline';

const FORBIDDEN_KEYWORDS = [
  'INSERT', 'UPDATE', 'DELETE', 'DROP', 'ALTER', 'CREATE', 'TRUNCATE',
  'GRANT', 'REVOKE', 'COPY', 'EXECUTE', 'CALL',
];

registerStepExecutor('db_query', async (
  step: PipelineStep,
  context: PipelineContext,
  executionId: number
): Promise<StepExecutorResult> => {
  const config = step.config as {
    query?: string;
    params?: string[];
    output_key?: string;
    single_row?: boolean;
  };

  const query = config.query || '';
  const params = config.params || [];
  const outputKey = config.output_key || 'query_result';
  const singleRow = config.single_row ?? false;

  if (!query) {
    return { success: false, output: {}, error: 'query is required' };
  }

  // Security: block mutations
  const upperQuery = query.toUpperCase().replace(/\s+/g, ' ');
  for (const keyword of FORBIDDEN_KEYWORDS) {
    // Check for keyword as a standalone word (not inside a string literal)
    const regex = new RegExp(`\\b${keyword}\\b`);
    if (regex.test(upperQuery)) {
      return {
        success: false,
        output: {},
        error: `Forbidden SQL keyword: ${keyword}. Only SELECT queries are allowed.`,
      };
    }
  }

  try {
    const result = await postgresClient.query(query, params);

    const rows = result.rows;
    const value = singleRow ? (rows[0] || null) : rows;

    return {
      success: true,
      output: {
        [outputKey]: value,
        [`${outputKey}_count`]: rows.length,
      },
    };
  } catch (error) {
    const msg = error instanceof Error ? error.message : String(error);
    return { success: false, output: { [outputKey]: null }, error: `DB query failed: ${msg}` };
  }
});
