const fs = require('fs');
const path = require('path');
const ConfigReader = require('../config/config-reader');
const FileUtils = require('./file-utils');

/**
 * Processor untuk transformasi dan processing payload
 */
class PayloadProcessor {

  /**
   * Process payload dengan semua transformasi yang diperlukan
   * @param {Object} payload - Raw payload object
   * @param {string} payloadPath - Path file payload
   * @param {Object} options - Processing options
   * @returns {Object} Processed payload
   */
  static processPayload(payload, payloadPath, options = {}) {
    console.log('Processing payload...');
    
    // Clone payload untuk avoid mutation
    let processedPayload = JSON.parse(JSON.stringify(payload));
    
    // Apply transformations
    processedPayload = this.processFileReferences(processedPayload, payloadPath, options);
    processedPayload = this.processFieldNames(processedPayload, options);
    processedPayload = this.processQueries(processedPayload, options);
    processedPayload = this.processActions(processedPayload, options);
    processedPayload = this.addMetadata(processedPayload, options);
    
    console.log('Payload processing completed');
    return processedPayload;
  }

  /**
   * Process file references dalam payload (untuk Node.js mode)
   * @param {Object} payload - Payload object
   * @param {string} payloadPath - Path file payload
   * @param {Object} options - Processing options
   * @returns {Object} Payload dengan file references yang sudah diproses
   */
  static processFileReferences(payload, payloadPath, options = {}) {
    const isPkg = ConfigReader.isPkg;

    if (isPkg) {
      console.log('Compiled binary mode: Skipping file reference processing (files assumed bundled)');
      return payload;
    }

    console.log('Processing file references in Node.js mode...');
    
    const payloadDir = path.dirname(payloadPath);
    const processedPayload = { ...payload };
    
    // Process datatablesQuery
    if (processedPayload.datatablesQuery && this.isFileReference(processedPayload.datatablesQuery)) {
      processedPayload.datatablesQuery = this.loadSqlFile(
        processedPayload.datatablesQuery,
        payloadDir,
        'datatablesQuery',
        options
      );
    }

    // Process viewQuery
    if (processedPayload.viewQuery && this.isFileReference(processedPayload.viewQuery)) {
      processedPayload.viewQuery = this.loadSqlFile(
        processedPayload.viewQuery,
        payloadDir,
        'viewQuery',
        options
      );
    }

    // Process masterDetail.detailConfig.detailQuery (digunakan oleh readComposite)
    if (
      processedPayload.masterDetail &&
      processedPayload.masterDetail.detailConfig &&
      this.isFileReference(processedPayload.masterDetail.detailConfig.detailQuery)
    ) {
      processedPayload.masterDetail = {
        ...processedPayload.masterDetail,
        detailConfig: {
          ...processedPayload.masterDetail.detailConfig,
          detailQuery: this.loadSqlFile(
            processedPayload.masterDetail.detailConfig.detailQuery,
            payloadDir,
            'masterDetail.detailConfig.detailQuery',
            options
          )
        }
      };
    }

    // Process advancedQueries
    if (processedPayload.advancedQueries && typeof processedPayload.advancedQueries === 'object') {
      processedPayload.advancedQueries = this.processAdvancedQueries(
        processedPayload.advancedQueries, 
        payloadDir
      );
    }

    // Process nestedQueries
    if (processedPayload.nestedQueries && Array.isArray(processedPayload.nestedQueries)) {
      processedPayload.nestedQueries = this.processNestedQueries(
        processedPayload.nestedQueries, 
        payloadDir
      );
    }

    // Process customQueries (extension untuk future use)
    if (processedPayload.customQueries && typeof processedPayload.customQueries === 'object') {
      processedPayload.customQueries = this.processCustomQueries(
        processedPayload.customQueries,
        payloadDir
      );
    }

    return processedPayload;
  }

  /**
   * Check apakah string adalah file reference
   * @param {string} value - String value
   * @returns {boolean} True jika file reference
   */
  static isFileReference(value) {
    return typeof value === 'string' && value.startsWith('file:');
  }

