<?php
// admin/router_port_match_lib.php
// قراءة MACات منفذ مخصص من راوتر MikroTik ومطابقتها بنفس فهرس المشتركين.
// يحفظ قراءة المنفذ كمسار رصد معتمد داخل Snapshot المستقبلات، مع ترك أحكام ثبات الملكية للمراقبة الأمنية.

require_once __DIR__ . '/db_bootstrap.php';
require_once __DIR__ . '/comms_admin_lib.php';
require_once __DIR__ . '/mikrotik_connection_lib.php';
require_once __DIR__ . '/receiver_subscriber_match_lib.php';

if (!function_exists('ua_rpm_h')) {
function ua_rpm_h($v): string { return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); }
}

if (!function_exists('ua_rpm_router_list')) {
function ua_rpm_router_list(mysqli $conn): array {
    if (function_exists('comms_ensure_tables')) @comms_ensure_tables($conn);
    $rows = [];
    $rs = @$conn->query("SELECT id,name,host,api_port,role,is_enabled,notes FROM routers WHERE COALESCE(is_enabled,1)=1 ORDER BY id ASC");
    if ($rs) {
        while ($r = $rs->fetch_assoc()) {
            $rows[] = [
                'id'=>(int)($r['id'] ?? 0),
                'name'=>(string)($r['name'] ?? ''),
                'host'=>(string)($r['host'] ?? ''),
                'api_port'=>(int)($r['api_port'] ?? 8728),
                'role'=>(string)($r['role'] ?? ''),
                'notes'=>(string)($r['notes'] ?? ''),
            ];
        }
    }
    return $rows;
}
}

if (!function_exists('ua_rpm_router_get')) {
function ua_rpm_router_get(mysqli $conn, int $id): ?array {
    if ($id <= 0) return null;
    if (function_exists('comms_ensure_tables')) @comms_ensure_tables($conn);
    $id = (int)$id;
    $rs = @$conn->query("SELECT * FROM routers WHERE id={$id} AND COALESCE(is_enabled,1)=1 LIMIT 1");
    if ($rs && ($r=$rs->fetch_assoc())) return $r;
    return null;
}
}

if (!function_exists('ua_rpm_connect')) {
function ua_rpm_connect(array $router, ?string &$error = null) {
    $error = '';
    $api = function_exists('ua_mt_connect_config') ? ua_mt_connect_config($router, $error, 0.8) : null;
    if (!$api) {
        $error = $error ?: (string)($GLOBALS['mt_last_error'] ?? 'تعذر الاتصال بالراوتر');
        return null;
    }
    return $api;
}
}

if (!function_exists('ua_rpm_disconnect')) {
function ua_rpm_disconnect($api): void {
    if ($api && is_object($api) && method_exists($api, 'disconnect')) {
        try { $api->disconnect(); } catch (Throwable $e) {}
    }
}
}

if (!function_exists('ua_rpm_iface_label')) {
function ua_rpm_iface_label(array $r): string {
    $name = trim((string)($r['name'] ?? ''));
    $comment = trim((string)($r['comment'] ?? ''));
    $type = trim((string)($r['type'] ?? ''));
    $label = $name;
    if ($comment !== '') $label .= ' — ' . $comment;
    if ($type !== '') $label .= ' (' . $type . ')';
    return $label;
}
}

if (!function_exists('ua_rpm_list_interfaces')) {
function ua_rpm_list_interfaces(mysqli $conn, int $routerId): array {
    $router = ua_rpm_router_get($conn, $routerId);
    if (!$router) return ['ok'=>false, 'message'=>'الراوتر غير موجود أو غير مفعّل', 'interfaces'=>[]];
    $err = '';
    $api = ua_rpm_connect($router, $err);
    if (!$api) return ['ok'=>false, 'message'=>$err ?: 'تعذر الاتصال بالراوتر', 'interfaces'=>[]];

    try {
        $rows = $api->command(['/interface/print']);
        $out = [];
        foreach ($rows as $r) {
            if (($r['.type'] ?? '') !== '!re') continue;
            $name = trim((string)($r['name'] ?? ''));
            if ($name === '') continue;
            $row = [
                'name'=>$name,
                'type'=>(string)($r['type'] ?? ''),
                'comment'=>(string)($r['comment'] ?? ''),
                'running'=>(string)($r['running'] ?? ''),
                'disabled'=>(string)($r['disabled'] ?? ''),
            ];
            $row['label'] = ua_rpm_iface_label($row);
            $out[] = $row;
        }
        return ['ok'=>true, 'router'=>[
            'id'=>(int)$router['id'],
            'name'=>(string)$router['name'],
            'host'=>(string)$router['host'],
        ], 'interfaces'=>$out];
    } catch (Throwable $e) {
        return ['ok'=>false, 'message'=>$e->getMessage(), 'interfaces'=>[]];
    } finally {
        ua_rpm_disconnect($api);
    }
}
}

