<?php
// admin/vouchers_api.php
require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/db_bootstrap.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/lang.php';
require_once __DIR__ . '/vouchers_lib.php';
require_once __DIR__ . '/mikrotik_lib.php';
require_once __DIR__ . '/shop_lib.php';

require_login();
if (function_exists('require_perm')) require_perm('can_manage_sales');

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

$conn = ensure_db(true);
vouchers_ensure_tables($conn);
ensure_shop_tables($conn);

$VOUCHER_SINGLE_DEVICE = get_app_setting($conn,'voucher_single_device','1');
$VOUCHER_PROFILE = get_app_setting($conn,'voucher_hotspot_profile','voucher');
$VOUCHER_AUTO_MT_ON_PAYMENT = get_app_setting($conn,'voucher_auto_mt_on_payment','1');
$VOUCHER_DEVICE_LOCK_ENABLED = get_app_setting($conn,'voucher_device_lock_enabled','1');
$VOUCHER_DEVICE_LOCK_STEPS = get_app_setting($conn,'voucher_device_lock_steps','1,5,10,30');
$VOUCHER_TIME_WALLCLOCK = get_app_setting($conn,'voucher_time_wallclock','1');
$GLOBALS['VOUCHER_TIME_WALLCLOCK'] = $VOUCHER_TIME_WALLCLOCK;

function mt_build_on_login_script(bool $wallclock_enabled, bool $single_device, bool $device_lock_enabled, string $steps_csv): string {
    if (!$wallclock_enabled && !$single_device) return '';

    // sanitize steps (minutes) for device lock
    $steps = array_values(array_filter(array_map('trim', explode(',', $steps_csv)), fn($x)=>$x!==''));
    $mins = [];
    foreach ($steps as $s) {
        if (preg_match('/^\d+$/', $s)) {
            $n = (int)$s;
            if ($n > 0 && $n <= 240) $mins[] = (string)$n;
        }
    }
    if (!$mins) $mins = ['1','5','10','30'];
    $arr = '{"' . implode('";"', $mins) . '"}';

    // RouterOS on-login script:
    // - Wallclock validity for vouchers: uses comment tags "durm=<minutes> start=1 rem=<minutes>"
    //   Creates scheduler vexp-<user> that decrements rem each minute even if user disconnects.
    // - Single device bind: binds first MAC; if mismatch and device_lock_enabled -> temporary disable with escalating minutes.
    $script = ':local u $user; :local m $mac; :local id [/ip hotspot user find name=$u];'
        . ' :if ([:len $id] = 0) do={ :return; }'
        . ' :local c [/ip hotspot user get $id comment];';

    if ($wallclock_enabled) {
        $script .= ' :local pd [:find $c "durm="];'
            . ' :if ($pd != nil) do={'
            . '   :local started ([:find $c "start=1"] != nil);'
            . '   :if (!$started) do={'
            . '     :local rest [:pick $c ($pd+5) [:len $c]]; :local sp [:find $rest " "]; :if ($sp != nil) do={ :set rest [:pick $rest 0 $sp]; }'
            . '     :local dur [:tonum $rest];'
            . '     :if ($dur > 0) do={'
            . '       /ip hotspot user set $id comment=($c . " start=1 rem=" . $dur);'
            . '       :local s ("vexp-" . $u);'
            . '       /system scheduler remove [find name=$s];'
            . '       /system scheduler add name=$s interval=1m on-event=('
            . '         ":local u \\"".$u."\\"; :local s \\"vexp-".$u."\\"; :local id [/ip hotspot user find name=$u];'
            . '          :if ([:len $id]=0) do={ /system scheduler remove [find name=$s]; :return; };'
            . '          :local c [/ip hotspot user get $id comment]; :local pr [:find $c \\"rem=\\"];'
            . '          :if ($pr = nil) do={ /system scheduler remove [find name=$s]; :return; };'
            . '          :local r [:pick $c ($pr+4) [:len $c]]; :local sp [:find $r \\" \\\"]; :if ($sp != nil) do={ :set r [:pick $r 0 $sp]; };'
            . '          :local rem [:tonum $r]; :set rem ($rem-1);'
            . '          :if ($rem <= 0) do={ /ip hotspot active remove [find user=$u]; /ip hotspot cookie remove [find user=$u]; /ip hotspot user disable $id; /system scheduler remove [find name=$s]; }'
            . '          else={'
            . '            :local pre [:pick $c 0 ($pr+4)]; :local rest2 [:pick $c ($pr+4) [:len $c]]; :local sp2 [:find $rest2 \\" \\\"]; :local suf \\"\\"; :if ($sp2 != nil) do={ :set suf [:pick $rest2 $sp2 [:len $rest2]]; };'
            . '            /ip hotspot user set $id comment=($pre . $rem . $suf);'
            . '          }"'
            . '       );'
            . '     }'
            . '   }'
            . ' };';
    }

    if ($single_device) {
        $script .= ' :local cur [/ip hotspot user get $id mac-address];'
            . ' :if ([:len $cur] = 0) do={ /ip hotspot user set $id mac-address=$m; }';
        if ($device_lock_enabled) {
            $script .= ' else={ :if ($cur != $m) do={'
                . ' :local c [/ip hotspot user get $id comment]; :local v 0;'
                . ' :local p [:find $c "viol="];'
                . ' :if ($p != nil) do={ :local rest [:pick $c ($p+5) [:len $c]]; :local sp [:find $rest " "]; :if ($sp != nil) do={ :set rest [:pick $rest 0 $sp]; } :set v [:tonum $rest]; }'
                . ' :set v ($v+1);'
                . ' :local pre $c;'
                . ' :if ($p != nil) do={ :set pre [:pick $c 0 $p]; :local rest2 [:pick $c ($p+5) [:len $c]]; :local sp2 [:find $rest2 " "]; :local suf ""; :if ($sp2 != nil) do={ :set suf [:pick $rest2 $sp2 [:len $rest2]]; } :set c ($pre . "viol=" . $v . $suf); } else={ :set c ($c . " viol=" . $v); }'
                . ' /ip hotspot user set $id comment=$c;'
                . ' :local steps ' . $arr . ';'
                . ' :local idx ($v-1); :if ($idx < 0) do={ :set idx 0; } :if ($idx >= [:len $steps]) do={ :set idx ([:len $steps]-1); }'
                . ' :local mins ($steps->$idx); :local mm $mins; :if ([:len $mm] = 1) do={ :set mm ("0".$mm); }'
                . ' :local interval ("00:".$mm.":00"); :local s ("unlock-".$u);'
                . ' /system scheduler remove [find name=$s];'
                . ' /ip hotspot active remove [find user=$u]; /ip hotspot cookie remove [find user=$u];'
                . ' /ip hotspot user disable $id;'
                . ' /system scheduler add name=$s interval=$interval on-event=("/ip hotspot user enable [find name=\\\"".$u."\\\"]; /system scheduler remove [find name=\\\"".$s."\\\"]; ");'
                . ' } };';
        }
        $script .= ' };';
    }

    return $script;
}

