<?php
// admin/voucher_accounting_endpoint.php
// Endpoint لاستقبال Accounting من MikroTik (Hotspot vouchers) — بدون تسجيل دخول.
// آمن عبر secret + (اختياري) whitelist IP.

if (session_status() === PHP_SESSION_NONE) { @session_start(); }

require_once __DIR__ . '/db_bootstrap.php';
require_once __DIR__ . '/settings_store.php';
require_once __DIR__ . '/vouchers_lib.php';

header('Content-Type: application/json; charset=utf-8');

function jexit($ok, $msg = '', $extra = []) {
    echo json_encode(array_merge(['ok' => (bool)$ok, 'msg' => (string)$msg], $extra), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

try {
    $conn = ensure_db(true);
    if (!$conn) jexit(false, 'DB');
    vouchers_ensure_tables($conn);

    $enabled = (string)setting_get($conn, 'voucher_acct_enabled', '0');
    if ($enabled !== '1') jexit(false, 'disabled');

    $secret = (string)setting_get($conn, 'voucher_acct_secret', '');
    $reqSecret = (string)($_REQUEST['secret'] ?? '');
    if ($secret === '' || !hash_equals($secret, $reqSecret)) jexit(false, 'unauthorized');

    $allow = trim((string)setting_get($conn, 'voucher_acct_allowed_ips', ''));
    if ($allow !== '') {
        $ip = $_SERVER['REMOTE_ADDR'] ?? '';
        $list = array_filter(array_map('trim', preg_split('/[\s,;]+/', $allow)));
        if ($ip !== '' && !in_array($ip, $list, true)) jexit(false, 'ip_blocked');
    }

    // Supports:
    // 1) form: u, rx, tx, up, ip, mac
    // 2) JSON: {users:[{u,rx,tx,up,ip,mac},...]}
    $raw = file_get_contents('php://input');
    $json = null;
    $tr = trim((string)$raw);
    if ($raw && ($tr !== '' && ($tr[0] === '{' || $tr[0] === '['))) {
        $json = json_decode($raw, true);
    }

    $users = [];
    if (is_array($json) && isset($json['users']) && is_array($json['users'])) {
        $users = $json['users'];
    } elseif (!empty($_REQUEST['u'])) {
        $users = [[
            'u' => (string)$_REQUEST['u'],
            'rx' => (string)($_REQUEST['rx'] ?? '0'),
            'tx' => (string)($_REQUEST['tx'] ?? '0'),
            'up' => (string)($_REQUEST['up'] ?? '0'),
            'ip' => (string)($_REQUEST['ip'] ?? ''),
            'mac' => (string)($_REQUEST['mac'] ?? ''),
        ]];
    }

    if (!$users) jexit(false, 'no_data');

    $updated = 0;
    $cut = 0;

    // Lazy-load MikroTik API only if quota enforcement needs to cut.
    $needCut = false;
    foreach ($users as $row) {
        $u = trim((string)($row['u'] ?? $row['user'] ?? ''));
        if ($u === '') continue;
        $rx = (int)preg_replace('/\D+/', '', (string)($row['rx'] ?? 0));
        $tx = (int)preg_replace('/\D+/', '', (string)($row['tx'] ?? 0));
        $up = (int)preg_replace('/\D+/', '', (string)($row['up'] ?? 0));
        $ip = trim((string)($row['ip'] ?? ''));
        $mac = trim((string)($row['mac'] ?? ''));

        // Find voucher by mt_username
        $uu = $conn->real_escape_string($u);
        $q = $conn->query("SELECT id, type, data_bytes, status FROM vouchers WHERE mt_username='$uu' ORDER BY id DESC LIMIT 1");
        if (!$q || !$q->num_rows) continue;
        $v = $q->fetch_assoc();
        $vid = (int)$v['id'];

        // upsert accounting
        $stmt = $conn->prepare("INSERT INTO voucher_accounting (voucher_id, mt_username, mac, ip, bytes_in, bytes_out, uptime_sec, last_update_at)
            VALUES (?,?,?,?,?,?,?,NOW())
            ON DUPLICATE KEY UPDATE mt_username=VALUES(mt_username), mac=VALUES(mac), ip=VALUES(ip), bytes_in=VALUES(bytes_in), bytes_out=VALUES(bytes_out), uptime_sec=VALUES(uptime_sec), last_update_at=NOW()" );
        $stmt->bind_param('isssiii', $vid, $u, $mac, $ip, $rx, $tx, $up);
        $stmt->execute();
        $stmt->close();

        // touch voucher last_seen
        @$conn->query("UPDATE vouchers SET last_seen_at=NOW(), used_ip='".$conn->real_escape_string($ip)."' WHERE id=$vid");

        $updated++;

        // enforce quota (data/both)
        $type = (string)($v['type'] ?? 'time');
        $limit = (int)($v['data_bytes'] ?? 0);
        if (($type === 'data' || $type === 'both') && $limit > 0) {
            $used = (int)$rx + (int)$tx;
            if ($used >= $limit && ($v['status'] ?? '') !== 'expired') {
                $needCut = true;
            }
        }
    }

    if ($needCut) {
        require_once __DIR__ . '/mikrotik_lib.php';
        $api = mt_api_connect($conn);
        if ($api) {
            foreach ($users as $row) {
                $u = trim((string)($row['u'] ?? $row['user'] ?? ''));
                if ($u === '') continue;
                $rx = (int)preg_replace('/\D+/', '', (string)($row['rx'] ?? 0));
                $tx = (int)preg_replace('/\D+/', '', (string)($row['tx'] ?? 0));

                $uu = $conn->real_escape_string($u);
                $q = $conn->query("SELECT id, type, data_bytes, status FROM vouchers WHERE mt_username='$uu' ORDER BY id DESC LIMIT 1");
                if (!$q || !$q->num_rows) continue;
                $v = $q->fetch_assoc();
                $vid = (int)$v['id'];
                $type = (string)($v['type'] ?? 'time');
                $limit = (int)($v['data_bytes'] ?? 0);
                if (!(($type === 'data' || $type === 'both') && $limit > 0)) continue;

                $used = (int)$rx + (int)$tx;
                if ($used < $limit) continue;

                // disable user + drop session/cookies
                $rows = $api->command(['/ip/hotspot/user/print', '?name=' . $u]);
                $uid = '';
                foreach ($rows as $r) {
                    if (($r['.type'] ?? '') !== '!re') continue;
                    $uid = (string)($r['.id'] ?? '');
                    break;
                }
                if ($uid !== '') {
                    $api->command(['/ip/hotspot/user/disable', '=.id=' . $uid]);
                    // kick
                    $api->command(['/ip/hotspot/active/remove', '?user=' . $u]);
                    $api->command(['/ip/hotspot/cookie/remove', '?user=' . $u]);
                }
                @$conn->query("UPDATE vouchers SET status='expired', expires_at=NOW() WHERE id=$vid AND status<>'expired'");
                vouchers_log($conn, $vid, 'acct_cut', ['used_bytes'=>$used,'limit_bytes'=>$limit,'via'=>'accounting']);
                $cut++;
            }
            $api->disconnect();
        }
    }

    jexit(true, 'ok', ['updated'=>$updated, 'cut'=>$cut]);

} catch (Throwable $e) {
    jexit(false, $e->getMessage());
}
