<?php
// Buka session read-only agar tidak mengunci session saat page ini dijalankan
session_start(['read_and_close' => true]);
require('routeros_api.class.php');

// ===== CEK LOGIN =====
if (!isset($_SESSION['ip'], $_SESSION['user'], $_SESSION['pass'])) {
    header('Location: index.php');
    exit;
}

// ===== FOLDER CACHE =====
$cacheDir = __DIR__ . '/cache';
if (!is_dir($cacheDir)) {
    @mkdir($cacheDir, 0755, true);
}

// ===== FILE CACHE BERDASARKAN IP MIKROTIK (AMAN) =====
$mikrotikIpRaw = $_SESSION['ip'] ?? '';
$mikrotikIp = preg_replace('/[^0-9\.]/', '', $mikrotikIpRaw);
$cacheFile = $cacheDir . '/cache_comment_' . ($mikrotikIp ?: 'unknown') . '_all.json';

// ===== HELPERS: BACA / TULIS DENGAN LOCK =====
function read_json_file_lock(string $path): array {
    if (!file_exists($path)) return [];
    $fp = @fopen($path, 'r');
    if (!$fp) return [];
    $contents = '';
    if (flock($fp, LOCK_SH)) {
        $contents = stream_get_contents($fp);
        flock($fp, LOCK_UN);
    }
    fclose($fp);
    $data = json_decode($contents, true);
    return is_array($data) ? $data : [];
}

function atomic_write_json(string $path, $data): bool {
    $dir = dirname($path);
    if (!is_dir($dir) && !@mkdir($dir, 0755, true)) {
        return false;
    }
    $tmp = $path . '.tmp';
    $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    if ($json === false) return false;
    $fp = @fopen($tmp, 'c');
    if (!$fp) return false;
    $ok = false;
    if (flock($fp, LOCK_EX)) {
        ftruncate($fp, 0);
        rewind($fp);
        $written = fwrite($fp, $json);
        fflush($fp);
        flock($fp, LOCK_UN);
        fclose($fp);
        if ($written !== false && @rename($tmp, $path)) {
            @chmod($path, 0644);
            $ok = true;
        } else {
            @unlink($tmp);
            $ok = false;
        }
    } else {
        fclose($fp);
        @unlink($tmp);
        $ok = false;
    }
    return $ok;
}

// ===== HANDLE RELOAD PARAM (AMAN) =====
$reload = filter_input(INPUT_GET, 'reload', FILTER_SANITIZE_STRING);
if ($reload === '1' && file_exists($cacheFile)) {
    @unlink($cacheFile);
}

// ===== CONNECT MIKROTIK =====
$API = new RouterosAPI();
$API->debug = false;
$API->connect_timeout = 4;
$API->read_timeout = 7;

$errorMsg = '';
$filtered = [];
$cacheValid = false;

// ===== LOAD CACHE JIKA ADA & VALID =====
$cacheData = read_json_file_lock($cacheFile);
if (!empty($cacheData['timestamp']) && (time() - (int)$cacheData['timestamp'] < 3600) && is_array($cacheData['data'])) {
    $filtered = $cacheData['data'];
    $cacheValid = true;
}