function mt_ensure_voucher_profile($api, string $profile_name, bool $single_device, bool $device_lock_enabled, string $steps_csv): void {
    $profile_name = trim($profile_name);
    if ($profile_name === '') $profile_name = 'voucher';

    $wallclock = ((($GLOBALS['VOUCHER_TIME_WALLCLOCK'] ?? '1')==='1'));
    $onLogin = mt_build_on_login_script($wallclock, $single_device, $device_lock_enabled, $steps_csv);

    $exists = $api->command(['/ip/hotspot/user/profile/print', '?name=' . $profile_name]);
    $found_id = null;
    foreach ($exists as $r) {
        if (($r['.type'] ?? '') === '!re' && isset($r['.id'])) { $found_id = $r['.id']; break; }
    }

    if ($found_id !== null) {
        $cmd = ['/ip/hotspot/user/profile/set', '=.id=' . $found_id];
        if ($single_device) $cmd[] = '=shared-users=1';
        if ($onLogin !== '') $cmd[] = '=on-login=' . $onLogin;
        $api->command($cmd);
        return;
    }

    $cmd = ['/ip/hotspot/user/profile/add', '=name=' . $profile_name];
    if ($single_device) $cmd[] = '=shared-users=1';
    if ($onLogin !== '') $cmd[] = '=on-login=' . $onLogin;
    $api->command($cmd);
}

function mt_create_hotspot_user_for_voucher(mysqli $conn, array $v, string $profile_name, bool $single_device): array {
    $username = $v['mt_username'] ?: $v['code'];
    $password = $v['mt_password'] ?: $v['passcode'];
    $comment = 'voucher:' . $v['code'];
    $rate = trim((string)$v['rate_limit']);
    $limit_uptime = null;
    if (!empty($v['duration_minutes'])) {
        $mins = (int)$v['duration_minutes'];
        $days = intdiv($mins, 1440); $mins -= $days*1440;
        $hours = intdiv($mins, 60); $mins -= $hours*60;
        $parts = [];
        if ($days>0) $parts[] = $days . 'd';
        if ($hours>0) $parts[] = $hours . 'h';
        if ($mins>0) $parts[] = $mins . 'm';
        $limit_uptime = $parts ? implode('', $parts) : null;
    }
    $limit_bytes = null;
    if (!empty($v['data_bytes'])) $limit_bytes = (string)((int)$v['data_bytes']);

    $api = mt_api_connect($conn);
    try {
        mt_ensure_voucher_profile($api, $profile_name, $single_device, ($GLOBALS['VOUCHER_DEVICE_LOCK_ENABLED'] ?? '1')==='1', (string)($GLOBALS['VOUCHER_DEVICE_LOCK_STEPS'] ?? '1,5,10,30'));
        $exists = $api->command(['/ip/hotspot/user/print', '?name=' . $username]);
        $found = false;
        foreach ($exists as $r) { if (($r['.type'] ?? '') === '!re') { $found = true; break; } }
        if (!$found) {
            $cmd = ['/ip/hotspot/user/add', '=name=' . $username, '=password=' . $password, '=comment=' . $comment, '=profile=' . $profile_name];
            if ($rate !== '') $cmd[] = '=rate-limit=' . $rate;
            if ($limit_uptime) $cmd[] = '=limit-uptime=' . $limit_uptime;
            if ($limit_bytes) $cmd[] = '=limit-bytes-total=' . $limit_bytes;
            $api->command($cmd);
        }
    } finally {
        $api->disconnect();
    }
    return ['username'=>$username,'password'=>$password,'rate'=>$rate,'uptime'=>$limit_uptime,'bytes'=>$limit_bytes,'profile'=>$profile_name];
}

