<?php
namespace App\Core;

/** Jejak audit untuk semua aksi penting. */
class Audit
{
    /** Kolom yang tidak pernah dicatat nilainya. */
    private const REDACT = ['password', 'password_hash', 'password_confirmation', 'kata_sandi', '_token'];

    public static function log(
        string $module,
        string $action,
        ?string $entityType = null,
        $entityId = null,
        ?string $description = null,
        ?array $old = null,
        ?array $new = null,
        ?int $approvalRequestId = null
    ): void {
        try {
            $u = Auth::check() ? Auth::user() : null;
            Database::i()->insert('audit_logs', [
                'user_id'     => $u['id'] ?? null,
                'user_name'   => $u['name'] ?? 'Sistem',
                'module'      => $module,
                'entity_type' => $entityType,
                'entity_id'   => $entityId !== null ? (int)$entityId : null,
                'action'      => $action,
                'description' => $description !== null ? mb_substr($description, 0, 500) : null,
                'old_values'  => $old !== null ? self::enc(self::redact($old)) : null,
                'new_values'  => $new !== null ? self::enc(self::redact($new)) : null,
                'ip_address'  => Request::ip(),
                'user_agent'  => Request::userAgent(),
                'approval_request_id' => $approvalRequestId,
            ]);
        } catch (\Throwable $e) {
            Logger::error('Gagal menulis audit log: ' . $e->getMessage());
        }
    }

    /** Mencatat hanya kolom yang benar-benar berubah. */
    public static function logDiff(string $module, string $action, string $entityType, $entityId, array $before, array $after, ?string $desc = null): void
    {
        $o = []; $n = [];
        foreach ($after as $k => $v) {
            $ov = $before[$k] ?? null;
            if ((string)$ov !== (string)$v) { $o[$k] = $ov; $n[$k] = $v; }
        }
        if (!$o && !$n) return;
        self::log($module, $action, $entityType, $entityId, $desc, $o, $n);
    }

    private static function redact(array $d): array
    {
        foreach ($d as $k => $v) {
            if (in_array(strtolower((string)$k), self::REDACT, true)) $d[$k] = '***';
        }
        return $d;
    }

    private static function enc(array $d): string
    {
        return (string)json_encode($d, JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE);
    }

    public static function actionLabel(string $a): string
    {
        return [
            'login' => 'Masuk', 'logout' => 'Keluar', 'create' => 'Tambah', 'update' => 'Ubah',
            'delete' => 'Hapus', 'restore' => 'Pulihkan', 'approve' => 'Setujui', 'reject' => 'Tolak',
            'import' => 'Import', 'export' => 'Export', 'rollback' => 'Batalkan Import',
            'ganti_sandi' => 'Ganti Kata Sandi', 'reset_sandi' => 'Reset Kata Sandi',
            'recalculate' => 'Hitung Ulang', 'reversal' => 'Pembalikan', 'cancel' => 'Pembatalan',
            'backup' => 'Pencadangan', 'restore_db' => 'Pemulihan Data', 'settings' => 'Ubah Pengaturan',
        ][$a] ?? ucfirst(str_replace('_', ' ', $a));
    }
}
