<?php
// admin/quota_runner.php
// تنفيذ مزامنة counters + إنفاذ LIMIT/RESTORE حسب حجم الباقة الشهري + الإضافي.

require_once __DIR__ . '/db_bootstrap.php';
require_once __DIR__ . '/mikrotik_lib.php';
require_once __DIR__ . '/quota_lib.php';

/**
 * تُرجع مصفوفة: username => [rx=>int, tx=>int]
 */
function q_fetch_ppp_counters(mysqli $conn): array {
  $rows = mt_ppp_active($conn);
  $out = [];
  foreach($rows as $r){
    $u = trim((string)($r['name'] ?? ''));
    if($u==='') continue;
    // normalize realm
    $u = preg_replace('/@.*/', '', $u);
    $rx = (int)($r['rx_bytes'] ?? 0);
    $tx = (int)($r['tx_bytes'] ?? 0);
    $out[$u] = ['rx'=>$rx,'tx'=>$tx];
  }
  return $out;
}

/**
 * تحديث الاستهلاك الشهري من counters الحية (دلتا)
 */
if (!function_exists('q_sync_monthly_usage')) {
function q_sync_monthly_usage(mysqli $conn, string $cycle_month): int {
  q_ensure_tables($conn);
  $counters = q_fetch_ppp_counters($conn);
  $updated = 0;

  // Detect ppp_usage_monthly schema (new: username+cycle_month, old: subscriber_id+month_key)
  $hasNew = false;
  $hasOld = false;
  try {
    $cU  = $conn->query("SHOW COLUMNS FROM `ppp_usage_monthly` LIKE 'username'");
    $cCM = $conn->query("SHOW COLUMNS FROM `ppp_usage_monthly` LIKE 'cycle_month'");
    if ($cU && $cU->num_rows && $cCM && $cCM->num_rows) $hasNew = true;

    $cS  = $conn->query("SHOW COLUMNS FROM `ppp_usage_monthly` LIKE 'subscriber_id'");
    $cMK = $conn->query("SHOW COLUMNS FROM `ppp_usage_monthly` LIKE 'month_key'");
    if ($cS && $cS->num_rows && $cMK && $cMK->num_rows) $hasOld = true;
  } catch (Throwable $e) {
    // ignore; will fall back to new schema attempt
  }

  // Map username -> subscriber_id for old schema
  $userToSid = [];
  if ($hasOld) {
    $rs = @$conn->query("SELECT id, COALESCE(NULLIF(ppp_username,''), username) AS u FROM subscribers WHERE COALESCE(is_deleted,0)=0");
    if ($rs) {
      while ($r = $rs->fetch_assoc()) {
        $u = trim((string)($r['u'] ?? ''));
        if ($u === '') continue;
        // normalize realm
        $u = preg_replace('/@.*/', '', $u);
        $userToSid[$u] = (int)($r['id'] ?? 0);
      }
    }
  }

  foreach($counters as $u => $v){
    $rx = (int)$v['rx'];
    $tx = (int)$v['tx'];
    if($rx < 0) $rx = 0;
    if($tx < 0) $tx = 0;

    $ue = $conn->real_escape_string($u);

    // last
    $lastRx = 0; $lastTx = 0;
    $rs = $conn->query("SELECT last_rx,last_tx FROM ppp_counters WHERE username='$ue' LIMIT 1");
    if($rs && $rs->num_rows){
      $row = $rs->fetch_assoc();
      $lastRx = (int)($row['last_rx'] ?? 0);
      $lastTx = (int)($row['last_tx'] ?? 0);
    }

    // handle counter reset (reconnect)
    $dRx = $rx >= $lastRx ? ($rx - $lastRx) : $rx;
    $dTx = $tx >= $lastTx ? ($tx - $lastTx) : $tx;
    $delta = $dRx + $dTx;

    // update last counters
    $conn->query("INSERT INTO ppp_counters (username,last_rx,last_tx) VALUES ('$ue',$rx,$tx)
                 ON DUPLICATE KEY UPDATE last_rx=$rx,last_tx=$tx");

    if($delta > 0){
      $me = $conn->real_escape_string($cycle_month);
      $wrote = false;

      if ($hasOld) {
        // old schema: subscriber_id + month_key
        $sid = (int)($userToSid[$u] ?? 0);
        if ($sid > 0) {
          $ok = @$conn->query("INSERT INTO ppp_usage_monthly (subscriber_id,month_key,used_bytes) VALUES ($sid,'$me',$delta)
                       ON DUPLICATE KEY UPDATE used_bytes=used_bytes+$delta");
          if ($ok) $wrote = true;
        }
      }

      if ($hasNew) {
        // new schema: username + cycle_month
        $ok = @$conn->query("INSERT INTO ppp_usage_monthly (username,cycle_month,used_bytes) VALUES ('$ue','$me',$delta)
                     ON DUPLICATE KEY UPDATE used_bytes=used_bytes+$delta");
        if ($ok) $wrote = true;
      }

      if ($wrote) $updated++;
    }
  }

  return $updated;
}

}

/**
 * إنفاذ limit/restore حسب الحصة.
 */
function q_enforce(mysqli $conn, string $cycle_month): array {
  q_ensure_tables($conn);
  $ms = mt_get_settings($conn);
  $defaultLimitSpeed = trim((string)($ms['limit_speed'] ?? '512k/512k'));

  $stats = ['limited'=>0,'restored'=>0,'skipped'=>0,'errors'=>0];

  $subs = $conn->query("SELECT id, username, full_name, base_speed, quota_gb FROM subscribers ORDER BY id ASC");
  if(!$subs) return $stats;

  while($s = $subs->fetch_assoc()){
    $sid = (int)$s['id'];
    $u = trim((string)($s['username'] ?? ''));
    if($u===''){ $stats['skipped']++; continue; }

    $baseSpeed = trim((string)($s['base_speed'] ?? ''));
    // السرعة الأساسية قد تكون مخزنة بصيغة 1M/2M أو كرمز 1M (حسب واجهة إضافة المشترك)
    // إذا كانت فارغة نضع قيمة افتراضية.
    if($baseSpeed==='') $baseSpeed = '10M/10M';
    $quotaGb = (float)($s['quota_gb'] ?? 0);
    $baseAllowed = (int)round($quotaGb * 1024 * 1024 * 1024);
    $addAllowed = q_sum_addons_bytes($conn, $sid, $u, $cycle_month);
    $allowed = max(0, $baseAllowed + $addAllowed);
    $used = q_get_monthly_used_bytes($conn, $u, $cycle_month);

    $ue = $conn->real_escape_string($u);
    $me = $conn->real_escape_string($cycle_month);
    $state = $conn->query("SELECT is_limited FROM quota_state WHERE username='$ue' AND cycle_month='$me' LIMIT 1");
    $isLimited = 0;
    if($state && $state->num_rows){ $isLimited = (int)($state->fetch_assoc()['is_limited'] ?? 0); }

    try {
      if($allowed > 0 && $used >= $allowed){
        if(!$isLimited){
          // ✅ تخفيض السرعة حسب السرعة الأساسية (Mapping)
          // يُقرأ من app_settings: quota_throttle_1M...quota_throttle_16M
          $speedKey = strtoupper(trim($baseSpeed));
          // Use the first rate token so configured speeds are not limited to
          // the old hard-coded 1M..16M list (for example 20M/20M => 20M).
          if (preg_match('/^([0-9]+(?:\.[0-9]+)?[KMG])/i', $speedKey, $m)) {
            $speedKey = strtoupper($m[1]);
          }
          $mapped = '';
          if(function_exists('get_app_setting')){
            $mapped = trim((string)get_app_setting($conn,'quota_throttle_'.$speedKey,''));
          }
          if($mapped==='') $mapped = $defaultLimitSpeed;
          mt_ppp_secret_set_rate($conn, $u, $mapped);
          mt_ppp_active_disconnect($conn, $u); // تطبيق فوري
          $conn->query("INSERT INTO quota_state (username,cycle_month,is_limited,last_action) VALUES ('$ue','$me',1,'LIMIT')
                        ON DUPLICATE KEY UPDATE is_limited=1,last_action='LIMIT'");
          $stats['limited']++;
        } else {
          $stats['skipped']++;
        }
      } else {
        // يسمح ⇒ رجّع السرعة إن كانت محدودة بسبب الحجم
        if($isLimited){
          mt_ppp_secret_set_rate($conn, $u, $baseSpeed);
          mt_ppp_active_disconnect($conn, $u);
          $conn->query("INSERT INTO quota_state (username,cycle_month,is_limited,last_action) VALUES ('$ue','$me',0,'RESTORE')
                        ON DUPLICATE KEY UPDATE is_limited=0,last_action='RESTORE'");
          $stats['restored']++;
        } else {
          $stats['skipped']++;
        }
      }
    } catch(Throwable $e){
      $stats['errors']++;
    }
  }

  return $stats;
}

// --------- Run (can be used from CLI or include) ---------
$cycle = q_cycle_month();
$syncCount = 0;
$enforceStats = ['limited'=>0,'restored'=>0,'skipped'=>0,'errors'=>0];

try {
  $syncCount = q_sync_monthly_usage($conn, $cycle);
  $enforceStats = q_enforce($conn, $cycle);
} catch(Throwable $e) {
  // silent
}

return ['cycle_month'=>$cycle,'synced_users'=>$syncCount] + $enforceStats;