function json_ok(array $data = []) { echo json_encode(['ok'=>true] + $data, JSON_UNESCAPED_UNICODE); exit; }
function json_err(string $msg, array $data = []) { echo json_encode(['ok'=>false,'error'=>$msg] + $data, JSON_UNESCAPED_UNICODE); exit; }

function csrf_require(): void {
    // vouchers_api is JSON-only; we require a CSRF token for sensitive operations.
    // Settings pages already generate/store this token.
    $sent = (string)($_POST['csrf_token'] ?? '');
    $sess = (string)($_SESSION['csrf_token'] ?? '');
    if ($sent === '' || $sess === '' || !hash_equals($sess, $sent)) {
        json_err('رمز الحماية غير صحيح. حدّث الصفحة وحاول مجددًا.');
    }
}


function mt_find_id_by_name($api, string $path, string $name): ?string {
    $rows = $api->command([$path . '/print', '?name=' . $name]);
    foreach ($rows as $r) {
        if (($r['.type'] ?? '') === '!re' && isset($r['.id'])) return (string)$r['.id'];
    }
    return null;
}
function mt_remove_by_id($api, string $path, string $id): void {
    $api->command([$path . '/remove', '=.id=' . $id]);
}
function mt_remove_many_by_user($api, string $path, string $username): void {
    $rows = $api->command([$path . '/print', '?user=' . $username]);
    foreach ($rows as $r) {
        if (($r['.type'] ?? '') === '!re' && isset($r['.id'])) {
            mt_remove_by_id($api, $path, (string)$r['.id']);
        }
    }
}