  /**
   * Load SQL file dari file reference
   * @param {string} fileReference - File reference (format: file:path.sql atau file:path.json)
   * @param {string} baseDir - Base directory
   * @param {string} context - Context untuk error message
   * @param {Object} options - Processing options
   * @returns {string} SQL content
   */
  static loadSqlFile(fileReference, baseDir, context, options = {}) {
    try {
      const relativePath = fileReference.substring(5); // remove 'file:'
      const fullPath = path.join(baseDir, relativePath);
      
      console.log(`Loading file for ${context}: ${relativePath}`);
      
      if (!fs.existsSync(fullPath)) {
        throw new Error(`File not found: ${fullPath}`);
      }

      const fileContent = FileUtils.readFileWithErrorHandling(fullPath);
      
      if (!fileContent || fileContent.trim().length === 0) {
        throw new Error(`File is empty: ${fullPath}`);
      }

      // If it's a JSON file, check if it contains SQL query
      if (relativePath.toLowerCase().endsWith('.json')) {
        try {
          // First try to parse as JSON
          const jsonContent = JSON.parse(fileContent);
          
          // If JSON contains a string (like SQL query), return it as string
          if (typeof jsonContent === 'string') {
            this.validateSqlContent(jsonContent, relativePath, options.skipSqlValidation);
            console.log(`JSON file with SQL query loaded: ${relativePath} (${jsonContent.length} chars)`);
            return jsonContent;
          } else {
            throw new Error(`JSON file ${relativePath} does not contain a string value`);
          }
        } catch (parseError) {
          // If it's not valid JSON, maybe it's a plain SQL file with .json extension
          // Treat it as regular SQL content
          console.log(`File ${relativePath} has .json extension but contains plain text, treating as SQL`);
          this.validateSqlContent(fileContent, relativePath, options.skipSqlValidation);
          console.log(`File loaded as SQL: ${relativePath} (${fileContent.length} chars)`);
          return fileContent;
        }
      } else {
        // Regular SQL file processing
        this.validateSqlContent(fileContent, relativePath, options.skipSqlValidation);
        console.log(`SQL file loaded: ${relativePath} (${fileContent.length} chars)`);
        return fileContent;
      }
    } catch (error) {
      throw new Error(`Failed to load file for ${context}: ${error.message}`);
    }
  }

  /**
   * Validate SQL content untuk basic security dan syntax
   * @param {string} sqlContent - SQL content
   * @param {string} fileName - File name untuk error message
   * @param {boolean} skipSqlValidation - Skip validasi SQL keywords (default: false)
   */
  static validateSqlContent(sqlContent, fileName, skipSqlValidation = false) {
    const trimmedSql = sqlContent.trim().toLowerCase();
    
    // Skip validasi jika skipSqlValidation = true
    if (skipSqlValidation) {
      console.log(`SQL validation skipped for file: ${fileName}`);
      return;
    }
    
    // Check for dangerous SQL keywords - hanya validasi statement lengkap yang berbahaya
    const dangerousPatterns = [
      /\bdrop\s+table\b/i,
      /\bdrop\s+database\b/i,
      /\btruncate\s+table\b/i,
      /\bdelete\s+from\b/i,
      /\binsert\s+into\b/i,
      /\bupdate\s+\w+\s+set\b/i,
      /\balter\s+table\b/i,
      /\bcreate\s+table\b/i,
      /\bcreate\s+database\b/i,
      /\bgrant\s+all\b/i,
      /\brevoke\s+all\b/i,
      /\bexec\s+/i,
      /\bexecute\s+/i
    ];
    
    for (const pattern of dangerousPatterns) {
      if (pattern.test(trimmedSql)) {
        console.warn(`Warning: SQL file ${fileName} contains potentially dangerous keyword: ${pattern.source}`);
      }
    }
    
    // Basic SQL validation
    if (!trimmedSql.startsWith('select') && !trimmedSql.startsWith('with')) {
      console.warn(`Warning: SQL file ${fileName} doesn't start with SELECT or WITH`);
    }
  }

  /**
   * Process advanced queries object
   * @param {Object} advancedQueries - Advanced queries object
   * @param {string} baseDir - Base directory
   * @returns {Object} Processed advanced queries
   */
  static processAdvancedQueries(advancedQueries, baseDir) {
    const processed = {};
    
    for (const [queryName, querySource] of Object.entries(advancedQueries)) {
      if (this.isFileReference(querySource)) {
        processed[queryName] = this.loadSqlFile(
          querySource, 
          baseDir, 
          `advancedQueries.${queryName}`
        );
      } else {
        processed[queryName] = querySource;
      }
    }
    
    return processed;
  }

