/**
 * Parses an event by comparing old and new data to determine which fields have changed.
 *
 * This function analyzes the differences between previous (`oldData`) and current (`newData`)
 * data states to identify changed fields. It determines if the event is a new entry or an update
 * and returns details about changed fields, the event type, and associated metadata.
 *
 * @param {Object} options - Configuration options for parsing the event.
 * @param {Object} [options.oldData] - The previous state of the data (undefined for new entries).
 * @param {Object} options.newData - The current state of the data.
 * @param {string} options.trigger - The type of event trigger (e.g., 'INSERT', 'UPDATE').
 * @param {string} options.table - The name of the table associated with the event.
 * @param {string} [options.jobId] - The job ID, if already extracted by the caller (optional).
 * @returns {Object} An object containing the parsed event details:
 *   - {Array<string>} changedFieldNames - List of field names that have changed.
 *   - {Object} changedFields - Map of changed fields with their old and new values.
 *   - {boolean} isNew - True if the event is a new entry (no oldData provided).
 *   - {Object} data - The current data state (`newData`).
 *   - {string} trigger - The event trigger type.
 *   - {string} table - The table name.
 *   - {string|null} jobId - The provided jobId or null if not provided.
 */
const eventParser = async ({ oldData, newData, trigger, table, jobId = null }) => {
  const isNew = !oldData; // True if no old data exists, indicating a new entry
  let changedFields = {};
  let changedFieldNames = [];

  if (isNew) {
    // For new entries, all fields in newData are considered "changed" (from undefined to their value)
    changedFields = Object.fromEntries(
      Object.entries(newData).map(([key, value]) => [key, { old: undefined, new: value }])
    );
    changedFieldNames = Object.keys(newData); // All keys are new
  } else {
    // Compare oldData and newData to detect updates
    for (const key in newData) {
      if (Object.prototype.hasOwnProperty.call(newData, key)) {
        // Check if the field is new or its value has changed
        if (
          !Object.prototype.hasOwnProperty.call(oldData, key) || // Field didn’t exist before
          JSON.stringify(oldData[key]) !== JSON.stringify(newData[key]) // Values differ (deep comparison)
        ) {
          changedFields[key] = {
            old: oldData[key], // Undefined if field wasn’t in oldData
            new: newData[key]
          };
          changedFieldNames.push(key);
        }
      }
    }
    // Identify fields removed in newData (present in oldData but absent in newData)
    for (const key in oldData) {
      if (Object.prototype.hasOwnProperty.call(oldData, key) && !Object.prototype.hasOwnProperty.call(newData, key)) {
        changedFields[key] = {
          old: oldData[key],
          new: null // Mark as removed
        };
        changedFieldNames.push(key);
      }
    }
  }

  return {
    changedFieldNames, // Array of fields that changed
    changedFields, // Object with old/new values for changed fields
    isNew, // Boolean indicating if this is a new entry
    data: newData, // Current data state
    trigger, // Event trigger (e.g., 'INSERT', 'UPDATE')
    table, // Associated table name
    jobId // Provided jobId or null
  };
};

module.exports = eventParser;
