<?php
// api/core/activity.php

function getClientIp(): string
{
    $headers = [
        'HTTP_CF_CONNECTING_IP',
        'HTTP_X_REAL_IP',
        'HTTP_X_FORWARDED_FOR',
        'REMOTE_ADDR'
    ];

    foreach ($headers as $key) {
        if (!empty($_SERVER[$key])) {
            $ipList = explode(',', $_SERVER[$key]);
            return trim($ipList[0]);
        }
    }

    return '0.0.0.0';
}

function logActivity(array $opts): void
{
    /**
     * REQUIRED
     * ----------------
     * userId
     * userUsed
     * category
     * kodeUnik
     * activityAction
     *
     * OPTIONAL
     * ----------------
     * device           (string)
     * oldData          (array)
     * newData          (array)
     * exceptionFields  (array)
     * skipDetail       (bool)
     */

    $ip = getClientIp();

    // =========================
    // DEVICE (FROM OPTS, NOT HEADER)
    // =========================
    $device = trim($opts['device'] ?? '');
    if ($device === '') {
        $device = 'unknown';
    }

    // =========================
    // INSERT ACTIVITY (HEADER)
    // =========================
    execute("
        INSERT INTO activity (
            Tanggal,
            IDUser,
            UserUsed,
            Activity,
            Device,
            IP,
            Category,
            KodeUnik
        ) VALUES (
            NOW(),
            :iduser,
            :userused,
            :activity,
            :device,
            :ip,
            :category,
            :kodeunik
        )
    ", [
        'iduser'   => (string) $opts['userId'],
        'userused' => $opts['userUsed'],
        'activity' => $opts['activityAction'],
        'device'   => $device,
        'ip'       => $ip,
        'category' => $opts['category'],
        'kodeunik' => $opts['kodeUnik']
    ]);

    // =========================
    // SKIP DETAIL?
    // =========================
    if (!empty($opts['skipDetail'])) {
        return;
    }

    // safety guard
    if (empty($opts['oldData']) || empty($opts['newData'])) {
        return;
    }

    $activityId = lastInsertId();

    // =========================
    // EXCEPTION FIELD
    // =========================
    $defaultExceptionFields = [
        'CreateBy',
        'CreateAt',
        'LastUpdateBy',
        'LastUpdateAt',
    ];

    $customExceptionFields = $opts['exceptionFields'] ?? [];

    $exceptionFields = array_unique(
        array_map(
            'strtolower',
            array_merge($defaultExceptionFields, $customExceptionFields)
        )
    );

    // =========================
    // INSERT ACTIVITY DETAIL (DIFF ONLY)
    // =========================
    foreach ($opts['newData'] as $field => $newValue) {

        if (in_array(strtolower($field), $exceptionFields, true)) {
            continue;
        }

        $oldValue = $opts['oldData'][$field] ?? null;

        if ((string) $oldValue === (string) $newValue) {
            continue;
        }

        execute("
            INSERT INTO activity_detail (
                IDActivity,
                FieldName,
                OldData,
                NewData
            ) VALUES (
                :id,
                :field,
                :old,
                :new
            )
        ", [
            'id'    => $activityId,
            'field' => $field,
            'old'   => is_scalar($oldValue)
                ? (string) $oldValue
                : json_encode($oldValue, JSON_UNESCAPED_UNICODE),
            'new'   => is_scalar($newValue)
                ? (string) $newValue
                : json_encode($newValue, JSON_UNESCAPED_UNICODE)
        ]);
    }
}