  /**
   * Process nested queries array
   * @param {Array} nestedQueries - Nested queries array
   * @param {string} baseDir - Base directory
   * @returns {Array} Processed nested queries
   */
  static processNestedQueries(nestedQueries, baseDir) {
    return nestedQueries.map((nestedQuery, index) => {
      const processed = { ...nestedQuery };
      
      if (processed.query && this.isFileReference(processed.query)) {
        processed.query = this.loadSqlFile(
          processed.query, 
          baseDir, 
          `nestedQueries[${index}].query`
        );
      }
      
      return processed;
    });
  }

  /**
   * Process custom queries (extension untuk future functionality)
   * @param {Object} customQueries - Custom queries object
   * @param {string} baseDir - Base directory
   * @returns {Object} Processed custom queries
   */
  static processCustomQueries(customQueries, baseDir) {
    const processed = {};
    
    for (const [queryType, queries] of Object.entries(customQueries)) {
      if (Array.isArray(queries)) {
        processed[queryType] = queries.map(query => {
          if (typeof query === 'object' && query.query && this.isFileReference(query.query)) {
            return {
              ...query,
              query: this.loadSqlFile(query.query, baseDir, `customQueries.${queryType}`)
            };
          }
          return query;
        });
      } else if (typeof queries === 'object') {
        processed[queryType] = {};
        for (const [subQueryName, subQuery] of Object.entries(queries)) {
          if (this.isFileReference(subQuery)) {
            processed[queryType][subQueryName] = this.loadSqlFile(
              subQuery, 
              baseDir, 
              `customQueries.${queryType}.${subQueryName}`
            );
          } else {
            processed[queryType][subQueryName] = subQuery;
          }
        }
      } else {
        processed[queryType] = queries;
      }
    }
    
    return processed;
  }

  /**
   * Process dan normalize field names
   * @param {Object} payload - Payload object
   * @param {Object} options - Processing options
   * @returns {Object} Payload dengan field names yang sudah diproses
   */
  static processFieldNames(payload, options = {}) {
    if (!payload.fieldName || !Array.isArray(payload.fieldName)) {
      return payload;
    }
    
    const processedPayload = { ...payload };
    
    // Normalize field names (trim whitespace, lowercase untuk consistency checks)
    let normalizedFields = payload.fieldName.map(field => field.trim());
    
    // Remove duplicates (case insensitive)
    if (options.removeDuplicates !== false) {
      const seen = new Set();
      normalizedFields = normalizedFields.filter(field => {
        const lowerField = field.toLowerCase();
        if (seen.has(lowerField)) {
          console.warn(`Duplicate field removed: ${field}`);
          return false;
        }
        seen.add(lowerField);
        return true;
      });
    }
    
    // Add common fields jika belum ada dan diminta
    if (options.addCommonFields) {
      const commonFields = ['created_at', 'updated_at', 'created_by', 'updated_by'];
      const fieldNamesLower = normalizedFields.map(f => f.toLowerCase());
      
      for (const commonField of commonFields) {
        if (!fieldNamesLower.includes(commonField)) {
          normalizedFields.push(commonField);
          console.log(`➕ Added common field: ${commonField}`);
        }
      }
    }
    
    // Ensure primary key field exists dan di posisi pertama
    if (options.ensureIdField !== false) {
      // Gunakan primaryKey dari payload, fallback ke fieldName[0], atau 'id'
      const primaryKey = processedPayload.primaryKey || normalizedFields[0] || 'id';

      const hasPrimaryKey = normalizedFields.some(field => field.toLowerCase() === primaryKey.toLowerCase());
      if (!hasPrimaryKey) {
        normalizedFields.unshift(primaryKey);
        console.log(`➕ Added primary key field '${primaryKey}' at the beginning`);
      } else {
        // Move primary key to first position if not already
        const pkIndex = normalizedFields.findIndex(field => field.toLowerCase() === primaryKey.toLowerCase());
        if (pkIndex > 0) {
          const pkField = normalizedFields.splice(pkIndex, 1)[0];
          normalizedFields.unshift(pkField);
          console.log(`Moved primary key field '${primaryKey}' to first position`);
        }
      }
    }
    
    processedPayload.fieldName = normalizedFields;
    
    // Add extended fields untuk template generation
    processedPayload._extendedFields = this.generateExtendedFields(normalizedFields);
    
    // Process fieldNameLookup jika ada
    if (processedPayload.fieldNameLookup) {
      processedPayload._lookupConfig = this.processLookupConfig(processedPayload.fieldNameLookup);
    }
    
    return processedPayload;
  }