if (!function_exists('ua_rpm_row_interface')) {
function ua_rpm_row_interface(array $r): string {
    foreach (['interface','on-interface','port','on_port'] as $k) {
        $v = trim((string)($r[$k] ?? ''));
        if ($v !== '') return $v;
    }
    return '';
}
}

if (!function_exists('ua_rpm_row_mac')) {
function ua_rpm_row_mac(array $r): string {
    foreach (['mac-address','mac','address'] as $k) {
        $m = ua_rx_norm_mac($r[$k] ?? '');
        if ($m !== '') return $m;
    }
    return '';
}
}

if (!function_exists('ua_rpm_bool')) {
function ua_rpm_bool($v): bool {
    $s = strtolower(trim((string)$v));
    return in_array($s, ['1','true','yes','y'], true);
}
}

if (!function_exists('ua_rpm_fetch_port_macs')) {
function ua_rpm_fetch_port_macs(mysqli $conn, int $routerId, string $iface): array {
    $iface = trim($iface);
    if ($iface === '') return ['ok'=>false, 'message'=>'لم يتم اختيار منفذ', 'raw_macs'=>[], 'macs'=>[], 'raw'=>[]];

    $router = ua_rpm_router_get($conn, $routerId);
    if (!$router) return ['ok'=>false, 'message'=>'الراوتر غير موجود أو غير مفعّل', 'raw_macs'=>[], 'macs'=>[], 'raw'=>[]];

    $err = '';
    $api = ua_rpm_connect($router, $err);
    if (!$api) return ['ok'=>false, 'message'=>$err ?: 'تعذر الاتصال بالراوتر', 'raw_macs'=>[], 'macs'=>[], 'raw'=>[]];

    try {
        // نقرأ كل FDB ثم نفلتر محلياً لأن RouterOS يختلف بين interface و on-interface حسب الإصدار.
        $rows = $api->command(['/interface/bridge/host/print']);
        $rawMacs = [];
        $clientMacs = [];
        $raw = [];
        foreach ($rows as $r) {
            if (($r['.type'] ?? '') !== '!re') continue;
            $rowIface = ua_rpm_row_interface($r);
            if ($rowIface !== $iface) continue;

            $mac = ua_rpm_row_mac($r);
            if ($mac === '') continue;

            $isLocal = ua_rpm_bool($r['local'] ?? '') || ua_rpm_bool($r['is-local'] ?? '');
            $isStatic = ua_rpm_bool($r['static'] ?? '');
            $item = [
                'mac'=>$mac,
                'interface'=>$rowIface,
                'bridge'=>(string)($r['bridge'] ?? ''),
                'vid'=>(string)($r['vid'] ?? ''),
                'local'=>$isLocal,
                'static'=>$isStatic,
                'external_fdb'=>(string)($r['external-fdb'] ?? ''),
            ];
            $raw[] = $item;
            $rawMacs[$mac] = true;
            if (!$isLocal) $clientMacs[$mac] = true;
        }

        $rawList = array_keys($rawMacs);
        sort($rawList);
        $clientList = array_keys($clientMacs);
        sort($clientList);

        return [
            'ok'=>true,
            'router'=>[
                'id'=>(int)$router['id'],
                'name'=>(string)$router['name'],
                'host'=>(string)$router['host'],
            ],
            'interface'=>$iface,
            'source'=>'router_port_bridge_host',
            'raw_macs'=>$rawList,
            'macs'=>$clientList,
            'raw'=>$raw,
            'raw_count'=>count($rawList),
            'client_count'=>count($clientList),
            'policy'=>'RouterOS /interface bridge host rows filtered by selected interface; local router MACs are diagnostics and excluded from client matching.',
        ];
    } catch (Throwable $e) {
        return ['ok'=>false, 'message'=>$e->getMessage(), 'raw_macs'=>[], 'macs'=>[], 'raw'=>[]];
    } finally {
        ua_rpm_disconnect($api);
    }
}
}



