'use strict';

/**
 * Audit Columns Helper
 *
 * Resolve nama kolom audit yang efektif berdasarkan konfigurasi payload.
 * Konvensi default mengikuti BaseModel runtime di `src/models/base-model.js`:
 *   createdAt -> created_at
 *   createdBy -> created_by
 *   updatedAt -> updated_at
 *   updatedBy -> updated_by
 *
 * Payload dapat override behavior:
 *   - `auditColumns: false` (atau null) -> disable audit columns
 *   - `auditColumns: { createdAt, createdBy, updatedAt, updatedBy }` -> custom mapping
 *   - tidak di-set / true -> pakai default 4 nama standar
 *
 * Helper ini dipakai oleh:
 *   - schema-diff: compute effective field list (fieldName ∪ audit columns)
 *   - endpoint create: validation pre-codegen
 *
 * @module lib/utils/audit-columns
 */

const DEFAULT_AUDIT_COLUMN_MAP = {
    createdAt: 'created_at',
    createdBy: 'created_by',
    updatedAt: 'updated_at',
    updatedBy: 'updated_by'
};

const DEFAULT_AUDIT_COLUMNS = Object.values(DEFAULT_AUDIT_COLUMN_MAP);

/**
 * Cek apakah audit columns aktif untuk payload ini.
 *
 * @param {Object} payload - Processed payload object
 * @returns {boolean} true jika audit columns akan di-inject runtime
 */
function isAuditColumnsEnabled(payload) {
    if (!payload) return false;
    if (!Object.prototype.hasOwnProperty.call(payload, 'auditColumns')) return true;
    const value = payload.auditColumns;
    if (value === false || value === null) return false;
    return true;
}

/**
 * Resolve nama kolom audit (sisi database) yang akan di-inject runtime.
 * Mengembalikan empty array bila audit columns di-disable.
 *
 * @param {Object} payload - Processed payload object
 * @returns {string[]} Array nama kolom database (snake_case)
 */
function resolveAuditColumnNames(payload) {
    if (!isAuditColumnsEnabled(payload)) return [];

    const value = payload && payload.auditColumns;
    if (value && typeof value === 'object' && !Array.isArray(value)) {
        const out = [];
        for (const key of Object.keys(DEFAULT_AUDIT_COLUMN_MAP)) {
            const mapped = value[key];
            if (typeof mapped === 'string' && mapped.length > 0) {
                out.push(mapped);
            } else {
                out.push(DEFAULT_AUDIT_COLUMN_MAP[key]);
            }
        }
        return out;
    }

    return DEFAULT_AUDIT_COLUMNS.slice();
}

/**
 * Resolve effective field list yang dipakai generator codegen:
 * gabungan fieldName eksplisit di payload + audit columns yang akan
 * di-inject runtime.
 *
 * Dipakai oleh schema validation untuk men-detect drift yang berasal
 * dari implicit audit columns (kasus umum: auditColumns aktif tapi
 * tabel database tidak punya kolom audit).
 *
 * @param {Object} payload - Processed payload object
 * @returns {{ fields: string[], audit: string[], explicit: string[] }}
 */
function resolveEffectiveFieldList(payload) {
    const explicit = Array.isArray(payload && payload.fieldName)
        ? payload.fieldName.slice()
        : [];
    const audit = resolveAuditColumnNames(payload);

    const merged = [];
    const seen = new Set();
    for (const f of explicit) {
        if (!seen.has(f)) {
            seen.add(f);
            merged.push(f);
        }
    }
    for (const f of audit) {
        if (!seen.has(f)) {
            seen.add(f);
            merged.push(f);
        }
    }

    return {
        fields: merged,
        audit,
        explicit
    };
}

/**
 * Deteksi alignment kolom audit standar antara payload generator dan tabel
 * database aktual. Helper ini dipakai oleh sync flow (payload-runner) dan
 * initial generation untuk men-set `auditColumns: false` bila kolom audit
 * tidak tersedia di database.
 *
 * Konvensi: kolom audit standar mengikuti DEFAULT_AUDIT_COLUMNS (snake_case).
 * Match dilakukan exact lowercase; bila tabel pakai naming convention lain
 * (mis. `CreatedAt`), audit detection akan miss.
 *
 * @param {string[]} dbColumns - Daftar nama kolom dari tabel database
 * @returns {{
 *   all: boolean,        // semua 4 kolom audit standar ada di database
 *   partial: boolean,    // sebagian (1-3) kolom audit ada
 *   none: boolean,       // tidak satupun kolom audit ada
 *   present: string[],   // kolom audit yang ada di database
 *   missing: string[]    // kolom audit yang tidak ada di database
 * }}
 */
function detectAuditAlignment(dbColumns) {
    const columns = Array.isArray(dbColumns) ? dbColumns : [];
    const present = DEFAULT_AUDIT_COLUMNS.filter(col => columns.includes(col));
    const missing = DEFAULT_AUDIT_COLUMNS.filter(col => !columns.includes(col));
    return {
        all: present.length === DEFAULT_AUDIT_COLUMNS.length,
        partial: present.length > 0 && present.length < DEFAULT_AUDIT_COLUMNS.length,
        none: present.length === 0,
        present,
        missing
    };
}

/**
 * Cek apakah konfigurasi `auditColumns` di payload memerlukan resolusi
 * berdasarkan alignment dengan database. Dipakai sync flow untuk men-detect
 * "audit-only drift" yang tidak ter-detect oleh comparator schema reguler.
 *
 * Aturan resolusi:
 *   - `auditColumns: false`/`null` -> no-op (preserved)
 *   - `auditColumns: { ... }` (object form) -> no auto-override (manual)
 *   - `auditColumns: true` atau tidak di-set (default true) -> butuh resolusi
 *     bila database tidak punya keempat kolom audit standar (none atau partial)
 *
 * @param {Object} payload - Processed payload object
 * @param {ReturnType<typeof detectAuditAlignment>} auditAlignment
 * @returns {boolean} true bila sync wajib regenerate untuk men-set false
 */
function needsAuditColumnResolution(payload, auditAlignment) {
    if (!payload || !auditAlignment) return false;
    const hasField = Object.prototype.hasOwnProperty.call(payload, 'auditColumns');
    const value = hasField ? payload.auditColumns : undefined;

    if (value === false || value === null) return false;
    if (value && typeof value === 'object' && !Array.isArray(value)) return false;

    return !auditAlignment.all;
}

module.exports = {
    DEFAULT_AUDIT_COLUMN_MAP,
    DEFAULT_AUDIT_COLUMNS,
    isAuditColumnsEnabled,
    resolveAuditColumnNames,
    resolveEffectiveFieldList,
    detectAuditAlignment,
    needsAuditColumnResolution
};