  /**
   * Generate extended fields untuk template usage
   * @param {Array} fieldNames - Field names array
   * @returns {Object} Extended fields information
   */
  static generateExtendedFields(fieldNames) {
    const extended = {
      all: fieldNames,
      nonId: fieldNames.filter(f => f.toLowerCase() !== 'id'),
      textFields: fieldNames.filter(f => this.isTextFieldCandidate(f)),
      dateFields: fieldNames.filter(f => this.isDateFieldCandidate(f)),
      primaryTextField: FileUtils.detectTextColumn(fieldNames),
      requiredFields: fieldNames.filter(f => this.isRequiredFieldCandidate(f))
    };
    
    return extended;
  }

  /**
   * Process fieldNameLookup configuration
   * @param {Object} lookupConfig - Lookup configuration object
   * @returns {Object} Processed lookup configuration
   */
  static processLookupConfig(lookupConfig) {
    const processed = {
      idField: lookupConfig.id || 'id',
      textField: lookupConfig.text || 'name',
      hasCustomText: false,
      searchFields: []
    };

    // Check jika text field adalah SQL expression
    if (processed.textField.includes('||') || processed.textField.toLowerCase().includes(' as ')) {
      processed.hasCustomText = true;
      
      // Extract field names dari SQL expression untuk search
      let expressionBeforeAs = processed.textField;
      
      // Split by 'as' dan ambil bagian sebelum 'as' untuk menghindari alias
      const asIndex = processed.textField.toLowerCase().indexOf(' as ');
      if (asIndex !== -1) {
        expressionBeforeAs = processed.textField.substring(0, asIndex);
      }
      
      const fieldMatches = expressionBeforeAs.match(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g);
      if (fieldMatches) {
        // Filter out SQL keywords dan ambil field names yang valid
        const sqlKeywords = ['as', 'and', 'or', 'case', 'when', 'then', 'else', 'end'];
        processed.searchFields = fieldMatches.filter(field => 
          !sqlKeywords.includes(field.toLowerCase()) && 
          field !== processed.idField
        );
      }
    } else {
      // Simple field name
      processed.searchFields = [processed.textField];
    }

    return processed;
  }

  /**
   * Check apakah field adalah kandidat text field
   * @param {string} fieldName - Field name
   * @returns {boolean} True jika kandidat text field
   */
  static isTextFieldCandidate(fieldName) {
    const textPatterns = [
      /name/i, /title/i, /text/i, /code/i, /label/i, /tag/i
    ];
    
    return textPatterns.some(pattern => pattern.test(fieldName));
  }

  /**
   * Check apakah field adalah kandidat date field
   * @param {string} fieldName - Field name
   * @returns {boolean} True jika kandidat date field
   */
  static isDateFieldCandidate(fieldName) {
    const datePatterns = [
      /date/i, /time/i, /created/i, /updated/i, /modified/i, 
      /deleted/i, /birth/i, /expire/i, /start/i, /end/i
    ];
    
    return datePatterns.some(pattern => pattern.test(fieldName));
  }

  /**
   * Check apakah field adalah kandidat required field
   * @param {string} fieldName - Field name
   * @returns {boolean} True jika kandidat required field
   */
  static isRequiredFieldCandidate(fieldName) {
    const requiredPatterns = [
      /^id$/i, /name$/i, /title$/i, /code$/i, /email$/i, /username$/i
    ];
    
    return requiredPatterns.some(pattern => pattern.test(fieldName));
  }