if (!function_exists('ua_rpm_persist_port_match')) {
function ua_rpm_persist_port_match(mysqli $conn, array $scan): array {
    if (empty($scan['ok'])) return ['ok'=>false,'message'=>'scan_not_ok'];
    $router = (array)($scan['router'] ?? []);
    $routerId = (int)($router['id'] ?? 0);
    $iface = trim((string)($scan['interface'] ?? ''));
    if ($routerId <= 0 || $iface === '') return ['ok'=>false,'message'=>'missing_router_or_interface'];
    if (!function_exists('ua_rx_router_port_sources_read') || !function_exists('ua_rx_router_port_sources_write')) {
        return ['ok'=>false,'message'=>'router_port_source_store_unavailable'];
    }
    $key = ua_rx_router_port_source_key($routerId, $iface);
    $pseudoId = ua_rx_router_port_pseudo_id($routerId, $iface);
    $store = ua_rx_router_port_sources_read();
    $store['ports'][$key] = [
        'enabled'=>true,
        'key'=>$key,
        'pseudo_id'=>$pseudoId,
        'router_id'=>$routerId,
        'router_name'=>(string)($router['name'] ?? ''),
        'router_host'=>(string)($router['host'] ?? ''),
        'interface'=>$iface,
        'interface_label'=>(string)($scan['interface_label'] ?? $iface),
        'name'=>'منفذ راوتر: ' . trim(((string)($router['name'] ?? 'Router')) . ' / ' . $iface),
        'source'=>'router_port_bridge_host',
        'cache_ts'=>time(),
        'last_refresh_at'=>date('Y-m-d H:i:s'),
        'raw_macs'=>array_values((array)($scan['raw_macs'] ?? [])),
        'macs'=>array_values((array)($scan['macs'] ?? [])),
        'raw_count'=>(int)($scan['raw_count'] ?? count((array)($scan['raw_macs'] ?? []))),
        'client_count'=>(int)($scan['client_count'] ?? count((array)($scan['macs'] ?? []))),
        'client_count_method'=>'router_port_bridge_host_selected_interface',
        'ownership_policy'=>'RouterOS selected bridge host interface rows are promoted as custom receiver/port ownership rows; local router MACs remain diagnostic raw data.',
        'last_summary'=>(array)($scan['summary'] ?? []),
    ];
    ua_rx_router_port_sources_write($store);
    return ['ok'=>true,'key'=>$key,'pseudo_id'=>$pseudoId,'file'=>basename(ua_rx_router_port_sources_file())];
}
}
if (!function_exists('ua_rpm_match_port')) {
function ua_rpm_match_port(mysqli $conn, int $routerId, string $iface): array {
    $scan = ua_rpm_fetch_port_macs($conn, $routerId, $iface);
    if (empty($scan['ok'])) return $scan;

    $idx = ua_rx_subscriber_mac_index($conn);
    if (function_exists('ua_rx_known_subscriber_mac_map_apply_to_index')) {
        $snap = function_exists('ua_rx_json_read') && function_exists('ua_rx_snapshot_file') ? ua_rx_json_read(ua_rx_snapshot_file(), []) : [];
        $idx = ua_rx_known_subscriber_mac_map_apply_to_index($idx, is_array($snap) ? $snap : []);
    }
    $byMac = (array)($idx['by_mac'] ?? []);

    $matched = [];
    $unknown = [];
    $conflicts = [];
    $knownMac = [];
    foreach ((array)$scan['macs'] as $mac) {
        $owners = (array)($byMac[$mac] ?? []);
        if (!$owners) {
            $unknown[] = $mac;
            continue;
        }
        $knownMac[$mac] = true;
        $conflict = count($owners) > 1;
        $owner = $conflict && function_exists('ua_rx_choose_best_owner') ? ua_rx_choose_best_owner($owners) : (array)reset($owners);
        if (!$owner) { $unknown[] = $mac; continue; }
        if ($conflict) {
            if (function_exists('uamac_register_conflict')) {
                uamac_register_conflict($conn, $mac, $owners, 'قراءة منفذ راوتر مخصص وجدت MAC له أكثر من مالك. تم احتسابه للمطابقة وتُترك ثبات الملكية للمراقبة الأمنية.', 'security_monitor_router_port_duplicate');
            }
            $conflicts[] = [
                'mac'=>$mac,
                'chosen'=>$owner,
                'candidates'=>function_exists('ua_rx_owner_refs') ? ua_rx_owner_refs($owners) : array_values($owners),
            ];
        }
        $matched[] = [
            'mac'=>$mac,
            'subscriber_id'=>(int)($owner['id'] ?? 0),
            'username'=>(string)($owner['username'] ?? ''),
            'ppp_username'=>(string)($owner['ppp_username'] ?? ''),
            'ppp_user'=>(string)($owner['ppp_user'] ?? ''),
            'full_name'=>(string)($owner['full_name'] ?? ''),
            'mac_source'=>(string)($owner['mac_source'] ?? ''),
            'ownership_conflict'=>$conflict,
        ];
    }

    $scan['matched'] = $matched;
    $scan['unknown'] = $unknown;
    $scan['conflicts'] = $conflicts;
    $scan['summary'] = [
        'raw_mac_total'=>(int)($scan['raw_count'] ?? count((array)$scan['raw_macs'])),
        'client_mac_total'=>(int)($scan['client_count'] ?? count((array)$scan['macs'])),
        'known_mac_total'=>count($knownMac),
        'matched_total'=>count($matched),
        'unknown_total'=>count($unknown),
        'conflict_total'=>count($conflicts),
        'subscriber_identity_index_unique_macs'=>is_array($idx['by_mac'] ?? null) ? count($idx['by_mac']) : 0,
    ];
    $scan['persisted'] = function_exists('ua_rpm_persist_port_match') ? ua_rpm_persist_port_match($conn, $scan) : ['ok'=>false,'message'=>'persist_helper_missing'];
    return $scan;
}
}