$action = $_POST['action'] ?? '';
try {
    if ($action === 'mark_sold') {
        $id = (int)($_POST['id'] ?? 0);
        $sold_to = trim((string)($_POST['sold_to'] ?? ''));
        $price = ($_POST['price'] ?? null);
        $price = ($price === '' || $price === null) ? null : (float)$price;
        $make_sale = (int)($_POST['make_sale'] ?? 1);

        if ($id <= 0) json_err('معرف غير صالح');
        $me = (int)($_SESSION['admin_id'] ?? ($_SESSION['admin_user_id'] ?? 0));

        // جلب الكرت أولاً لتفادي تكرار فاتورة البيع
        $q = $conn->prepare("SELECT * FROM vouchers WHERE id=? LIMIT 1");
        $q->bind_param('i', $id);
        $q->execute();
        $res = $q->get_result();
        $v = $res ? $res->fetch_assoc() : null;
        $q->close();
        if (!$v) json_err('الكرت غير موجود');

        $stmt = $conn->prepare("UPDATE vouchers SET status='sold', sold_at=NOW(), sold_by=?, sold_to=?, price=COALESCE(?,price) WHERE id=? AND status IN ('new','sold')");
        $stmt->bind_param('isdi', $me, $sold_to, $price, $id);
        $stmt->execute();
        $stmt->close();

        $sale_id = null;
        $payment_id = null;
        if ($make_sale === 1) {
            // إن كانت الفاتورة موجودة مسبقاً لا نعيد إنشاءها
            if (!empty($v['shop_sale_id'])) {
                $sale_id = (int)$v['shop_sale_id'];
            } else {
                $final_price = $price;
                if ($final_price === null && $v['price'] !== null) $final_price = (float)$v['price'];
                if ($final_price === null) $final_price = 0.0;

                $item_name = 'كرت إنترنت (' . $v['code'] . ')';
                // وصف بسيط حسب النوع
                if (($v['type'] ?? '') === 'time' && !empty($v['duration_minutes'])) {
                    $hrs = round(((int)$v['duration_minutes'])/60, 2);
                    $item_name .= ' — ' . $hrs . 'h';
                } elseif (($v['type'] ?? '') === 'data' && !empty($v['data_bytes'])) {
                    $gb = round(((int)$v['data_bytes'])/1024/1024/1024, 2);
                    $item_name .= ' — ' . $gb . 'GB';
                } elseif (($v['type'] ?? '') === 'both') {
                    $parts = [];
                    if (!empty($v['duration_minutes'])) $parts[] = round(((int)$v['duration_minutes'])/60, 2) . 'h';
                    if (!empty($v['data_bytes'])) $parts[] = round(((int)$v['data_bytes'])/1024/1024/1024, 2) . 'GB';
                    if ($parts) $item_name .= ' — ' . implode(' + ', $parts);
                }

                $payload = [
                    'customer_name' => $sold_to,
                    'customer_phone' => '',
                    'discount' => 0,
                    'notes' => 'Voucher: ' . $v['code'],
                    'created_by' => $me,
                    'items' => [
                        ['product_id'=>0,'name'=>$item_name,'qty'=>1,'price'=>$final_price]
                    ]
                ];
                $sale_id = shop_create_sale($conn, $payload);
                if ($sale_id) {
                    $up = $conn->prepare("UPDATE vouchers SET shop_sale_id=? WHERE id=?");
                    $up->bind_param('ii', $sale_id, $id);
                    $up->execute();
                    $up->close();
                }
            }

            // قبض تلقائي للصندوق (payments) — مرة واحدة فقط
            if ($sale_id && empty($v['payment_id'])) {
                // اقرأ الصافي من فاتورة البيع إن وُجد
                $net_total = null;
                $qs = $conn->prepare("SELECT net_total FROM shop_sales WHERE id=? LIMIT 1");
                if ($qs) {
                    $qs->bind_param('i', $sale_id);
                    $qs->execute();
                    $rs = $qs->get_result();
                    if ($rs && $rs->num_rows) {
                        $row = $rs->fetch_assoc();
                        $net_total = isset($row['net_total']) ? (float)$row['net_total'] : null;
                    }
                    $qs->close();
                }
                if ($net_total === null) {
                    // fallback
                    $net_total = ($price !== null) ? (float)$price : (float)($v['price'] ?? 0);
                }

                $created_by_name = (string)($_SESSION['admin_username'] ?? ($_SESSION['admin_user'] ?? ''));
                $payment_id = vouchers_create_cash_payment_for_shop_sale($conn, (int)$sale_id, (float)$net_total, (string)$v['code'], $created_by_name);
                if ($payment_id) {
                    $up2 = $conn->prepare("UPDATE vouchers SET payment_id=? WHERE id=?");
                    $up2->bind_param('ii', $payment_id, $id);
                    @$up2->execute();
                    @$up2->close();
                    vouchers_log($conn, $id, 'cash_payment', ['payment_id'=>$payment_id,'amount'=>$net_total,'reference'=>'SHOP_SALE#'.$sale_id]);
                }
            }
        }

        // ✅ ضمان وجود QR Token للطباعة (حتى قبل الدفع للتوزيع)
        vouchers_ensure_qr_token($conn, $id);

        // ✅ تفعيل تلقائي على MikroTik مباشرة بعد الدفع (مناسب لنقاط البيع)
        if ($VOUCHER_AUTO_MT_ON_PAYMENT === '1') {
            // نعيد جلب الكرت بآخر تحديثات الدفع/الأسعار
            $q2 = $conn->prepare("SELECT * FROM vouchers WHERE id=? LIMIT 1");
            $q2->bind_param('i', $id);
            $q2->execute();
            $r2 = $q2->get_result();
            $vv = $r2 ? $r2->fetch_assoc() : null;
            $q2->close();

            if ($vv && (!empty($vv['payment_id']) || ($vv['status'] ?? '')==='used')) {
                try {
                    $profile_used = vouchers_resolve_mt_profile($conn, (int)($vv['product_id'] ?? 0), $VOUCHER_PROFILE);
                    $info = mt_create_hotspot_user_for_voucher($conn, $vv, $profile_used, ($VOUCHER_SINGLE_DEVICE==='1'));
                    // حفظ بيانات الدخول لو لم تكن محفوظة
                    $upmt = $conn->prepare("UPDATE vouchers SET mt_username=?, mt_password=? WHERE id=?");
                    $un = $info['username'];
                    $pw = $info['password'];
                    $upmt->bind_param('ssi', $un, $pw, $id);
                    @$upmt->execute();
                    @$upmt->close();
                    vouchers_log($conn, $id, 'mt_hotspot_user', ['username'=>$un,'profile'=>$info['profile'],'default_profile'=>$VOUCHER_PROFILE,'via'=>'payment']);
                } catch (Throwable $e) {
                    vouchers_log($conn, $id, 'mt_error', ['msg'=>$e->getMessage(),'via'=>'payment']);
                }
            }
        }

        vouchers_log($conn, $id, 'sold', ['sold_to'=>$sold_to,'price'=>$price,'by'=>$me,'sale_id'=>$sale_id,'payment_id'=>$payment_id]);
        json_ok(['sale_id'=>$sale_id,'payment_id'=>$payment_id]);
    }

    if ($action === 'cancel') {
        $id = (int)($_POST['id'] ?? 0);
        if ($id <= 0) json_err('معرف غير صالح');

        // تحقق من الحالة الحالية
        $q = $conn->prepare("SELECT status, code FROM vouchers WHERE id=? LIMIT 1");
        $q->bind_param('i', $id);
        $q->execute();
        $res = $q->get_result();
        $v = $res ? $res->fetch_assoc() : null;
        $q->close();
        if (!$v) json_err('الكرت غير موجود');

        $st = (string)$v['status'];
        if (!in_array($st, ['new','sold'], true)) {
            json_err('لا يمكن إلغاء الكرت بحالته الحالية: ' . $st);
        }

        $stmt = $conn->prepare("UPDATE vouchers SET status='cancelled' WHERE id=? AND status IN ('new','sold')");
        $stmt->bind_param('i', $id);
        $stmt->execute();
        $affected = $stmt->affected_rows;
        $stmt->close();

        if ($affected <= 0) json_err('لم يتم تغيير أي سجل (قد تكون الحالة تغيّرت).');

        vouchers_log($conn, $id, 'cancelled');
        json_ok();
    }


    if ($action === 'create_hotspot_user') {
        $id = (int)($_POST['id'] ?? 0);
        if ($id <= 0) json_err('معرف غير صالح');

        $rowQ = $conn->prepare("SELECT * FROM vouchers WHERE id=? LIMIT 1");
        $rowQ->bind_param('i', $id);
        $rowQ->execute();
        $res = $rowQ->get_result();
        $v = $res ? $res->fetch_assoc() : null;
        $rowQ->close();
        if (!$v) json_err('الكرت غير موجود');

        if (in_array($v['status'], ['cancelled','expired'], true)) json_err('لا يمكن إنشاء مستخدم لهذا الكرت بحالته الحالية');
        // تفعيل المستخدم حصراً بعد الدفع (وجود payment_id) أو إذا أصبح الكرت مستخدم بالفعل
        if (empty($v['payment_id']) && ($v['status'] ?? '') !== 'used') {
            json_err('لا يمكن تفعيل هذا الكرت قبل الدفع');
        }


        $profile_used = vouchers_resolve_mt_profile($conn, (int)($v['product_id'] ?? 0), $VOUCHER_PROFILE);
        $info = mt_create_hotspot_user_for_voucher($conn, $v, $profile_used, ($VOUCHER_SINGLE_DEVICE==='1'));

        $up = $conn->prepare("UPDATE vouchers SET mt_username=?, mt_password=? WHERE id=?");
        $up->bind_param('ssi', $info['username'], $info['password'], $id);
        $up->execute();
        $up->close();

        vouchers_log($conn, $id, 'mt_hotspot_user', ['username'=>$info['username'],'rate'=>$info['rate'],'uptime'=>$info['uptime'],'bytes'=>$info['bytes'],'profile'=>$info['profile']]);
        json_ok(['username'=>$info['username'],'password'=>$info['password']]);
    }

    // تهيئة Accounting (Push) للكروت من MikroTik إلى النظام
    if ($action === 'install_voucher_acct') {
        csrf_require();
        $url = trim((string)get_app_setting($conn, 'voucher_acct_endpoint_url', ''));
        $secret = (string)get_app_setting($conn, 'voucher_acct_secret', '');

        if ($url === '') json_err('ضع رابط Endpoint أولاً ضمن إعدادات الكروت (Accounting).');
        if ($secret === '') json_err('أنشئ Secret أولاً ضمن إعدادات الكروت (Accounting).');

        $api = mt_api_connect($conn);
        if (!$api) json_err($GLOBALS['mt_last_error'] ?? 'فشل الاتصال بالراوتر');

        // RouterOS script: يقرأ Counters من /ip hotspot user (cumulative) ويُرسلها للنظام.
        // ملاحظة: نرسل up=0 (اختياري) لأن تحويل uptime إلى ثواني داخل RouterOS قد يكون معقداً.
        $scriptName = 'voucher_acct_push';
        $schedName  = 'voucher_acct_push';
        $interval   = (string)get_app_setting($conn, 'voucher_acct_interval', '5m');
        if ($interval === '') $interval = '5m';

        // Escape double-quotes for RouterOS strings
        $urlEsc = str_replace('"', '\"', $url);
        $secretEsc = str_replace('"', '\"', $secret);

        $onEvent = ':local url "'.$urlEsc.'"; :local secret "'.$secretEsc.'";'
            . ' :foreach i in=[/ip hotspot user find where comment~"voucher:" and disabled=no] do={'
            . '   :local u [/ip hotspot user get $i name];'
            . '   :local rx [/ip hotspot user get $i bytes-in];'
            . '   :local tx [/ip hotspot user get $i bytes-out];'
            . '   :local mac [/ip hotspot user get $i mac-address];'
            . '   :if ([:len $u] > 0) do={'
            . '     /tool fetch url=($url."?secret=".$secret."&u=".$u."&rx=".$rx."&tx=".$tx."&up=0&mac=".$mac) keep-result=no;'
            . '   }'
            . ' }';

        try {
            // Upsert script
            $rows = $api->command(['/system/script/print', '?name='.$scriptName]);
            $sid = '';
            foreach ($rows as $r) {
                if (($r['.type'] ?? '') !== '!re') continue;
                $sid = (string)($r['.id'] ?? '');
                break;
            }
            if ($sid !== '') {
                $api->command(['/system/script/set', '=.id='.$sid, '=source='.$onEvent, '=policy=read,write,policy,test,password,sniff,sensitive,romon']);
            } else {
                $api->command(['/system/script/add', '=name='.$scriptName, '=source='.$onEvent, '=policy=read,write,policy,test,password,sniff,sensitive,romon']);
            }

            // Upsert scheduler
            $rows = $api->command(['/system/scheduler/print', '?name='.$schedName]);
            $scid = '';
            foreach ($rows as $r) {
                if (($r['.type'] ?? '') !== '!re') continue;
                $scid = (string)($r['.id'] ?? '');
                break;
            }
            if ($scid !== '') {
                $api->command(['/system/scheduler/set', '=.id='.$scid, '=interval='.$interval, '=on-event='.$scriptName]);
            } else {
                $api->command(['/system/scheduler/add', '=name='.$schedName, '=interval='.$interval, '=on-event='.$scriptName]);
            }
        } finally {
            $api->disconnect();
        }

        json_ok(['script'=>$scriptName,'scheduler'=>$schedName,'interval'=>$interval]);
    }

    // ترقية الكروت القديمة (التي كانت تستخدم limit-uptime) إلى نظام durm/rem (Wall-clock validity)
    if ($action === 'upgrade_legacy_wallclock') {
        csrf_require();

        // إذا كان الخيار غير مفعّل لا معنى للترقية
        if (($VOUCHER_TIME_WALLCLOCK ?? '1') !== '1') {
            json_err('خيار “مدة الكرت تبدأ من أول تسجيل دخول” غير مفعّل. فعّله أولاً من إعدادات الكروت.');
        }

        $limit = (int)($_POST['limit'] ?? 300);
        if ($limit < 10) $limit = 10;
        if ($limit > 2000) $limit = 2000;

        $me = (int)($_SESSION['admin_id'] ?? ($_SESSION['admin_user_id'] ?? 0));

        // اختر كروت فيها مدة زمنية، تم تصديرها للميكروتك، ولم يتم ترقيتها سابقاً.
        $sql = "
          SELECT v.*
          FROM vouchers v
          LEFT JOIN voucher_usage u ON (u.voucher_id=v.id AND u.event='upgrade_wallclock')
          WHERE u.id IS NULL
            AND v.duration_minutes IS NOT NULL AND v.duration_minutes>0
            AND v.mt_username IS NOT NULL AND v.mt_username<>''
            AND (v.mt_exported=1 OR v.mt_exported IS NULL)
            AND v.status IN ('new','sold','used')
          ORDER BY v.id ASC
          LIMIT $limit
        ";
        $q = $conn->query($sql);
        $rows = $q ? $q->fetch_all(MYSQLI_ASSOC) : [];

        if (!$rows) {
            json_ok(['upgraded'=>0,'skipped'=>0,'not_found'=>0,'message'=>'لا يوجد كروت قديمة بحاجة ترقية.']);
        }

        $api = null;
        $upgraded = 0; $skipped = 0; $notFound = 0;
        $details = [];

        try {
            $api = mt_api_connect($conn);

            foreach ($rows as $v) {
                $vid = (int)$v['id'];
                $username = (string)$v['mt_username'];
                $dur = (int)$v['duration_minutes'];
                if ($username === '' || $dur <= 0) { $skipped++; continue; }

                $r = $api->command(['/ip/hotspot/user/print', '?name=' . $username]);
                $uid = null; $comment = ''; $profile = '';
                foreach ($r as $row) {
                    if (($row['.type'] ?? '') === '!re' && isset($row['.id'])) {
                        $uid = (string)$row['.id'];
                        $comment = (string)($row['comment'] ?? '');
                        $profile = (string)($row['profile'] ?? '');
                        break;
                    }
                }
                if ($uid === null) {
                    $notFound++;
                    $details[] = ['id'=>$vid,'user'=>$username,'status'=>'not_found'];
                    vouchers_log($conn, $vid, 'upgrade_wallclock_not_found', ['username'=>$username], $me, 'admin');
                    continue;
                }

                // أمان: لا نلمس إلا كروت vouchers
                if (strpos($comment, 'voucher:') === false) {
                    $skipped++;
                    $details[] = ['id'=>$vid,'user'=>$username,'status'=>'skipped_not_voucher'];
                    vouchers_log($conn, $vid, 'upgrade_wallclock_skipped', ['reason'=>'not_voucher_comment','comment'=>$comment], $me, 'admin');
                    continue;
                }

                if (strpos($comment, 'durm=') !== false) {
                    $skipped++;
                    vouchers_log($conn, $vid, 'upgrade_wallclock', ['username'=>$username,'already'=>true], $me, 'admin');
                    $details[] = ['id'=>$vid,'user'=>$username,'status'=>'already'];
                    continue;
                }

                $newComment = trim($comment);
                $newComment .= ($newComment === '' ? '' : ' ');
                $newComment .= 'durm=' . $dur;

                // Ensure profile on-login has the new wallclock logic
                $p = trim($profile);
                if ($p === '') $p = $VOUCHER_PROFILE;
                mt_ensure_voucher_profile($api, $p, ($VOUCHER_SINGLE_DEVICE==='1'), ($VOUCHER_DEVICE_LOCK_ENABLED==='1'), (string)$VOUCHER_DEVICE_LOCK_STEPS);

                // Remove legacy limit-uptime and add durm tag
                $api->command(['/ip/hotspot/user/set', '=.id=' . $uid, '=comment=' . $newComment, '=limit-uptime=0s']);

                $upgraded++;
                vouchers_log($conn, $vid, 'upgrade_wallclock', ['username'=>$username,'durm'=>$dur,'profile'=>$p], $me, 'admin');
                $details[] = ['id'=>$vid,'user'=>$username,'status'=>'upgraded'];
            }
        } catch (Throwable $e) {
            json_err('خطأ أثناء الترقية: ' . $e->getMessage(), ['upgraded'=>$upgraded,'skipped'=>$skipped,'not_found'=>$notFound]);
        } finally {
            if ($api && method_exists($api,'disconnect')) {
                try { $api->disconnect(); } catch(Throwable $e){}
            }
        }

        json_ok(['upgraded'=>$upgraded,'skipped'=>$skipped,'not_found'=>$notFound,'checked'=>count($rows),'details'=>$details]);
    }

    

if ($action === 'reset_violations') {
    $id = (int)($_POST['id'] ?? 0);
    if ($id <= 0) json_err('معرف غير صالح');

    $rowQ = $conn->prepare("SELECT * FROM vouchers WHERE id=? LIMIT 1");
    $rowQ->bind_param('i', $id);
    $rowQ->execute();
    $res = $rowQ->get_result();
    $v = $res ? $res->fetch_assoc() : null;
    $rowQ->close();
    if (!$v) json_err('الكرت غير موجود');

    $username = (string)($v['mt_username'] ?: $v['code']);
    if (trim($username) === '') json_err('لا يوجد اسم مستخدم على MikroTik');

    try {
        $api = mt_api_connect($conn);
        try {
            mt_ensure_voucher_profile($api, $VOUCHER_PROFILE, ($VOUCHER_SINGLE_DEVICE==='1'), ($VOUCHER_DEVICE_LOCK_ENABLED==='1'), (string)$VOUCHER_DEVICE_LOCK_STEPS);

            $u = $api->command(['/ip/hotspot/user/print', '?name=' . $username]);
            $uid = null;
            $comment = '';
            foreach ($u as $r) {
                if (($r['.type'] ?? '') === '!re' && isset($r['.id'])) {
                    $uid = $r['.id'];
                    $comment = (string)($r['comment'] ?? '');
                    break;
                }
            }
            if ($uid === null) json_err('مستخدم MikroTik غير موجود: ' . $username);

            // إزالة viol=... من التعليق
            $newComment = preg_replace('/\s*viol=\d+\s*/u', ' ', $comment);
            $newComment = trim(preg_replace('/\s{2,}/u', ' ', (string)$newComment));

            $api->command(['/ip/hotspot/user/set', '=.id=' . $uid, '=comment=' . $newComment]);

            // إزالة مهمة فك القفل + تفعيل المستخدم
            $schedName = 'unlock-' . $username;
            $sid = mt_find_id_by_name($api, '/system/scheduler', $schedName);
            if ($sid) mt_remove_by_id($api, '/system/scheduler', $sid);

            $api->command(['/ip/hotspot/user/enable', '=.id=' . $uid]);

            // فصل أي جلسة/كوكي لتطبيق الحالة فوراً
            mt_remove_many_by_user($api, '/ip/hotspot/active', $username);
            mt_remove_many_by_user($api, '/ip/hotspot/cookie', $username);
        } finally {
            $api->disconnect();
        }
    } catch (Throwable $e) {
        vouchers_log($conn, $id, 'mt_error', ['msg'=>$e->getMessage(),'via'=>'reset_violations']);
        json_err('خطأ MikroTik: ' . $e->getMessage());
    }

    vouchers_log($conn, $id, 'reset_violations', ['username'=>$username]);
    json_ok();
}

// ترقية الكروت القديمة (التي كانت تعتمد limit-uptime) لتعمل بنظام مدة من أول Login (durm/rem + scheduler)
if ($action === 'upgrade_legacy_wallclock') {
    csrf_require();
    if (($VOUCHER_TIME_WALLCLOCK ?? '1') !== '1') {
        json_err('هذه الميزة تتطلب تفعيل خيار: مدة الكرت تبدأ من أول تسجيل دخول.');
    }

    $limit = (int)($_POST['limit'] ?? 500);
    if ($limit < 1) $limit = 1;
    if ($limit > 2000) $limit = 2000;

    // فقط: الكروت التي لديها وقت + تم تصديرها إلى الميكروتك + لم تُرقّى سابقًا
    $sql = "
        SELECT v.*
        FROM vouchers v
        LEFT JOIN voucher_usage u
               ON u.voucher_id = v.id AND u.event = 'upgrade_wallclock'
        WHERE u.id IS NULL
          AND v.duration_minutes IS NOT NULL AND v.duration_minutes > 0
          AND v.mt_username IS NOT NULL AND v.mt_username <> ''
          AND (v.mt_exported = 1 OR v.mt_exported IS NULL)
          AND v.status IN ('new','sold','used')
        ORDER BY v.id ASC
        LIMIT $limit
    ";

    $q = $conn->query($sql);
    $rows = $q ? $q->fetch_all(MYSQLI_ASSOC) : [];
    if (!$rows) json_ok(['scanned'=>0,'upgraded'=>0,'skipped'=>0,'errors'=>0,'details'=>[]]);

    $upgraded = 0; $skipped = 0; $errors = 0;
    $details = [];

    try {
        $api = mt_api_connect($conn);
        try {
            // Ensure default profile has the correct on-login behavior
            mt_ensure_voucher_profile($api, (string)$VOUCHER_PROFILE, ($VOUCHER_SINGLE_DEVICE==='1'), ($VOUCHER_DEVICE_LOCK_ENABLED==='1'), (string)$VOUCHER_DEVICE_LOCK_STEPS);

            foreach ($rows as $v) {
                $vid = (int)$v['id'];
                $username = (string)$v['mt_username'];
                $durm = (int)$v['duration_minutes'];
                if ($username === '' || $durm <= 0) { $skipped++; continue; }

                $res = $api->command(['/ip/hotspot/user/print', '?name=' . $username]);
                $uid = null;
                $comment = '';
                $profile = '';
                foreach ($res as $r) {
                    if (($r['.type'] ?? '') === '!re' && isset($r['.id'])) {
                        $uid = (string)$r['.id'];
                        $comment = (string)($r['comment'] ?? '');
                        $profile = (string)($r['profile'] ?? '');
                        break;
                    }
                }

                if ($uid === null) {
                    $errors++;
                    $details[] = ['id'=>$vid,'code'=>$v['code'],'username'=>$username,'status'=>'error','msg'=>'مستخدم MikroTik غير موجود'];
                    continue;
                }

                // إذا durm موجود مسبقاً -> تخطي لكن نعلّم كمُرقى لمنع تكرار الفحص
                if (strpos($comment, 'durm=') !== false) {
                    vouchers_log($conn, $vid, 'upgrade_wallclock', ['username'=>$username,'already'=>true,'durm'=>$durm]);
                    $skipped++;
                    $details[] = ['id'=>$vid,'code'=>$v['code'],'username'=>$username,'status'=>'skipped','msg'=>'مسبقاً durm موجود'];
                    continue;
                }

                // أمان: لا نلمس إلا مستخدمين voucher:
                if (strpos($comment, 'voucher:') === false) {
                    $errors++;
                    $details[] = ['id'=>$vid,'code'=>$v['code'],'username'=>$username,'status'=>'error','msg'=>'ليس Voucher (comment لا يحتوي voucher:)'];
                    continue;
                }

                $newComment = trim($comment . ' durm=' . $durm);

                // Ensure profile contains the updated on-login script (legacy profiles)
                if ($profile === '') $profile = (string)$VOUCHER_PROFILE;
                mt_ensure_voucher_profile($api, $profile, ($VOUCHER_SINGLE_DEVICE==='1'), ($VOUCHER_DEVICE_LOCK_ENABLED==='1'), (string)$VOUCHER_DEVICE_LOCK_STEPS);

                // Remove legacy limit-uptime (connected-time) and set durm marker
                $api->command(['/ip/hotspot/user/set', '=.id=' . $uid, '=comment=' . $newComment, '=limit-uptime=0s']);

                vouchers_log($conn, $vid, 'upgrade_wallclock', ['username'=>$username,'durm'=>$durm,'profile'=>$profile]);
                $upgraded++;
                $details[] = ['id'=>$vid,'code'=>$v['code'],'username'=>$username,'status'=>'upgraded','msg'=>'تمت الترقية'];
            }
        } finally {
            $api->disconnect();
        }
    } catch (Throwable $e) {
        json_err('فشل الاتصال أو التنفيذ على MikroTik: ' . $e->getMessage());
    }

    json_ok(['scanned'=>count($rows),'upgraded'=>$upgraded,'skipped'=>$skipped,'errors'=>$errors,'details'=>$details]);
}
json_err('Action غير معروف');
} catch (Throwable $e) {
    if (ob_get_length()) { ob_end_clean(); }
    json_err($e->getMessage());
} finally {
    restore_error_handler();
}