  /**
   * Process dan normalize SQL queries
   * @param {Object} payload - Payload object
   * @param {Object} options - Processing options
   * @returns {Object} Payload dengan queries yang sudah diproses
   */
  static processQueries(payload, options = {}) {
    const processedPayload = { ...payload };
    
    // Process datatablesQuery
    if (processedPayload.datatablesQuery) {
      processedPayload.datatablesQuery = this.normalizeQuery(
        processedPayload.datatablesQuery, 
        'datatablesQuery',
        options
      );
    }
    
    // Process advancedQueries
    if (processedPayload.advancedQueries) {
      const processedAdvanced = {};
      for (const [name, query] of Object.entries(processedPayload.advancedQueries)) {
        processedAdvanced[name] = this.normalizeQuery(query, `advancedQueries.${name}`, options);
      }
      processedPayload.advancedQueries = processedAdvanced;
    }
    
    // Process nestedQueries
    if (processedPayload.nestedQueries) {
      processedPayload.nestedQueries = processedPayload.nestedQueries.map((nested, index) => ({
        ...nested,
        query: nested.query ? this.normalizeQuery(nested.query, `nestedQueries[${index}]`, options) : nested.query
      }));
    }
    
    return processedPayload;
  }

  /**
   * Normalize single SQL query
   * @param {string} query - SQL query string
   * @param {string} context - Context untuk logging
   * @param {Object} options - Normalization options
   * @returns {string} Normalized query
   */
  static normalizeQuery(query, context, options = {}) {
    if (!query || typeof query !== 'string') {
      return query;
    }
    
    let normalizedQuery = query;
    
    // Remove extra whitespace dan normalize line breaks
    if (options.normalizeWhitespace !== false) {
      normalizedQuery = normalizedQuery
        .replace(/\s+/g, ' ')
        .replace(/\n\s*/g, '\n')
        .trim();
    }
    
    // Replace table name placeholders
    if (options.tableName) {
      normalizedQuery = normalizedQuery
        .replace(/\${tableName}/g, options.tableName)
        .replace(/\${this\.table}/g, options.tableName);
    }
    
    // Skip adding alias automatically to prevent conflicts
    // User should define aliases in their queries as needed
    
    console.log(`Normalized query for ${context}`);
    return normalizedQuery;
  }

  /**
   * Action alias mapping - maps legacy action names to modern names
   * This allows backward compatibility with old payloads using add/list
   * Modern payloads should use: create, read, update, delete
   */
  static get ACTION_ALIASES() {
    return {
      'add': 'create',   // add → create (legacy support)
      'list': 'read'     // list → read (legacy support)
    };
  }

  /**
   * Process dan normalize actions configuration
   * @param {Object} payload - Payload object
   * @param {Object} options - Processing options
   * @returns {Object} Payload dengan actions yang sudah diproses
   */
  static processActions(payload, options = {}) {
    const processedPayload = { ...payload };

    if (!processedPayload.action || typeof processedPayload.action !== 'object') {
      // Set default actions jika tidak ada
      processedPayload.action = this.getDefaultActions(options);
      console.log(`Applied default actions configuration`);
    } else {
      // Apply action aliases sebelum normalisasi
      // Mapping: add → create, list → read (legacy support)
      processedPayload.action = this.applyActionAliases(processedPayload.action);

      // Normalize existing actions
      processedPayload.action = this.normalizeActions(processedPayload.action, options);
    }

    // Add action metadata untuk template generation
    processedPayload._actionMetadata = this.generateActionMetadata(processedPayload.action);

    return processedPayload;
  }

  /**
   * Apply action aliases - maps legacy action names to modern names
   * Legacy payload dapat menggunakan: add, list
   * Modern payload menggunakan: create, read, update, delete
   * Generator akan menerima nama modern: create, read
   * @param {Object} actions - Actions object dari payload
   * @returns {Object} Actions dengan alias yang sudah di-resolve
   */
  static applyActionAliases(actions) {
    const resolvedActions = { ...actions };

    for (const [legacy, modern] of Object.entries(this.ACTION_ALIASES)) {
      if (legacy in resolvedActions) {
        const legacyValue = resolvedActions[legacy];

        // Jika modern name sudah ada, merge dengan OR logic
        if (modern in resolvedActions) {
          resolvedActions[modern] = resolvedActions[modern] || legacyValue;
          console.log(`Action alias: ${legacy} merged with existing ${modern} (result: ${resolvedActions[modern]})`);
        } else {
          // Copy legacy value ke modern name
          resolvedActions[modern] = legacyValue;
          console.log(`Action alias: ${legacy} → ${modern} (value: ${legacyValue})`);
        }

        // Hapus legacy name dari actions
        delete resolvedActions[legacy];
      }
    }

    return resolvedActions;
  }