if (!$cacheValid) {
    // Ambil user dari Mikrotik (aman: tangani error)
    $connected = false;
    try {
        if ($API->connect($_SESSION['ip'], $_SESSION['user'], $_SESSION['pass'])) {
            $connected = true;

            // Gunakan parseResponse untuk konsistensi
            $API->write('/ip/hotspot/user/print');
            $users = $API->parseResponse($API->read(false));
            if (!is_array($users)) $users = [];

            // Group berdasarkan prefix + tanggal di comment
            $grouped = [];
            foreach ($users as $u) {
                $comment = $u['comment'] ?? '';
                if ($comment === '') continue;
                if (preg_match('/^([a-zA-Z0-9\-]+)-(\d{2}\.\d{2}\.\d{2})/', $comment, $match)) {
                    $prefixTanggal = $match[1] . '-' . $match[2];
                    $grouped[$prefixTanggal][] = $u;
                }
            }

            // Tampilkan semua group tanpa batasan jumlah (comment_all)
            $filtered = [];
            foreach ($grouped as $key => $listUser) {
                $jumlah = count($listUser);
                $filtered[] = [
                    'jumlah' => $jumlah,
                    'user' => $listUser[0]
                ];
            }

            // Urutkan berdasarkan tanggal terbaru di comment (descending)
            usort($filtered, function($a, $b) {
                $getDate = function($item) {
                    $c = $item['user']['comment'] ?? '';
                    if (preg_match('/\d{2}\.\d{2}\.\d{2}/', $c, $m)) {
                        $dt = DateTime::createFromFormat('m.d.y', $m[0]);
                        if ($dt instanceof DateTime) {
                            return $dt->getTimestamp();
                        }
                    }
                    return 0;
                };
                return $getDate($b) <=> $getDate($a);
            });

            // Simpan cache secara aman (tidak wajib berhasil)
            @atomic_write_json($cacheFile, [
                'timestamp' => time(),
                'data' => $filtered
            ]);
        } else {
            $errorMsg = '❌ Gagal koneksi ke Mikrotik.';
        }
    } catch (Exception $e) {
        $errorMsg = '❌ Terjadi kesalahan saat mengambil data: ' . $e->getMessage();
    } finally {
        if (!empty($connected) && $API->connected) {
            $API->disconnect();
        }
    }
}
?>
<!DOCTYPE html>
<html>
<head>
    <title>Semua Sisa Voucher</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="favicon.png" />
<style>
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: 'Segoe UI', Tahoma, sans-serif;
    background: #f0f2f5;
    padding: 0;
    line-height: 1.6;
}

header {
    background: linear-gradient(135deg, #0d1823, #005ec3);
    color: #fff;
    padding: 15px;
    text-align: center;
    font-size: 1.7em;
    font-weight: bold;
    letter-spacing: 1px;
    animation: fadeInDown 1s ease;
    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}

main {
    padding: 15px;
    max-width: 1200px;
    margin: 0 auto;
    animation: fadeIn 1.2s ease;
}

.action-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 20px;
}

.action-bar a {
    padding: 10px 16px;
    border-radius: 6px;
    text-decoration: none;
    font-size: 14px;
    border: none;
    cursor: pointer;
    transition: all 0.3s ease;
    white-space: nowrap;
}

.back-btn {
    background: #dc3545;
    color: white;
}

