<?php
if(!isset($_SESSION['userid'])){
    exit("Unauthorized Access");
}

ini_set('max_execution_time', 300);
date_default_timezone_set('Asia/Dhaka');

/*
|--------------------------------------------------------------------------
| CONFIG
|--------------------------------------------------------------------------
*/
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

$oltInfoo = $obj->getSingleData('tbl_olt_devices', [
    'where' => [['id', '=', "'".$id."'"]]
]);

$port = $oltInfoo['telnet_port'];
$device_ip = $oltInfoo['device_ip'];
$onu_id = $oltInfoo['vendor_id'];
$oltIp = strtok($device_ip, ':');

if ($onu_id == '1'){

$username = "forid";
$password = "forid####";

/*
|--------------------------------------------------------------------------
| CACHE CONFIG (PER OLT)
|--------------------------------------------------------------------------
*/
$cacheDir = __DIR__ . '/cache/olt_' . $id;

$cacheOnu = $cacheDir . '/onu_cache.txt';
$cacheAllMac = $cacheDir . '/mac_all.txt';
$cacheMikrotik = $cacheDir . '/mikrotik_cache.json';

if (!file_exists($cacheDir)) {
    mkdir($cacheDir, 0777, true);
}

/*
|--------------------------------------------------------------------------
| CACHE HELPER
|--------------------------------------------------------------------------
*/
function getCacheData($cacheFile, $ttl, $callback){

    if(file_exists($cacheFile)){
        if((time() - filemtime($cacheFile)) < $ttl){
            $data = file_get_contents($cacheFile);
            return json_decode($data, true) ?: $data;
        }
    }

    $data = $callback();

    if(is_array($data)){
        file_put_contents($cacheFile, json_encode($data));
    }else{
        file_put_contents($cacheFile, $data);
    }

    return $data;
}

/*
|--------------------------------------------------------------------------
| HELPERS
|--------------------------------------------------------------------------
*/
function formatMac($mac){
    $mac = strtolower(trim($mac));
    $mac = str_replace(['.', '-', ':'], '', $mac);
    return implode(':', str_split($mac, 2));
}

/*
|--------------------------------------------------------------------------
| TELNET
|--------------------------------------------------------------------------
*/
function runTelnetCommand($command, $timeout = 10){

    global $oltIp, $port, $username, $password;

    $script = "/usr/bin/expect -c '
    set timeout $timeout
    spawn telnet $oltIp $port

    expect \"Username:\"
    send \"$username\r\"

    expect \"Password:\"
    send \"$password\r\"

    expect -re \".*>\" 

    send \"enable\r\"
    expect -re \".*#\"

    send \"terminal length 0\r\"
    expect -re \".*#\"

    send \"$command\r\"
    expect -re \".*#\"

    send \"exit\r\"
    expect eof
    '";

    return shell_exec($script);
}

/*
|--------------------------------------------------------------------------
| ONU PARSE
|--------------------------------------------------------------------------
*/
function parseOnuList($output){

    $data = [];
    $output = str_replace("\r", "", $output);

    foreach(explode("\n", $output) as $line){

        $line = trim($line);

        if(
            $line == '' ||
            stripos($line, 'IntfName') !== false ||
            stripos($line, 'MAC Address') !== false ||
            stripos($line, '----') !== false
        ){
            continue;
        }

        if(preg_match('/^(EPON\S+)\s+(\S+)\s+(\S+)\s+([0-9a-fA-F\.:-]+)\s+.*?(active|online|offline|off-line|deregistered|auto-configured)/i', $line, $m)){

            $rawMac = strtolower($m[4]);
            $rawMac = str_replace([':', '.', '-'], '', $rawMac);

            $data[] = [
                "interface" => strtolower($m[1]),
                "vendor"    => strtolower($m[2]),
                "model"     => $m[3],
                "mac"       => implode(':', str_split($rawMac, 2)),
                "status"    => (in_array(strtolower($m[5]), ['active','online','auto-configured'])) ? "UP" : "DOWN"
            ];
        }
    }

    return $data;
}

/*
|--------------------------------------------------------------------------
| MAC TABLE PARSE
|--------------------------------------------------------------------------
*/
function parseMacTable($output){

    $data = [];
    $capture = false;

    foreach(explode("\n", $output) as $line){

        $line = trim($line);

        if(preg_match('/vlan.*mac.*address/i', $line)){
            $capture = true;
            continue;
        }

        if(!$capture || $line === '' || preg_match('/^-+$/', $line)){
            continue;
        }

        if(preg_match('/^(\d+)\s+([0-9a-fA-F:.]{11,17})\s+(\w+)\s+(.+)$/', $line, $m)){

            $data[] = [
                'vlan' => (int)$m[1],
                'mac'  => formatMac($m[2]),
                'type' => strtoupper($m[3]),
                'port' => strtolower(trim($m[4]))
            ];
        }
    }

    return $data;
}

/*
|--------------------------------------------------------------------------
| GROUP MAC
|--------------------------------------------------------------------------
*/
function groupMacByInterface($macList){

    $grouped = [];

    foreach($macList as $m){

        $port = strtolower($m['port']);

        if(strpos($port,'epon') === false) continue;

        $base = explode('-', $port)[0];

        $grouped[$base][] = $m;
    }

    return $grouped;
}

/*
|--------------------------------------------------------------------------
| LOAD DATA
|--------------------------------------------------------------------------
*/
$onuOutput = getCacheData($cacheOnu, 300, fn()=> runTelnetCommand("show epon onu-information"));
$macOutput = getCacheData($cacheAllMac, 1800, fn()=> runTelnetCommand("show mac address-table", 15));

$mikrotikMap = getCacheData($cacheMikrotik, 1800, function() use ($obj){

    $users = $obj->pppeoActiveSecretList(1);
    $map = [];

    foreach($users as $u){

        if(!empty($u['caller-id'])){

            $raw = strtolower($u['caller-id']);
            $raw = str_replace(['-','.'], '', $raw);

            $mac = formatMac($raw);

            $map[$mac] = [
                'name' => $u['name'],
                'router_mac' => $mac
            ];
        }
    }

    return $map;
});

$allOnu = parseOnuList($onuOutput);
$allMacList = parseMacTable($macOutput);
$macGrouped = groupMacByInterface($allMacList);

/*
|--------------------------------------------------------------------------
| PAGINATION
|--------------------------------------------------------------------------
*/
$perPage = isset($_GET['limit']) ? (int)$_GET['limit'] : 10;
if(!in_array($perPage, [10,20,50,100])) $perPage = 10;

$currentPage = isset($_GET['pg']) ? max(1,(int)$_GET['pg']) : 1;
$totalPage = ceil(count($allOnu)/$perPage);
$onus = array_slice($allOnu, ($currentPage-1)*$perPage, $perPage);

?>

<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>

<body class="bg-light">
<div class="container mt-4">

<h4>ONU Monitoring Dashboard</h4>

<form method="post">
    <input type="hidden" name="id" value="<?= $id ?>">
    <button type="submit" name="sync_now" class="btn btn-primary mb-3">
        🔄 Sync Now Only This page
    </button>
</form>

<form method="get" class="mb-3 d-flex gap-2">
    <input type="hidden" name="page" value="onu_info">
    <input type="hidden" name="id" value="<?= $id ?>">

    <select name="limit" class="form-select w-auto" onchange="this.form.submit()">
        <option value="10" <?= $perPage==10?'selected':'' ?>>10</option>
        <option value="20" <?= $perPage==20?'selected':'' ?>>20</option>
        <option value="50" <?= $perPage==50?'selected':'' ?>>50</option>
        <option value="100" <?= $perPage==100?'selected':'' ?>>100</option>
    </select>
</form>

<div class="alert alert-dark">
    <strong>Total ONU:</strong> <?= count($allOnu) ?> |
    <strong>Showing:</strong> <?= count($onus) ?>
</div>

<table class="table table-bordered">
<thead class="table-dark">
<tr>
<th>Interface</th>
<th>Vendor</th>
<th>Model</th>
<th>ONU MAC</th>
<th>Status</th>
<th>Sync</th>
<th>User</th>
<th>Router MAC</th>
</tr>
</thead>

<tbody>
<?php foreach($onus as $o):

$matchedUser = null;
$routerMac = null;

$macList = $macGrouped[strtolower($o['interface'])] ?? [];

foreach($macList as $m){
    if($m['type'] != 'DYNAMIC') continue;

    $oltMac = str_replace(':','',strtolower($m['mac']));

    foreach($mikrotikMap as $mk => $user){
        if($oltMac == str_replace(':','',strtolower($mk))){
            $matchedUser = $user['name'];
            $routerMac = $user['router_mac'];
            break 2;
        }
    }
}
?>

<tr>
<td><?= $o['interface'] ?></td>
<td><?= $o['vendor'] ?></td>
<td><?= $o['model'] ?></td>
<td><?= $o['mac'] ?></td>

<td><?= ($o['status']=="UP")
? "<span class='badge bg-success'>UP</span>"
: "<span class='badge bg-danger'>DOWN</span>" ?></td>

<td><?= $matchedUser ? "<span class='badge bg-success'>Matched</span>" : "<span class='badge bg-warning'>No Client</span>" ?></td>
<td><?= $matchedUser ?: 'N/A' ?></td>
<td><?= $routerMac ?: 'N/A' ?></td>
</tr>

<?php endforeach; ?>
</tbody>
</table>

<?php if($totalPage > 1): ?>
<ul class="pagination">
<?php for($i=1;$i<=$totalPage;$i++): ?>
<li class="page-item <?= $i==$currentPage?'active':'' ?>">
<a class="page-link"
href="?page=onu_info&id=<?= $id ?>&pg=<?= $i ?>&limit=<?= $perPage ?>">
<?= $i ?>
</a>
</li>
<?php endfor; ?>
</ul>
<?php endif; ?>

</div>
</body>
</html>

<?php
/*
|--------------------------------------------------------------------------
| SYNC UPDATE
|--------------------------------------------------------------------------
*/
if(isset($_POST['sync_now'])){

    foreach($allOnu as $o){

        $matchedUser = null;
        $macList = $macGrouped[strtolower($o['interface'])] ?? [];

        foreach($macList as $m){
            if($m['type'] != 'DYNAMIC') continue;

            foreach($mikrotikMap as $mk => $user){
                if(str_replace(':','',$m['mac']) == str_replace(':','',$mk)){
                    $matchedUser = $user['name'];
                    break 2;
                }
            }
        }

        if($matchedUser && !empty($o['mac'])){

            $existing = $obj->getSingleData('tbl_agent', [
                'where' => [['ip', '=', "'".$matchedUser."'"]]
            ]);

            if(empty($existing['onumac'])){
                $obj->updateData(
                    'tbl_agent',
                    ['onumac' => $o['mac']],
                    ['ip' => $matchedUser]
                );
            }
        }
    }

    echo "<script>alert('Sync Completed Successfully');</script>";
}

}else{
    echo "<div class='alert alert-danger'>vendor not found.</div>";
}
?>