  /**
   * Get default actions configuration
   * @param {Object} options - Options
   * @returns {Object} Default actions
   */
  static getDefaultActions(options = {}) {
    const defaultActions = {
      datatables: true,
      create: true,
      update: true,
      delete: true,
      first: true,
      lookup: true
    };
    
    // Apply options overrides
    if (options.defaultActions) {
      return { ...defaultActions, ...options.defaultActions };
    }
    
    return defaultActions;
  }

  /**
   * Normalize actions object
   * @param {Object} actions - Actions object (sudah di-apply aliases)
   * @param {Object} options - Options
   * @returns {Object} Normalized actions
   */
  static normalizeActions(actions, options = {}) {
    // Valid actions untuk generator (modern names)
    // Note: 'add' dan 'list' sudah di-convert ke 'create' dan 'read' oleh applyActionAliases()
    const validActions = ['datatables', 'create', 'update', 'delete', 'first', 'lookup', 'read', 'export', 'import', 'adjust', 'aggregate', 'createComposite', 'updateComposite', 'readComposite', 'workflow'];

    // Action aliases yang dikenali di payload tapi tidak perlu di-normalize lagi
    // (sudah di-handle oleh applyActionAliases sebelum sampai di sini)
    const knownAliases = Object.keys(this.ACTION_ALIASES);

    const normalized = {};

    // Process valid actions
    for (const action of validActions) {
      if (action in actions) {
        normalized[action] = Boolean(actions[action]);
      } else {
        normalized[action] = false;
      }
    }

    // Warn about unknown actions (skip known aliases)
    for (const action of Object.keys(actions)) {
      if (!validActions.includes(action) && !knownAliases.includes(action)) {
        console.warn(`Unknown action '${action}' will be ignored`);
      }
    }

    // Ensure at least one action is enabled
    const enabledActions = Object.values(normalized).some(enabled => enabled);
    if (!enabledActions && options.ensureMinimumActions !== false) {
      normalized.datatables = true;
      normalized.first = true;
      console.log(`Enabled minimum actions: datatables, first`);
    }

    return normalized;
  }

  /**
   * Generate action metadata untuk template usage
   * @param {Object} actions - Actions object
   * @returns {Object} Action metadata
   */
  static generateActionMetadata(actions) {
    const enabled = Object.entries(actions)
      .filter(([, isEnabled]) => isEnabled)
      .map(([action]) => action);
    
    return {
      enabled: enabled,
      count: enabled.length,
      hasCreate: enabled.includes('add'),
      hasRead: enabled.includes('first') || enabled.includes('datatables'),
      hasUpdate: enabled.includes('update'),
      hasDelete: enabled.includes('delete'),
      hasLookup: enabled.includes('lookup'),
      isCrud: ['add', 'first', 'update', 'delete'].every(action => enabled.includes(action))
    };
  }

  /**
   * Add metadata ke payload untuk template generation
   * @param {Object} payload - Payload object
   * @param {Object} options - Options
   * @returns {Object} Payload dengan metadata
   */
  static addMetadata(payload, options = {}) {
    const processedPayload = { ...payload };
    
    processedPayload._metadata = {
      processedAt: new Date().toISOString(),
      processor: 'PayloadProcessor v2.0.0',
      tableName: payload.tableName,
      fieldCount: payload.fieldName ? payload.fieldName.length : 0,
      hasAdvancedQueries: !!(payload.advancedQueries && Object.keys(payload.advancedQueries).length > 0),
      hasNestedQueries: !!(payload.nestedQueries && payload.nestedQueries.length > 0),
      hasFilters: !!(payload.filters && payload.filters.length > 0),
      hasSearchColumns: !!(payload.searchColumns && payload.searchColumns.length > 0),
      databaseType: options.databaseType || 'postgres',
      features: this.detectFeatures(payload)
    };
    
    return processedPayload;
  }