.back-btn:hover {
    background: #c82333;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

.refresh-btn {
    background: #28a745;
    color: white;
}

.refresh-btn:hover {
    background: #218838;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

.filter-btn {
    background: #17a2b8;
    color: white;
}

.filter-btn:hover {
    background: #138496;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

.mobile-sort {
    display: none;
    margin: 15px 0;
    text-align: center;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: center;
}

.mobile-sort button {
    background: #007bff;
    color: #fff;
    border: none;
    padding: 8px 14px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
    transition: all 0.3s ease;
}

.mobile-sort button:hover {
    background: #0056b3;
}

.table-responsive {
    overflow-x: auto;
    background: white;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

table {
    width: 100%;
    border-collapse: collapse;
}

thead {
    background: linear-gradient(135deg, #007bff, #0056b3);
    color: white;
    position: sticky;
    top: 0;
}

th {
    padding: 14px;
    text-align: center;
    font-weight: 600;
    font-size: 14px;
    user-select: none;
    cursor: pointer;
    transition: all 0.2s ease;
    border-bottom: 2px solid #0056b3;
}

th:hover {
    background: #0056b3;
}

tbody tr {
    border-bottom: 1px solid #e9ecef;
    transition: all 0.2s ease;
}

tbody tr:hover {
    background: #f8f9fa;
    box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}

td {
    padding: 12px 14px;
    font-size: 14px;
    text-align: left;
}

td.no-urut {
    text-align: center;
    font-weight: 600;
    color: #007bff;
    width: 50px;
    min-width: 50px;
}

/* GABUNGAN JUMLAH + COMMENT */
td.jumlah-comment {
    width: 550px;
    min-width: 550px;
}

.jumlah-comment-wrapper {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 10px;
}

td.jumlah-comment .jumlah-badge {
    font-weight: 700;
    color: #fff;
    background: linear-gradient(135deg, #28a745, #20c997);
    border-radius: 4px;
    padding: 4px 10px;
    min-width: 45px;
    text-align: center;
    font-size: 13px;
    flex-shrink: 0;
}

td.jumlah-comment .comment-text {
    font-family: 'Courier New', monospace;
    font-weight: 550;
    color: #000;
    font-size: 13px;
    flex: 1;
    word-break: break-word;
}

td.profile {
    text-align: center;
    color: #666;
}

td.action {
    text-align: center;
    width: 100px;
}

.btn {
    background: #dc3545;
    color: white;
    border: none;
    padding: 8px 14px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
    transition: all 0.2s ease;
    font-weight: 500;
}

.btn:hover {
    background: #c82333;
    transform: translateY(-1px);
    box-shadow: 0 2px 4px rgba(0,0,0,0.15);
}

.btn:disabled {
    background: #ccc;
    cursor: not-allowed;
    transform: none;
}

#overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.8);
    color: white;
    text-align: center;
    padding-top: 20vh;
    z-index: 9999;
    animation: fadeIn 0.3s ease;
}

#overlayContent {
    background: rgba(0,0,0,0.6);
    padding: 30px;
    border-radius: 12px;
    max-width: 400px;
    margin: 0 auto;
}

#overlayContent h3 {
    margin-bottom: 20px;
    font-size: 18px;
}

#progressContainer {
    width: 100%;
    background: #555;
    border-radius: 10px;
    overflow: hidden;
    margin: 20px 0;
    height: 24px;
}

#progressBar {
    width: 0%;
    height: 100%;
    background: linear-gradient(90deg, #4caf50, #66bb6a);
    border-radius: 10px;
    transition: width 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-size: 12px;
    font-weight: bold;
}

#percent {
    font-size: 24px;
    font-weight: bold;
}

.error-message {
    background: #f8d7da;
    color: #721c24;
    padding: 15px;
    border-radius: 6px;
    margin: 20px 0;
    border-left: 4px solid #dc3545;
    animation: slideIn 0.3s ease;
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes fadeInDown {
    from { opacity: 0; transform: translateY(-20px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes slideIn {
    from { opacity: 0; transform: translateX(-20px); }
    to { opacity: 1; transform: translateX(0); }
}

/* RESPONSIVE DESIGN */
@media (max-width: 1024px) {
    header {
        font-size: 1.5em;
        padding: 12px;
    }

    th, td {
        padding: 10px;
        font-size: 13px;
    }

    .action-bar {
        gap: 8px;
    }

    .action-bar a {
        padding: 8px 12px;
        font-size: 13px;
    }

    td.jumlah-comment {
        width: 550px;
        min-width: 140px;
    }

    td.jumlah-comment .jumlah-badge,
    td.jumlah-comment .comment-text {
        font-size: 12px;
    }
}

@media (max-width: 768px) {
    main {
        padding: 10px;
    }

    header {
        font-size: 1.3em;
        padding: 12px 8px;
    }

    .action-bar {
        flex-direction: row;
        gap: 8px;
    }

    .action-bar a {
        flex: 1;
        text-align: center;
    }

    .mobile-sort {
        display: flex;
    }

    th, td {
        padding: 10px 8px;
        font-size: 12px;
    }

    td.no-urut {
        width: 40px;
        min-width: 40px;
    }

    td.jumlah-comment {
        width: 130px;
        min-width: 130px;
    }

    td.jumlah-comment .jumlah-badge,
    td.jumlah-comment .comment-text {
        font-size: 11px;
    }

    .btn {
        padding: 6px 10px;
        font-size: 12px;
    }

    table {
        font-size: 12px;
    }
}

@media (max-width: 480px) {
    header {
        font-size: 1.1em;
        padding: 10px;
    }

    main {
        padding: 8px;
    }

    .table-responsive {
        border-radius: 4px;
    }

    table {
        font-size: 11px;
    }

    th, td {
        padding: 8px 6px;
        font-size: 11px;
    }

    td.no-urut {
        width: 35px;
        min-width: 35px;
        padding: 8px 4px;
    }

    td.jumlah-comment {
        width: 100%;
        min-width: 100%;
        padding: 8px 4px;
    }

    .jumlah-comment-wrapper {
        flex-direction: column;
        gap: 4px;
    }

    td.jumlah-comment .jumlah-badge,
    td.jumlah-comment .comment-text {
        font-size: 10px;
    }

    td.jumlah-comment .jumlah-badge {
        width: 100%;
    }

    td.profile {
        font-size: 10px;
    }

    td.action {
        width: 80px;
        padding: 8px 4px;
    }

    .btn {
        padding: 5px 8px;
        font-size: 11px;
    }

    .action-bar a {
        padding: 8px 12px;
        font-size: 12px;
    }

    .mobile-sort button {
        padding: 6px 10px;
        font-size: 11px;
    }

    #overlayContent {
        max-width: 90%;
        padding: 20px;
    }

    #overlayContent h3 {
        font-size: 16px;
    }

    #percent {
        font-size: 20px;
    }
}

@media (max-width: 320px) {
    header {
        font-size: 0.95em;
    }

    th, td {
        padding: 6px 4px;
        font-size: 10px;
    }

    td.jumlah-comment {
        width: 100%;
    }

    .btn {
        padding: 4px 6px;
        font-size: 10px;
    }
}
</style>
</head>
<body>
<header>📊 Semua Sisa Voucher</header>
<main>

<div class="action-bar">
    <a class="back-btn" href="comment.php">⬅️ Back</a>
    <a class="refresh-btn" href="?reload=1">🔄 Refresh</a>
    <a class="filter-btn" href="comment.php">📋 Comment -11</a>
</div>

<?php if ($errorMsg): ?>
<div class="error-message"><?= htmlspecialchars($errorMsg) ?></div>
<?php endif; ?>

<div class="table-responsive">
    <table id="commentTable">
<thead>
    <tr>
        <th data-label="No">No</th>
        <th data-label="Jumlah + Comment" onclick="sortTable(1)">Jumlah + Comment</th>
        <th data-label="Prof" onclick="sortTable(2)">Prof</th>
        <th data-label="Aksi">Aksi</th>
    </tr>
</thead>

        <tbody id="commentTbody">
        <?php $no = 1; 
        if (!empty($filtered)) {
            foreach ($filtered as $item):
                $dataComment = htmlspecialchars($item['user']['comment'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
                $jumlah = (int)($item['jumlah'] ?? 0);
                $profile = htmlspecialchars($item['user']['profile'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
        ?>
        <tr data-comment="<?= $dataComment ?>" data-jumlah="<?= $jumlah ?>">
            <td class="no-urut"><?= $no++ ?></td>
            <td class="jumlah-comment">
                <div class="jumlah-comment-wrapper">
                    <span class="jumlah-badge"><?= $jumlah ?></span>
                    <span class="comment-text"><?= $dataComment ?></span>
                </div>
            </td>
            <td class="profile"><?= $profile ?></td>
            <td class="action">
                <button class="btn" onclick="deleteComment(this)">🗑️ Hapus</button>
            </td>
        </tr>
        <?php endforeach;
        } else {
            echo '<tr><td colspan="4" style="text-align:center; padding:20px; color:#999;">Tidak ada data voucher</td></tr>';
        }
        ?>
        </tbody>
    </table>
</div>

</main>

<div id="overlay">
    <div id="overlayContent">
        <h3>⏳ Sedang memproses...</h3>
        <div id="percent">0%</div>
        <div id="progressContainer">
            <div id="progressBar"></div>
        </div>
    </div>
</div>

<script>
// Helper: update nomor urut setelah hapus
function renumberRows(){
    const rows = document.querySelectorAll('#commentTbody tr');
    rows.forEach((r, i) => {
        const noCell = r.querySelector('.no-urut');
        if(noCell) noCell.textContent = i + 1;
    });
}

function deleteComment(btn){
    const row = btn.closest('tr');
    if(!row) return;
    
    const comment = row.getAttribute('data-comment') || row.querySelector('.comment-text').innerText.trim();
    
    if(!confirm('Hapus semua user dengan comment ini?')) return;

    // Disable button saat proses
    btn.disabled = true;

    // Tampilkan overlay
    document.getElementById('overlay').style.display = 'block';
    document.getElementById('percent').innerText = '0%';
    document.getElementById('progressBar').style.width = '0%';

    const progressUrl = 'cache/progress_<?= htmlspecialchars($mikrotikIp, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?>_all.json?rand=' + Math.random();

    // Polling progress
    let polling = true;
    const interval = setInterval(() => {
        fetch(progressUrl).then(r => {
            if(!r.ok) throw new Error('no-progress');
            return r.json();
        }).then(p => {
            const pct = parseInt(p.percent) || 0;
            document.getElementById('percent').innerText = pct + '%';
            document.getElementById('progressBar').style.width = pct + '%';
            if(pct >= 100){
                clearInterval(interval);
                polling = false;
                setTimeout(() => {
                    if(row) row.remove();
                    renumberRows();
                    document.getElementById('overlay').style.display = 'none';
                    btn.disabled = false;
                }, 500);
            }
        }).catch(e => {
            // Progress file belum tersedia
        });
    }, 350);

    // Kirim request hapus ke server
    fetch('delete_comment.php?comment=' + encodeURIComponent(comment))
    .then(r => r.json())
    .then(data => {
        if(!data.success){
            clearInterval(interval);
            alert('Gagal hapus user: ' + (data.error || 'unknown error'));
            document.getElementById('overlay').style.display = 'none';
            btn.disabled = false;
            return;
        }
        if(polling){
            clearInterval(interval);
            document.getElementById('percent').innerText = '100%';
            document.getElementById('progressBar').style.width = '100%';
            setTimeout(() => {
                if(row) row.remove();
                renumberRows();
                document.getElementById('overlay').style.display = 'none';
                btn.disabled = false;
            }, 500);
        }
    })
    .catch(err => {
        clearInterval(interval);
        alert('Terjadi error komunikasi dengan server');
        document.getElementById('overlay').style.display = 'none';
        btn.disabled = false;
    });
}

// Fungsi sortir aman
function sortTable(colIndex) {
    const tbody = document.getElementById("commentTbody");
    const rows = Array.from(tbody.querySelectorAll("tr"));

    const currentSort = tbody.getAttribute("data-sortcol");
    const currentDir  = tbody.getAttribute("data-sortdir");
    let asc = true;
    if(currentSort == colIndex && currentDir == "asc"){
        asc = false;
    }

    rows.sort((a, b) => {
        let valA, valB;

        // Kolom 1 (Jumlah) - sort by numeric jumlah
        if(colIndex === 1){
            valA = parseInt(a.getAttribute('data-jumlah')) || 0;
            valB = parseInt(b.getAttribute('data-jumlah')) || 0;
            return asc ? valA - valB : valB - valA;
        }
        // Kolom 2 (Prof) - sort by profile text
        else if(colIndex === 2){
            valA = a.cells[colIndex]?.innerText.trim() || "";
            valB = b.cells[colIndex]?.innerText.trim() || "";
        }
        // Default
        else {
            valA = a.cells[colIndex]?.innerText.trim() || "";
            valB = b.cells[colIndex]?.innerText.trim() || "";
        }

        if(valA < valB) return asc ? -1 : 1;
        if(valA > valB) return asc ? 1 : -1;
        return 0;
    });

    rows.forEach(r => tbody.appendChild(r));

    tbody.setAttribute("data-sortcol", colIndex);
    tbody.setAttribute("data-sortdir", asc ? "asc" : "desc");

    updateSortIcons(colIndex, asc);
    renumberRows();
}
function updateSortIcons(colIndex, asc){
    document.querySelectorAll("thead th").forEach((th,i)=>{
        if(i === colIndex){
            th.innerText = th.getAttribute("data-label") + (asc ? " ▲" : " ▼");
        } else {
            th.innerText = th.getAttribute("data-label");
        }
    });
}
</script>

</body>
</html>