/**
 * Service: Audit Trail untuk Operasi Sensitif
 * Mencatat semua operasi sensitif untuk tracking dan security
 */
const Database = require('better-sqlite3');
const path = require('path');
const { logger } = require('../config/logger');

const dbPath = path.join(__dirname, '../database/billing.db');
const db = new Database(dbPath);

// Inisialisasi tabel audit_trail
function initAuditTrailTable() {
  try {
    db.exec(`
      CREATE TABLE IF NOT EXISTS audit_trail (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        action TEXT NOT NULL,
        entity_type TEXT NOT NULL,
        entity_id TEXT,
        actor_type TEXT NOT NULL,
        actor_id TEXT,
        actor_name TEXT,
        details TEXT,
        ip_address TEXT,
        user_agent TEXT,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
      );

      CREATE INDEX IF NOT EXISTS idx_audit_actor ON audit_trail(actor_type, actor_id);
      CREATE INDEX IF NOT EXISTS idx_audit_entity ON audit_trail(entity_type, entity_id);
      CREATE INDEX IF NOT EXISTS idx_audit_action ON audit_trail(action);
      CREATE INDEX IF NOT EXISTS idx_audit_created_at ON audit_trail(created_at);
    `);
  } catch (e) {
    logger.error(`[Audit Trail] Gagal inisialisasi tabel: ${e.message}`);
  }
}

// Inisialisasi saat module dimuat
initAuditTrailTable();

/**
 * Catat audit trail
 * @param {Object} data - Data audit
 * @param {string} data.action - Tipe aksi (CREATE, UPDATE, DELETE, LOGIN, LOGOUT, dll)
 * @param {string} data.entity_type - Tipe entity (customer, invoice, package, dll)
 * @param {string} data.entity_id - ID entity
 * @param {string} data.actor_type - Tipe actor (admin, cashier, technician, agent, customer, system)
 * @param {string} data.actor_id - ID actor
 * @param {string} data.actor_name - Nama actor
 * @param {Object} data.details - Detail aksi (akan di-JSON.stringify)
 * @param {string} data.ip_address - IP address
 * @param {string} data.user_agent - User agent
 */
function logAuditTrail(data) {
  try {
    const stmt = db.prepare(`
      INSERT INTO audit_trail (
        action, entity_type, entity_id, actor_type, actor_id, actor_name,
        details, ip_address, user_agent
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    `);

    stmt.run(
      data.action,
      data.entity_type,
      data.entity_id || null,
      data.actor_type,
      data.actor_id || null,
      data.actor_name || null,
      data.details ? JSON.stringify(data.details) : null,
      data.ip_address || null,
      data.user_agent || null
    );

    logger.info(`[Audit Trail] ${data.action} ${data.entity_type} by ${data.actor_type} - ${data.actor_name}`);
  } catch (e) {
    logger.error(`[Audit Trail] Gagal mencatat audit: ${e.message}`);
  }
}

/**
 * Ambil audit trail berdasarkan filter
 * @param {Object} filters - Filter pencarian
 * @param {string} filters.action - Filter berdasarkan aksi
 * @param {string} filters.entity_type - Filter berdasarkan tipe entity
 * @param {string} filters.actor_type - Filter berdasarkan tipe actor
 * @param {string} filters.actor_id - Filter berdasarkan ID actor
 * @param {number} filters.limit - Batas hasil
 * @param {number} filters.offset - Offset hasil
 */
function getAuditTrail(filters = {}) {
  try {
    let query = 'SELECT * FROM audit_trail WHERE 1=1';
    const params = [];

    if (filters.action) {
      query += ' AND action = ?';
      params.push(filters.action);
    }

    if (filters.entity_type) {
      query += ' AND entity_type = ?';
      params.push(filters.entity_type);
    }

    if (filters.actor_type) {
      query += ' AND actor_type = ?';
      params.push(filters.actor_type);
    }

    if (filters.actor_id) {
      query += ' AND actor_id = ?';
      params.push(filters.actor_id);
    }

    query += ' ORDER BY created_at DESC';

    if (filters.limit) {
      query += ' LIMIT ?';
      params.push(filters.limit);
    }

    if (filters.offset) {
      query += ' OFFSET ?';
      params.push(filters.offset);
    }

    const stmt = db.prepare(query);
    const results = stmt.all(...params);

    // Parse details JSON
    return results.map(row => ({
      ...row,
      details: row.details ? JSON.parse(row.details) : null
    }));
  } catch (e) {
    logger.error(`[Audit Trail] Gagal mengambil audit: ${e.message}`);
    return [];
  }
}

/**
 * Ambil statistik audit trail
 */
function getAuditStats() {
  try {
    const stats = {
      total: 0,
      by_action: {},
      by_entity_type: {},
      by_actor_type: {},
      recent_24h: 0
    };

    // Total audit
    const totalStmt = db.prepare('SELECT COUNT(*) as count FROM audit_trail');
    stats.total = totalStmt.get().count;

    // By action
    const actionStmt = db.prepare(`
      SELECT action, COUNT(*) as count
      FROM audit_trail
      GROUP BY action
      ORDER BY count DESC
    `);
    stats.by_action = actionStmt.all();

    // By entity type
    const entityStmt = db.prepare(`
      SELECT entity_type, COUNT(*) as count
      FROM audit_trail
      GROUP BY entity_type
      ORDER BY count DESC
    `);
    stats.by_entity_type = entityStmt.all();

    // By actor type
    const actorStmt = db.prepare(`
      SELECT actor_type, COUNT(*) as count
      FROM audit_trail
      GROUP BY actor_type
      ORDER BY count DESC
    `);
    stats.by_actor_type = actorStmt.all();

    // Recent 24h
    const recentStmt = db.prepare(`
      SELECT COUNT(*) as count
      FROM audit_trail
      WHERE created_at >= datetime('now', '-24 hours')
    `);
    stats.recent_24h = recentStmt.get().count;

    return stats;
  } catch (e) {
    logger.error(`[Audit Trail] Gagal mengambil statistik: ${e.message}`);
    return null;
  }
}

/**
 * Hapus audit trail lama (retention policy)
 * @param {number} days - Jumlah hari untuk dipertahankan (default 90 hari)
 */
function cleanupOldAuditTrail(days = 90) {
  try {
    const stmt = db.prepare(`
      DELETE FROM audit_trail
      WHERE created_at < datetime('now', '-${days} days')
    `);
    const result = stmt.run();
    logger.info(`[Audit Trail] Cleaned up ${result.changes} old records (older than ${days} days)`);
    return result.changes;
  } catch (e) {
    logger.error(`[Audit Trail] Gagal cleanup: ${e.message}`);
    return 0;
  }
}

module.exports = {
  logAuditTrail,
  getAuditTrail,
  getAuditStats,
  cleanupOldAuditTrail
};