  /**
   * Detect features dari payload
   * @param {Object} payload - Payload object
   * @returns {Array} Array feature names
   */
  static detectFeatures(payload) {
    const features = [];
    
    if (payload.filters && payload.filters.length > 0) {
      features.push('filtering');
    }
    
    if (payload.searchColumns && payload.searchColumns.length > 0) {
      features.push('searching');
    }
    
    if (payload.advancedQueries && Object.keys(payload.advancedQueries).length > 0) {
      features.push('advanced_queries');
    }
    
    if (payload.nestedQueries && payload.nestedQueries.length > 0) {
      features.push('nested_queries');
    }
    
    if (payload.datatablesWhere && payload.datatablesWhere.length > 0) {
      features.push('custom_where');
    }
    
    // Detect CTE (Common Table Expression) queries
    if (payload.datatablesQuery && typeof payload.datatablesQuery === 'string') {
      const query = payload.datatablesQuery.toLowerCase().trim();
      if (query.startsWith('with recursive') || query.startsWith('with ')) {
        features.push('cte_query');
      }
    }
    
    // Detect complex queries that might need subquery wrapper
    if (payload.datatablesQuery && typeof payload.datatablesQuery === 'string') {
      const query = payload.datatablesQuery.toLowerCase();
      if (query.includes('order by') || query.includes('group by') || query.includes('union')) {
        features.push('complex_query');
      }
    }
    
    return features;
  }

  /**
   * Validate processed payload
   * @param {Object} processedPayload - Processed payload
   * @returns {Object} Validation result
   */
  static validateProcessedPayload(processedPayload) {
    const result = {
      isValid: true,
      warnings: [],
      errors: []
    };
    
    // Check required fields
    if (!processedPayload.tableName) {
      result.errors.push('tableName is required');
      result.isValid = false;
    }
    
    if (!processedPayload.fieldName || !Array.isArray(processedPayload.fieldName)) {
      result.errors.push('fieldName must be an array');
      result.isValid = false;
    }
    
    if (!processedPayload.datatablesQuery) {
      result.errors.push('datatablesQuery is required');
      result.isValid = false;
    }
    
    // Check field name consistency
    if (processedPayload.fieldName && processedPayload.fieldName.length === 0) {
      result.errors.push('fieldName array cannot be empty');
      result.isValid = false;
    }
    
    // Check action configuration
    if (processedPayload._actionMetadata && processedPayload._actionMetadata.count === 0) {
      result.warnings.push('No actions are enabled');
    }
    
    return result;
  }

  /**
   * Create processing summary
   * @param {Object} originalPayload - Original payload
   * @param {Object} processedPayload - Processed payload
   * @returns {Object} Processing summary
   */
  static createProcessingSummary(originalPayload, processedPayload) {
    return {
      originalFieldCount: originalPayload.fieldName ? originalPayload.fieldName.length : 0,
      processedFieldCount: processedPayload.fieldName ? processedPayload.fieldName.length : 0,
      addedFields: (processedPayload.fieldName || []).filter(
        field => !(originalPayload.fieldName || []).includes(field)
      ),
      removedFields: (originalPayload.fieldName || []).filter(
        field => !(processedPayload.fieldName || []).includes(field)
      ),
      processedQueries: this.countProcessedQueries(processedPayload),
      enabledActions: processedPayload._actionMetadata ? processedPayload._actionMetadata.enabled : [],
      features: processedPayload._metadata ? processedPayload._metadata.features : []
    };
  }

  /**
   * Count processed queries
   * @param {Object} payload - Processed payload
   * @returns {number} Number of processed queries
   */
  static countProcessedQueries(payload) {
    let count = 0;
    
    if (payload.datatablesQuery) count++;
    if (payload.advancedQueries) count += Object.keys(payload.advancedQueries).length;
    if (payload.nestedQueries) count += payload.nestedQueries.length;
    if (payload.customQueries) {
      for (const queries of Object.values(payload.customQueries)) {
        if (Array.isArray(queries)) {
          count += queries.length;
        } else if (typeof queries === 'object') {
          count += Object.keys(queries).length;
        } else {
          count++;
        }
      }
    }
    
    return count;
  }

}

module.exports = PayloadProcessor;